From 75d547998c859a7e7809ce2214a26fa1128bfdd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E5=B9=BF=E6=98=8E?= Date: Thu, 4 Nov 2021 16:55:37 +0800 Subject: [PATCH] * Code for task #44005. --- config/zentaopms.php | 3 + db/update15.9.sql | 48 + db/zentao.sql | 211 ++-- module/common/lang/common.php | 2 + module/common/lang/en.php | 69 +- module/common/lang/menu.php | 59 +- module/common/lang/zh-cn.php | 69 +- module/design/config.php | 32 + module/design/control.php | 485 +++++++++ module/design/css/browse.css | 3 + module/design/css/edit.css | 1 + module/design/css/linkcommit.css | 8 + module/design/js/batchcreate.js | 4 + module/design/js/browse.js | 5 + module/design/js/common.js | 16 + module/design/js/create.js | 4 + module/design/js/edit.js | 4 + module/design/js/linkcommit.js | 28 + module/design/js/view.js | 4 + module/design/lang/de.php | 78 ++ module/design/lang/en.php | 80 ++ module/design/lang/fr.php | 78 ++ module/design/lang/vi.php | 78 ++ module/design/lang/zh-cn.php | 80 ++ module/design/lang/zh-tw.php | 78 ++ module/design/model.php | 465 +++++++++ module/design/view/ajaxgetdropmenu.html.php | 64 ++ module/design/view/assignto.html.php | 40 + module/design/view/batchcreate.html.php | 45 + module/design/view/browse.html.php | 69 ++ module/design/view/create.html.php | 60 ++ module/design/view/edit.html.php | 98 ++ module/design/view/linkcommit.html.php | 88 ++ module/design/view/view.html.php | 92 ++ module/design/view/viewcommit.html.php | 63 ++ module/doc/css/common.css | 2 + module/group/lang/resource.php | 55 ++ module/programplan/config.php | 54 ++ module/programplan/control.php | 201 ++++ module/programplan/js/browse.js | 34 + module/programplan/js/create.js | 16 + module/programplan/lang/de.php | 73 ++ module/programplan/lang/en.php | 73 ++ module/programplan/lang/fr.php | 73 ++ module/programplan/lang/vi.php | 73 ++ module/programplan/lang/zh-cn.php | 73 ++ module/programplan/lang/zh-tw.php | 73 ++ module/programplan/model.php | 918 ++++++++++++++++++ module/programplan/view/browse.html.php | 38 + module/programplan/view/create.html.php | 184 ++++ module/programplan/view/edit.html.php | 107 ++ module/programplan/view/gantt.html.php | 436 +++++++++ module/programplan/view/list.html.php | 89 ++ module/project/model.php | 26 +- module/project/view/browsebylist.html.php | 4 +- module/stage/control.php | 185 ++++ .../stage/ext/view/create.cmmi.html.hook.php | 1 + module/stage/ext/view/edit.cmmi.html.hook.php | 1 + module/stage/lang/de.php | 38 + module/stage/lang/en.php | 38 + module/stage/lang/fr.php | 38 + module/stage/lang/vi.php | 38 + module/stage/lang/zh-cn.php | 38 + module/stage/lang/zh-tw.php | 38 + module/stage/model.php | 130 +++ module/stage/view/batchcreate.html.php | 46 + module/stage/view/browse.html.php | 73 ++ module/stage/view/create.html.php | 52 + module/stage/view/edit.html.php | 51 + module/stage/view/settype.html.php | 86 ++ 70 files changed, 5912 insertions(+), 154 deletions(-) create mode 100644 db/update15.9.sql create mode 100644 module/design/config.php create mode 100644 module/design/control.php create mode 100644 module/design/css/browse.css create mode 100644 module/design/css/edit.css create mode 100644 module/design/css/linkcommit.css create mode 100644 module/design/js/batchcreate.js create mode 100644 module/design/js/browse.js create mode 100644 module/design/js/common.js create mode 100644 module/design/js/create.js create mode 100644 module/design/js/edit.js create mode 100644 module/design/js/linkcommit.js create mode 100644 module/design/js/view.js create mode 100644 module/design/lang/de.php create mode 100644 module/design/lang/en.php create mode 100644 module/design/lang/fr.php create mode 100644 module/design/lang/vi.php create mode 100644 module/design/lang/zh-cn.php create mode 100644 module/design/lang/zh-tw.php create mode 100644 module/design/model.php create mode 100644 module/design/view/ajaxgetdropmenu.html.php create mode 100644 module/design/view/assignto.html.php create mode 100644 module/design/view/batchcreate.html.php create mode 100644 module/design/view/browse.html.php create mode 100644 module/design/view/create.html.php create mode 100644 module/design/view/edit.html.php create mode 100644 module/design/view/linkcommit.html.php create mode 100644 module/design/view/view.html.php create mode 100644 module/design/view/viewcommit.html.php create mode 100644 module/programplan/config.php create mode 100644 module/programplan/control.php create mode 100644 module/programplan/js/browse.js create mode 100644 module/programplan/js/create.js create mode 100644 module/programplan/lang/de.php create mode 100644 module/programplan/lang/en.php create mode 100644 module/programplan/lang/fr.php create mode 100644 module/programplan/lang/vi.php create mode 100644 module/programplan/lang/zh-cn.php create mode 100644 module/programplan/lang/zh-tw.php create mode 100644 module/programplan/model.php create mode 100644 module/programplan/view/browse.html.php create mode 100644 module/programplan/view/create.html.php create mode 100644 module/programplan/view/edit.html.php create mode 100644 module/programplan/view/gantt.html.php create mode 100644 module/programplan/view/list.html.php create mode 100644 module/stage/control.php create mode 100644 module/stage/ext/view/create.cmmi.html.hook.php create mode 100644 module/stage/ext/view/edit.cmmi.html.hook.php create mode 100644 module/stage/lang/de.php create mode 100644 module/stage/lang/en.php create mode 100644 module/stage/lang/fr.php create mode 100644 module/stage/lang/vi.php create mode 100644 module/stage/lang/zh-cn.php create mode 100644 module/stage/lang/zh-tw.php create mode 100644 module/stage/model.php create mode 100644 module/stage/view/batchcreate.html.php create mode 100644 module/stage/view/browse.html.php create mode 100644 module/stage/view/create.html.php create mode 100644 module/stage/view/edit.html.php create mode 100644 module/stage/view/settype.html.php diff --git a/config/zentaopms.php b/config/zentaopms.php index a66441e4e2..76822302e5 100644 --- a/config/zentaopms.php +++ b/config/zentaopms.php @@ -167,6 +167,7 @@ define('TABLE_USERTPL', '`' . $config->db->prefix . 'usertpl`'); define('TABLE_PRODUCT', '`' . $config->db->prefix . 'product`'); define('TABLE_BRANCH', '`' . $config->db->prefix . 'branch`'); define('TABLE_EXPECT', '`' . $config->db->prefix . 'expect`'); +define('TABLE_STAGE', '`' . $config->db->prefix . 'stage`'); define('TABLE_STAKEHOLDER', '`' . $config->db->prefix . 'stakeholder`'); define('TABLE_STORY', '`' . $config->db->prefix . 'story`'); define('TABLE_STORYSPEC', '`' . $config->db->prefix . 'storyspec`'); @@ -192,6 +193,8 @@ define('TABLE_BURN', '`' . $config->db->prefix . 'burn`'); define('TABLE_BUILD', '`' . $config->db->prefix . 'build`'); define('TABLE_ACL', '`' . $config->db->prefix . 'acl`'); +define('TABLE_DESIGN', '`' . $config->db->prefix . 'design`'); +define('TABLE_DESIGNSPEC', '`' . $config->db->prefix . 'designspec`'); define('TABLE_DOCLIB', '`' . $config->db->prefix . 'doclib`'); define('TABLE_DOC', '`' . $config->db->prefix . 'doc`'); define('TABLE_API', '`' . $config->db->prefix . 'api`'); diff --git a/db/update15.9.sql b/db/update15.9.sql new file mode 100644 index 0000000000..c9a0fdbcb4 --- /dev/null +++ b/db/update15.9.sql @@ -0,0 +1,48 @@ +-- DROP TABLE IF EXISTS `zt_stage`; +CREATE TABLE IF NOT EXISTS `zt_stage` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `percent` varchar(255) NOT NULL, + `type` varchar(255) NOT NULL, + `createdBy` varchar(30) NOT NULL, + `createdDate` datetime NOT NULL, + `editedBy` varchar(30) NOT NULL, + `editedDate` datetime NOT NULL, + `deleted` enum('0','1') NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- DROP TABLE IF EXISTS `zt_design`; +CREATE TABLE IF NOT EXISTS `zt_design` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `project` varchar(255) NOT NULL, + `product` varchar(255) NOT NULL, + `commit` text NOT NULL, + `commitedBy` varchar(30) NOT NULL, + `execution` mediumint(8) unsigned NOT NULL DEFAULT '0', + `name` varchar(255) NOT NULL, + `status` varchar(30) NOT NULL, + `createdBy` varchar(30) NOT NULL, + `createdDate` datetime NOT NULL, + `editedBy` varchar(30) NOT NULL, + `editedDate` datetime NOT NULL, + `assignedTo` varchar(30) NOT NULL, + `assignedBy` varchar(30) NOT NULL, + `assignedDate` datetime NOT NULL, + `deleted` enum('0','1') NOT NULL DEFAULT '0', + `story` char(30) NOT NULL, + `desc` text NOT NULL, + `version` smallint(6) NOT NULL, + `type` char(30) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- DROP TABLE IF EXISTS `zt_designspec`; +CREATE TABLE IF NOT EXISTS `zt_designspec` ( + `design` mediumint(8) NOT NULL, + `version` smallint(6) NOT NULL, + `name` varchar(255) NOT NULL, + `desc` text NOT NULL, + `files` varchar(255) NOT NULL, + UNIQUE KEY `design` (`design`,`version`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/db/zentao.sql b/db/zentao.sql index 60f013c5d7..4a5a29f530 100644 --- a/db/zentao.sql +++ b/db/zentao.sql @@ -30,99 +30,94 @@ CREATE TABLE IF NOT EXISTS `zt_action` ( KEY `objectID` (`objectID`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_api_lib_release`; -CREATE TABLE `zt_api_lib_release` -( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, - `lib` int UNSIGNED NOT NULL DEFAULT 0, - `desc` varchar(255) NOT NULL DEFAULT '', - `version` varchar(255) NOT NULL DEFAULT '', - `snap` mediumtext NOT NULL, - `addedBy` varchar(30) NOT NULL DEFAULT 0, - `addedDate` datetime NOT NULL, - PRIMARY KEY (`id`) +CREATE TABLE `zt_api_lib_release` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `lib` int UNSIGNED NOT NULL DEFAULT 0, + `desc` varchar(255) NOT NULL DEFAULT '', + `version` varchar(255) NOT NULL DEFAULT '', + `snap` mediumtext NOT NULL, + `addedBy` varchar(30) NOT NULL DEFAULT 0, + `addedDate` datetime NOT NULL, + PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_api`; -CREATE TABLE `zt_api` -( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, - `product` varchar(255) NOT NULL DEFAULT '', - `lib` int UNSIGNED NOT NULL DEFAULT 0, - `module` int UNSIGNED NOT NULL DEFAULT 0, - `title` varchar(100) NOT NULL DEFAULT '', - `path` varchar(255) NOT NULL DEFAULT '', - `protocol` varchar(10) NOT NULL DEFAULT '', - `method` varchar(10) NOT NULL DEFAULT '', - `requestType` varchar(100) NOT NULL DEFAULT '', - `responseType` varchar(100) NOT NULL DEFAULT '', - `status` varchar(20) NOT NULL DEFAULT '', - `owner` varchar(30) NOT NULl DEFAULT 0, - `desc` text NULL, - `version` smallint UNSIGNED NOT NULL DEFAULT 0, - `params` text NULL, - `paramsExample` text NUll, - `responseExample` text NUll, - `response` text NULL, - `commonParams` text NULL, - `addedBy` varchar(30) NOT NULL DEFAULT 0, - `addedDate` datetime NOT NULL, - `editedBy` varchar(30) NOT NULL DEFAULT 0, - `editedDate` datetime NOT NULL, - `deleted` enum ('0', '1') NOT NULL DEFAULT '0', - PRIMARY KEY (`id`) +CREATE TABLE `zt_api` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `product` varchar(255) NOT NULL DEFAULT '', + `lib` int UNSIGNED NOT NULL DEFAULT 0, + `module` int UNSIGNED NOT NULL DEFAULT 0, + `title` varchar(100) NOT NULL DEFAULT '', + `path` varchar(255) NOT NULL DEFAULT '', + `protocol` varchar(10) NOT NULL DEFAULT '', + `method` varchar(10) NOT NULL DEFAULT '', + `requestType` varchar(100) NOT NULL DEFAULT '', + `responseType` varchar(100) NOT NULL DEFAULT '', + `status` varchar(20) NOT NULL DEFAULT '', + `owner` varchar(30) NOT NULl DEFAULT 0, + `desc` text NULL, + `version` smallint UNSIGNED NOT NULL DEFAULT 0, + `params` text NULL, + `paramsExample` text NUll, + `responseExample` text NUll, + `response` text NULL, + `commonParams` text NULL, + `addedBy` varchar(30) NOT NULL DEFAULT 0, + `addedDate` datetime NOT NULL, + `editedBy` varchar(30) NOT NULL DEFAULT 0, + `editedDate` datetime NOT NULL, + `deleted` enum ('0', '1') NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_apispec`; -CREATE TABLE `zt_apispec` -( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, - `doc` int UNSIGNED NOT NULL DEFAULT 0, - `module` int UNSIGNED NOT NULL DEFAULT 0, - `title` varchar(100) NOT NULL DEFAULT '', - `path` varchar(255) NOT NULL DEFAULT '', - `protocol` varchar(10) NOT NULL DEFAULT '', - `method` varchar(10) NOT NULL DEFAULT '', - `requestType` varchar(100) NOT NULL DEFAULT '', - `responseType` varchar(100) NOT NULL DEFAULT '', - `status` varchar(20) NOT NULL DEFAULT '', - `owner` varchar(255) NOT NULl DEFAULT 0, - `desc` text NULL, - `version` smallint UNSIGNED NOT NULL DEFAULT 0, - `params` text NULL, - `paramsExample` text NUll, - `responseExample` text NUll, - `response` text NULL, - `addedBy` varchar(30) NOT NULL DEFAULT 0, - `addedDate` datetime NULL, - PRIMARY KEY (`id`) +CREATE TABLE `zt_apispec` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `doc` int UNSIGNED NOT NULL DEFAULT 0, + `module` int UNSIGNED NOT NULL DEFAULT 0, + `title` varchar(100) NOT NULL DEFAULT '', + `path` varchar(255) NOT NULL DEFAULT '', + `protocol` varchar(10) NOT NULL DEFAULT '', + `method` varchar(10) NOT NULL DEFAULT '', + `requestType` varchar(100) NOT NULL DEFAULT '', + `responseType` varchar(100) NOT NULL DEFAULT '', + `status` varchar(20) NOT NULL DEFAULT '', + `owner` varchar(255) NOT NULl DEFAULT 0, + `desc` text NULL, + `version` smallint UNSIGNED NOT NULL DEFAULT 0, + `params` text NULL, + `paramsExample` text NUll, + `responseExample` text NUll, + `response` text NULL, + `addedBy` varchar(30) NOT NULL DEFAULT 0, + `addedDate` datetime NULL, + PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_apistruct`; -CREATE TABLE `zt_apistruct` -( - `id` int unsigned NOT NULL AUTO_INCREMENT, - `lib` int UNSIGNED NOT NULL DEFAULT 0, - `name` varchar(30) NOT NULL DEFAULT '', - `type` varchar(50) NOT NULL DEFAULT '', - `desc` varchar(255) NOT NULL DEFAULT '', - `version` smallint unsigned NOT NULL DEFAULT 0, - `attribute` text NULL, - `addedBy` varchar(30) NOT NULL DEFAULT 0, - `addedDate` datetime NOT NULL, - `editEdBy` varchar(30) NOT NULL DEFAULT 0, - `editedDate` datetime NOT NULL, - `deleted` enum ('0', '1') NOT NULL DEFAULT '0', - primary key (`id`) +CREATE TABLE `zt_apistruct` ( + `id` int unsigned NOT NULL AUTO_INCREMENT, + `lib` int UNSIGNED NOT NULL DEFAULT 0, + `name` varchar(30) NOT NULL DEFAULT '', + `type` varchar(50) NOT NULL DEFAULT '', + `desc` varchar(255) NOT NULL DEFAULT '', + `version` smallint unsigned NOT NULL DEFAULT 0, + `attribute` text NULL, + `addedBy` varchar(30) NOT NULL DEFAULT 0, + `addedDate` datetime NOT NULL, + `editEdBy` varchar(30) NOT NULL DEFAULT 0, + `editedDate` datetime NOT NULL, + `deleted` enum ('0', '1') NOT NULL DEFAULT '0', + primary key (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_apistruct_spec`; -CREATE TABLE `zt_apistruct_spec` -( - `id` int UNSIGNED NOT NULL AUTO_INCREMENT, - `name` varchar(255) NOT NULL DEFAULT '', - `type` varchar(50) NOT NULL DEFAULT '', - `desc` varchar(255) NOT NULL DEFAULT '', - `attribute` text NULL, - `version` smallint unsigned NOT NULL DEFAULT 0, - `addedBy` varchar(30) NOT NULL DEFAULT 0, - `addedDate` datetime NOT NULL, - primary key (`id`) +CREATE TABLE `zt_apistruct_spec` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL DEFAULT '', + `type` varchar(50) NOT NULL DEFAULT '', + `desc` varchar(255) NOT NULL DEFAULT '', + `attribute` text NULL, + `version` smallint unsigned NOT NULL DEFAULT 0, + `addedBy` varchar(30) NOT NULL DEFAULT 0, + `addedDate` datetime NOT NULL, + primary key (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_block`; CREATE TABLE IF NOT EXISTS `zt_block` ( @@ -393,6 +388,39 @@ CREATE TABLE IF NOT EXISTS `zt_dept` ( KEY `parent` (`parent`), KEY `path` (`path`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_design`; +CREATE TABLE IF NOT EXISTS `zt_design` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `project` varchar(255) NOT NULL, + `product` varchar(255) NOT NULL, + `commit` text NOT NULL, + `commitedBy` varchar(30) NOT NULL, + `execution` mediumint(8) unsigned NOT NULL DEFAULT '0', + `name` varchar(255) NOT NULL, + `status` varchar(30) NOT NULL, + `createdBy` varchar(30) NOT NULL, + `createdDate` datetime NOT NULL, + `editedBy` varchar(30) NOT NULL, + `editedDate` datetime NOT NULL, + `assignedTo` varchar(30) NOT NULL, + `assignedBy` varchar(30) NOT NULL, + `assignedDate` datetime NOT NULL, + `deleted` enum('0','1') NOT NULL DEFAULT '0', + `story` char(30) NOT NULL, + `desc` text NOT NULL, + `version` smallint(6) NOT NULL, + `type` char(30) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_designspec`; +CREATE TABLE IF NOT EXISTS `zt_designspec` ( + `design` mediumint(8) NOT NULL, + `version` smallint(6) NOT NULL, + `name` varchar(255) NOT NULL, + `desc` text NOT NULL, + `files` varchar(255) NOT NULL, + UNIQUE KEY `design` (`design`,`version`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_doc`; CREATE TABLE IF NOT EXISTS `zt_doc` ( `id` mediumint(8) unsigned NOT NULL auto_increment, @@ -1016,6 +1044,19 @@ CREATE TABLE IF NOT EXISTS `zt_searchindex` ( FULLTEXT KEY `content` (`content`), FULLTEXT KEY `title` (`title`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +-- DROP TABLE IF EXISTS `zt_stage`; +CREATE TABLE IF NOT EXISTS `zt_stage` ( + `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `percent` varchar(255) NOT NULL, + `type` varchar(255) NOT NULL, + `createdBy` varchar(30) NOT NULL, + `createdDate` datetime NOT NULL, + `editedBy` varchar(30) NOT NULL, + `editedDate` datetime NOT NULL, + `deleted` enum('0','1') NOT NULL DEFAULT '0', + PRIMARY KEY (`id`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; -- DROP TABLE IF EXISTS `zt_stakeholder`; CREATE TABLE IF NOT EXISTS `zt_stakeholder` ( `id` mediumint(8) NOT NULL AUTO_INCREMENT PRIMARY KEY, diff --git a/module/common/lang/common.php b/module/common/lang/common.php index ee993c8a48..96f8e12f14 100644 --- a/module/common/lang/common.php +++ b/module/common/lang/common.php @@ -6,6 +6,8 @@ $lang->todo = new stdclass(); $lang->program = new stdclass(); $lang->product = new stdclass(); $lang->project = new stdclass(); +$lang->design = new stdclass(); +$lang->stage = new stdclass(); $lang->scrum = new stdclass(); $lang->waterfall = new stdclass(); $lang->execution = new stdclass(); diff --git a/module/common/lang/en.php b/module/common/lang/en.php index 84156def3d..24fe453601 100644 --- a/module/common/lang/en.php +++ b/module/common/lang/en.php @@ -44,35 +44,38 @@ $lang->runInfo = "
Z PUBLIC LICENSE 1.2 . Without authorization, I should not remove, hide or cover any logos/links of ZenTao."; $lang->designedByAIUX = " AIUX"; -$lang->reset = 'Reset'; -$lang->cancel = 'Cancel'; -$lang->refresh = 'Refresh'; -$lang->create = 'Create'; -$lang->edit = 'Edit'; -$lang->delete = 'Delete'; -$lang->close = 'Close'; -$lang->unlink = 'Unlink'; -$lang->import = 'Import'; -$lang->export = 'Export'; -$lang->setFileName = 'File Name'; -$lang->submitting = 'Saving...'; -$lang->save = 'Save'; -$lang->confirm = 'Confirm'; -$lang->preview = 'View'; -$lang->goback = 'Back'; -$lang->goPC = 'PC'; -$lang->more = 'More'; -$lang->moreLink = 'MORE'; -$lang->day = ' Day'; -$lang->customConfig = 'Custom Config'; -$lang->public = 'Public'; -$lang->trunk = 'Trunk'; -$lang->sort = 'Order'; -$lang->required = 'Required'; -$lang->noData = 'No data.'; -$lang->fullscreen = 'Fullscreen'; -$lang->retrack = 'Retrack'; -$lang->whitelist = 'Access whitelist'; +$lang->reset = 'Reset'; +$lang->cancel = 'Cancel'; +$lang->refresh = 'Refresh'; +$lang->create = 'Create'; +$lang->edit = 'Edit'; +$lang->delete = 'Delete'; +$lang->close = 'Close'; +$lang->unlink = 'Unlink'; +$lang->import = 'Import'; +$lang->export = 'Export'; +$lang->setFileName = 'File Name'; +$lang->submitting = 'Saving...'; +$lang->save = 'Save'; +$lang->confirm = 'Confirm'; +$lang->preview = 'View'; +$lang->goback = 'Back'; +$lang->goPC = 'PC'; +$lang->more = 'More'; +$lang->moreLink = 'MORE'; +$lang->day = ' Day'; +$lang->customConfig = 'Custom Config'; +$lang->public = 'Public'; +$lang->trunk = 'Trunk'; +$lang->sort = 'Order'; +$lang->required = 'Required'; +$lang->noData = 'No data.'; +$lang->fullscreen = 'Fullscreen'; +$lang->retrack = 'Retrack'; +$lang->whitelist = 'Access whitelist'; +$lang->globalSetting = 'Global Setting'; +$lang->waterfallModel= 'Waterfall'; +$lang->all = 'All'; $lang->actions = 'Action'; $lang->restore = 'Reset'; @@ -161,6 +164,13 @@ $lang->dept->common = 'Dept'; $lang->upgrade->common = 'Update'; $lang->program->list = 'Program List'; $lang->program->kanban = 'Program Kanban'; +$lang->design->common = 'Design'; +$lang->design->HLDS = 'HLDS'; +$lang->design->DDS = 'DDS'; +$lang->design->DBDS = 'DBDS'; +$lang->design->ADS = 'ADS'; +$lang->stage->common = 'Stage'; +$lang->stage->list = 'Stage List'; $lang->execution->list = "{$lang->executionCommon} List"; $lang->personnel->common = 'Member'; @@ -190,7 +200,6 @@ $lang->settings = 'Settings'; $lang->overview = 'Overview'; $lang->module = 'Module'; $lang->priv = 'Privilege'; -$lang->design = 'Design'; $lang->other = 'Other'; $lang->estimation = 'Estimation'; $lang->issue = 'Issue'; diff --git a/module/common/lang/menu.php b/module/common/lang/menu.php index e53a8fd484..cd4eb4912b 100644 --- a/module/common/lang/menu.php +++ b/module/common/lang/menu.php @@ -238,6 +238,48 @@ $lang->scrum->menu->settings['subMenu']->whitelist = array('link' => "{$lang-> $lang->scrum->menu->settings['subMenu']->stakeholder = array('link' => "{$lang->stakeholder->common}|stakeholder|browse|project=%s", 'subModule' => 'stakeholder'); $lang->scrum->menu->settings['subMenu']->group = array('link' => "{$lang->priv}|project|group|project=%s", 'alias' => 'group,manageview,managepriv'); +/* Waterfall menu. */ +$lang->waterfall->menu = new stdclass(); +$lang->waterfall->menu->programplan = array('link' => "{$lang->productplan->shortCommon}|programplan|browse|project=%s&productID=0&type=lists", 'subModule' => 'programplan'); +$lang->waterfall->menu->execution = array('link' => "{$lang->stage->common}|project|execution|status=all&projectID=%s"); +$lang->waterfall->menu->story = array('link' => "$lang->SRCommon|projectstory|story|project=%s", 'subModule' => 'projectstory,tree', 'exclude' => 'projectstory-track'); +$lang->waterfall->menu->design = array('link' => "{$lang->design->common}|design|browse|project=%s"); +$lang->waterfall->menu->devops = array('link' => "{$lang->repo->common}|repo|browse|repoID=0&branchID=&objectID=%s", 'subModule' => 'repo'); +$lang->waterfall->menu->build = array('link' => "{$lang->build->common}|project|build|project=%s"); +$lang->waterfall->menu->release = array('link' => "{$lang->release->common}|projectrelease|browse|project=%s", 'subModule' => 'projectrelease'); +$lang->waterfall->menu->dynamic = array('link' => "$lang->dynamic|project|dynamic|project=%s"); + +$lang->waterfall->menu->settings = $lang->scrum->menu->settings; +$lang->waterfall->dividerMenu = ',build,dynamic,'; + +/* Waterfall menu order. */ +$lang->waterfall->menuOrder[15] = 'programplan'; +$lang->waterfall->menuOrder[20] = 'execution'; +$lang->waterfall->menuOrder[25] = 'story'; +$lang->waterfall->menuOrder[30] = 'design'; +$lang->waterfall->menuOrder[35] = 'devops'; +$lang->waterfall->menuOrder[60] = 'doc'; +$lang->waterfall->menuOrder[65] = 'build'; +$lang->waterfall->menuOrder[70] = 'release'; +$lang->waterfall->menuOrder[80] = 'dynamic'; + +$lang->waterfall->menu->doc['subMenu'] = new stdclass(); + +$lang->waterfall->menu->programplan['subMenu'] = new stdclass(); +$lang->waterfall->menu->programplan['subMenu']->lists = array('link' => "{$lang->stage->list}|programplan|browse|projectID=%s&productID=0&type=lists", 'alias' => 'create'); + +$lang->waterfall->menu->qa['subMenu'] = new stdclass(); +$lang->waterfall->menu->qa['subMenu']->bug = array('link' => "{$lang->bug->common}|project|bug|projectID=%s", 'subModule' => 'bug'); +$lang->waterfall->menu->qa['subMenu']->testcase = array('link' => "{$lang->testcase->shortCommon}|project|testcase|projectID=%s", 'subModule' => 'testsuite,testcase,caselib,tree'); +$lang->waterfall->menu->qa['subMenu']->testtask = array('link' => "{$lang->testtask->common}|project|testtask|projectID=%s", 'subModule' => 'testtask', 'class' => 'dropdown dropdown-hover'); + +$lang->waterfall->menu->design['subMenu'] = new stdclass(); +$lang->waterfall->menu->design['subMenu']->all = array("link' => '$lang->all|design|browse|projectID=%s&productID=0&browseType=all"); +$lang->waterfall->menu->design['subMenu']->hlds = array("link' => '{$lang->design->HLDS}|design|browse|projectID=%s&productID=0&browseType=HLDS"); +$lang->waterfall->menu->design['subMenu']->dds = array("link' => '{$lang->design->DDS}|design|browse|projectID=%s&productID=0&browseType=DDS"); +$lang->waterfall->menu->design['subMenu']->dbds = array("link' => '{$lang->design->DBDS}|design|browse|projectID=%s&productID=0&browseType=DBDS"); +$lang->waterfall->menu->design['subMenu']->ads = array("link' => {$lang->design->ADS}|design|browse|projectID=%s&productID=0&browseType=ADS"); +$lang->waterfall->menu->design['subMenu']->bysearch = array('link' => ' ' . $lang->searchAB . ''); /* Execution menu. */ $lang->execution->homeMenu = new stdclass(); @@ -414,13 +456,26 @@ $lang->company->menuOrder[30] = 'addUser'; $lang->admin->menu = new stdclass(); $lang->admin->menu->index = array('link' => "$lang->indexPage|admin|index", 'alias' => 'register,certifytemail,certifyztmobile,ztcompany'); $lang->admin->menu->company = array('link' => "{$lang->personnel->common}|company|browse|", 'subModule' => ',user,dept,group,'); -$lang->admin->menu->model = array('link' => "$lang->model|custom|browsestoryconcept|", 'subModule' => 'holiday'); +$lang->admin->menu->model = array('link' => "$lang->model|custom|browsestoryconcept|", 'class' => 'dropdown dropdown-hover', 'exclude' => 'custom-index,custom-set,custom-product,custom-execution,custom-required,custom-flow,custom-score,custom-feedback,custom-timezone,custom-mode'); $lang->admin->menu->custom = array('link' => "{$lang->custom->common}|custom|index", 'exclude' => 'custom-browsestoryconcept,custom-timezone,custom-estimate'); $lang->admin->menu->extension = array('link' => "{$lang->extension->common}|extension|browse", 'subModule' => 'extension'); $lang->admin->menu->dev = array('link' => "$lang->redev|dev|api", 'alias' => 'db', 'subModule' => 'dev,editor,entry'); $lang->admin->menu->message = array('link' => "{$lang->message->common}|message|index", 'subModule' => 'message,mail,webhook'); $lang->admin->menu->system = array('link' => "{$lang->admin->system}|backup|index", 'subModule' => 'cron,backup,action,admin,search', 'exclude' => 'admin-index,admin-xuanxuan,admin-register,admin-ztcompany'); +if($config->systemMode == 'new') +{ + $lang->admin->menu->model['dropMenu'] = new stdclass(); + $lang->admin->menu->model['dropMenu']->allModel = array('link' => "{$lang->globalSetting}|custom|browsestoryconcept|", 'subModule' => 'subject,custom,meetingroom,baseline'); + $lang->admin->menu->model['dropMenu']->waterfall = array('link' => "{$lang->waterfallModel}|stage|setType|", 'subModule' => 'stage,measurement,auditcl,cmcl,process,activity,zoutput,classify,sqlbuilder,reviewcl,reviewsetting,report'); + + $lang->admin->menu->allModel['subMenu'] = new stdclass(); + $lang->admin->menu->allModel['subMenu']->storyConcept = array('link' => '需求概念|custom|browsestoryconcept|'); + + $lang->admin->menu->waterfall['subMenu'] = new stdclass(); + $lang->admin->menu->waterfall['subMenu']->stage = array('link' => '阶段|stage|setType|', 'subModule' => 'stage'); +} + /* Admin menu order. */ $lang->admin->menuOrder[5] = 'index'; $lang->admin->menuOrder[10] = 'company'; @@ -506,6 +561,8 @@ $lang->navGroup->story = 'product'; $lang->navGroup->project = 'project'; $lang->navGroup->deploy = 'project'; +$lang->navGroup->programplan = 'project'; +$lang->navGroup->design = 'project'; $lang->navGroup->stakeholder = 'project'; $lang->navGroup->projectbuild = 'project'; diff --git a/module/common/lang/zh-cn.php b/module/common/lang/zh-cn.php index 97ba7d7763..8e92b3e49c 100644 --- a/module/common/lang/zh-cn.php +++ b/module/common/lang/zh-cn.php @@ -44,35 +44,38 @@ $lang->runInfo = "
《Z PUBLIC LICENSE授权协议1.2》。未经许可,不得去除、隐藏或遮掩禅道软件的任何标志及链接。"; $lang->designedByAIUX = " 艾体验设计"; -$lang->reset = '重填'; -$lang->cancel = '取消'; -$lang->refresh = '刷新'; -$lang->create = '新建'; -$lang->edit = '编辑'; -$lang->delete = '删除'; -$lang->close = '关闭'; -$lang->unlink = '移除'; -$lang->import = '导入'; -$lang->export = '导出'; -$lang->setFileName = '文件名:'; -$lang->submitting = '稍候...'; -$lang->save = '保存'; -$lang->confirm = '确认'; -$lang->preview = '查看'; -$lang->goback = '返回'; -$lang->goPC = 'PC版'; -$lang->more = '更多'; -$lang->moreLink = 'More'; -$lang->day = '天'; -$lang->customConfig = '自定义'; -$lang->public = '公共'; -$lang->trunk = '主干'; -$lang->sort = '排序'; -$lang->required = '必填'; -$lang->noData = '暂无'; -$lang->fullscreen = '全屏'; -$lang->retrack = '收起'; -$lang->whitelist = '访问白名单'; +$lang->reset = '重填'; +$lang->cancel = '取消'; +$lang->refresh = '刷新'; +$lang->create = '新建'; +$lang->edit = '编辑'; +$lang->delete = '删除'; +$lang->close = '关闭'; +$lang->unlink = '移除'; +$lang->import = '导入'; +$lang->export = '导出'; +$lang->setFileName = '文件名:'; +$lang->submitting = '稍候...'; +$lang->save = '保存'; +$lang->confirm = '确认'; +$lang->preview = '查看'; +$lang->goback = '返回'; +$lang->goPC = 'PC版'; +$lang->more = '更多'; +$lang->moreLink = 'More'; +$lang->day = '天'; +$lang->customConfig = '自定义'; +$lang->public = '公共'; +$lang->trunk = '主干'; +$lang->sort = '排序'; +$lang->required = '必填'; +$lang->noData = '暂无'; +$lang->fullscreen = '全屏'; +$lang->retrack = '收起'; +$lang->whitelist = '访问白名单'; +$lang->globalSetting = '全局设置'; +$lang->waterfallModel= '瀑布模型'; +$lang->all = '所有'; $lang->actions = '操作'; $lang->restore = '恢复默认'; @@ -161,6 +164,13 @@ $lang->dept->common = '部门'; $lang->upgrade->common = '升级'; $lang->program->list = '项目集列表'; $lang->program->kanban = '项目集看板'; +$lang->design->common = '设计'; +$lang->design->HLDS = '概要设计'; +$lang->design->DDS = '详细设计'; +$lang->design->DBDS = '数据库设计'; +$lang->design->ADS = '接口设计'; +$lang->stage->common = '阶段'; +$lang->stage->list = '阶段列表'; $lang->execution->list = "{$lang->executionCommon}列表"; $lang->personnel->common = '人员'; @@ -190,7 +200,6 @@ $lang->settings = '设置'; $lang->overview = '概况'; $lang->module = '模块'; $lang->priv = '权限'; -$lang->design = '设计'; $lang->other = '其他'; $lang->estimation = '估算'; $lang->issue = '问题'; diff --git a/module/design/config.php b/module/design/config.php new file mode 100644 index 0000000000..61486c4830 --- /dev/null +++ b/module/design/config.php @@ -0,0 +1,32 @@ +design = new stdclass(); +$config->design->editor = new stdclass(); +$config->design->editor->create = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->design->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools'); +$config->design->editor->assignto = array('id' => 'comment', 'tools' => 'simpleTools'); + +$config->design->create = new stdclass(); +$config->design->edit = new stdclass(); +$config->design->create->requiredFields = 'name,type'; +$config->design->edit->requiredFields = 'name,type'; + +$config->design->affectedFixedNum = 7; + +global $lang; +$config->design->search['module'] = 'design'; +$config->design->search['fields']['id'] = $lang->design->id; +$config->design->search['fields']['type'] = $lang->design->type; +$config->design->search['fields']['name'] = $lang->design->name; +$config->design->search['fields']['commit'] = $lang->design->submission; +$config->design->search['fields']['createdBy'] = $lang->design->createdBy; +$config->design->search['fields']['createdDate'] = $lang->design->createdDate; +$config->design->search['fields']['assignedTo'] = $lang->design->assignedTo; +$config->design->search['fields']['story'] = $lang->design->story; + +$config->design->search['params']['type'] = array('operator' => '=', 'control' => 'select', 'values' => $lang->design->typeList); +$config->design->search['params']['name'] = array('operator' => 'include', 'control' => 'input', 'values' => ''); +$config->design->search['params']['commit'] = array('operator' => 'include', 'control' => 'input', 'values' => ''); +$config->design->search['params']['createdBy'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->design->search['params']['createdDate'] = array('operator' => '=', 'control' => 'input', 'values' => '', 'class' => 'date'); +$config->design->search['params']['assignedTo'] = array('operator' => '=', 'control' => 'select', 'values' => 'users'); +$config->design->search['params']['story'] = array('operator' => '=', 'control' => 'select', 'values' => ''); diff --git a/module/design/control.php b/module/design/control.php new file mode 100644 index 0000000000..b70a81edae --- /dev/null +++ b/module/design/control.php @@ -0,0 +1,485 @@ + + * @package design + * @version $Id: control.php 5107 2020-09-02 09:46:12Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +class design extends control +{ + /** + * Construct function, load module auto. + * + * @param string $moduleName + * @param string $methodName + * @access public + * @return void + */ + public function __construct($moduleName = '', $methodName = '') + { + parent::__construct($moduleName, $methodName); + + $this->loadModel('product'); + $this->loadModel('project'); + $this->loadModel('task'); + } + + /** + * Design common action. + * + * @param int $projectID + * @param int $productID + * @param int $designID + * @access public + * @return void + */ + public function commonAction($projectID = 0, $productID = 0, $designID = 0) + { + $products = $this->product->getProductPairsByProject($projectID); + $productID = $this->product->saveState($productID, $products); + + $this->lang->modulePageNav = $this->design->setMenu($projectID, $products, $productID); + $this->project->setMenu($projectID); + $this->view->products = $products; + + return $productID; + } + + /** + * Browse designs. + * + * @param int $projectID + * @param int $productID + * @param string $type all|bySearch|HLDS|DDS|DBDS|ADS + * @param string $param + * @param string $orderBy + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function browse($projectID = 0, $productID = 0, $type = 'all', $param = '', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $productID = $this->commonAction($projectID, $productID); + + /* Save session for design list and process product id. */ + $this->session->set('designList', $this->app->getURI(true), 'project'); + + /* Build the search form. */ + $queryID = ($type == 'bySearch') ? (int)$param : 0; + $actionURL = $this->createLink('design', 'browse', "projectID=$projectID&productID=$productID&type=bySearch&queryID=myQueryID"); + $this->design->buildSearchForm($queryID, $actionURL); + + /* Print top and right actions. */ + $this->lang->TRActions = ''; + + /* Init pager and get designs. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init(0, $recPerPage, $pageID); + $designs = $this->design->getList($projectID, $productID, $type, $queryID, $orderBy, $pager); + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->browse; + $this->view->position[] = $this->lang->design->browse; + + $this->view->designs = $designs; + $this->view->type = $type; + $this->view->param = $param; + $this->view->orderBy = $orderBy; + $this->view->productID = $productID; + $this->view->projectID = $projectID; + $this->view->pager = $pager; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + $this->display(); + } + + /** + * Create a design. + * + * @param int $projectID + * @param int $productID + * @param string $type + * @access public + * @return void + */ + public function create($projectID = 0, $productID = 0, $type = 'all') + { + $productID = $this->commonAction($projectID, $productID); + + if($_POST) + { + $designID = $this->design->create($projectID); + + if(dao::isError()) + { + $response['result'] = 'fail'; + $response['message'] = dao::getError(); + return $this->send($response); + } + + $this->loadModel('action')->create('design', $designID, 'created'); + + $response['result'] = 'success'; + $response['message'] = $this->lang->saveSuccess; + $response['locate'] = $this->createLink('design', 'browse', "projectID=$projectID&productID=$productID"); + return $this->send($response); + } + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->create; + $this->view->position[] = $this->lang->design->create; + + $this->view->users = $this->loadModel('user')->getPairs('noclosed'); + $this->view->stories = $this->loadModel('story')->getProductStoryPairs($productID); + $this->view->productID = $productID; + $this->view->type = $type; + $this->view->project = $this->loadModel('project')->getByID($projectID); + + $this->display(); + } + + /** + * Batch create designs. + * + * @param int $projectID + * @param int $productID + * @param string $type + * @access public + * @return void + */ + public function batchCreate($projectID = 0, $productID = 0, $type = 'all') + { + $productID = $this->commonAction($projectID, $productID); + + if($_POST) + { + $this->design->batchCreate($projectID, $productID); + + if(dao::isError()) + { + $response['result'] = 'fail'; + $response['message'] = dao::getError(); + return $this->send($response); + } + + $response['result'] = 'success'; + $response['message'] = $this->lang->saveSuccess; + $response['locate'] = inlink('browse', "projectID=$projectID&productID=$productID"); + + return $this->send($response); + } + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->batchCreate; + $this->view->position[] = $this->lang->design->batchCreate; + + $this->view->stories = $this->loadModel('story')->getProductStoryPairs($productID); + $this->view->users = $this->loadModel('user')->getPairs('noclosed'); + $this->view->type = $type; + + $this->display(); + } + + /** + * View a design. + * + * @param int $designID + * @access public + * @return void + */ + public function view($designID = 0) + { + $design = $this->design->getByID($designID); + $productID = $this->commonAction($design->project, $design->product, $designID); + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->view; + $this->view->position[] = $this->lang->design->view; + + $this->view->design = $design; + $this->view->stories = $this->loadModel('story')->getProductStoryPairs($design->product); + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + $this->view->actions = $this->loadModel('action')->getList('design', $design->id); + + $this->display(); + } + + /** + * Edit a design. + * + * @param int $designID + * @access public + * @return void + */ + public function edit($designID = 0) + { + $design = $this->design->getByID($designID); + $design = $this->design->getAffectedScope($design); + $productID = $this->commonAction($design->project, $design->product, $designID); + + if($_POST) + { + $changes = $this->design->update($designID); + + if(dao::isError()) + { + $response['result'] = 'fail'; + $response['message'] = dao::getError(); + return $this->send($response); + } + + if(!empty($changes)) + { + $actionID = $this->loadModel('action')->create('design', $designID, 'changed'); + $this->action->logHistory($actionID, $changes); + } + + $response['result'] = 'success'; + $response['message'] = $this->lang->saveSuccess; + $response['locate'] = $this->createLink('design', 'view', "id=$design->id"); + return $this->send($response); + } + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->edit; + $this->view->position[] = $this->lang->design->edit; + + $this->view->design = $design; + $this->view->project = $this->loadModel('project')->getByID($design->project); + $this->view->stories = $this->loadModel('story')->getProductStoryPairs($design->product); + + $this->display(); + } + + /** + * Design link commits. + * + * @param int $designID + * @param int $repoID + * @param string $begin + * @param string $end + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function linkCommit($designID = 0, $repoID = 0, $begin = '', $end = '', $recTotal = 0, $recPerPage = 50, $pageID = 1) + { + $design = $this->design->getById($designID); + $productID = $this->commonAction($design->project, $design->product, $designID); + + /* Get project and date. */ + $project = $this->loadModel('project')->getByID($design->project); + $begin = $begin ? date('Y-m-d', strtotime($begin)) : $project->begin; + $end = $end ? date('Y-m-d', strtotime($end)) : helper::today(); + + /* Get the repository information through the repoID. */ + $repos = $this->loadModel('repo')->getRepoPairs($design->project); + $repoID = $repoID ? $repoID : key($repos); + + if(empty($repoID)) die(js::locate(helper::createLink('repo', 'create', "objectID=$design->project"))); + + $repo = $this->loadModel('repo')->getRepoByID($repoID); + $revisions = $this->repo->getCommits($repo, '', 'HEAD', '', '', $begin, $end); + + if($_POST) + { + $this->design->linkCommit($designID, $repoID); + + $result['result'] = 'success'; + $result['message'] = $this->lang->saveSuccess; + $result['locate'] = 'parent'; + return $this->send($result); + } + + /* Linked submission. */ + $linkedRevisions = array(); + $relations = $this->loadModel('common')->getRelations('design', $designID, 'commit'); + foreach($relations as $relation) $linkedRevisions[$relation->BID] = $relation->BID; + + foreach($revisions as $id => $commit) + { + if(isset($linkedRevisions[$commit->id])) unset($revisions[$id]); + } + + /* Init pager. */ + $this->app->loadClass('pager', $static = true); + $recTotal = count($revisions); + $pager = new pager($recTotal, $recPerPage, $pageID); + $revisions = array_chunk($revisions, $pager->recPerPage); + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->linkCommit; + $this->view->position[] = $this->lang->design->linkCommit; + + $this->view->repos = $repos; + $this->view->repoID = $repoID; + $this->view->repo = $repo; + $this->view->revisions = empty($revisions) ? $revisions : $revisions[$pageID - 1]; + $this->view->designID = $designID; + $this->view->begin = $begin; + $this->view->end = $end; + $this->view->design = $this->design->getByID($designID); + $this->view->pager = $pager; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + $this->display(); + } + + /** + * Design unlink commits. + * + * @param int $designID + * @param int $commitID + * @param string $confirm + * @access public + * @return void + */ + public function unlinkCommit($designID = 0, $commitID = 0, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->design->confirmUnlink, inlink('unlinkCommit', "designID=$designID&commitID=$commitID&confirm=yes"))); + } + else + { + $this->design->unlinkCommit($designID, $commitID); + + die(js::reload('parent')); + } + } + + /** + * View a design's commit. + * + * @param int $designID + * @param int $recTotal + * @param int $recPerPage + * @param int $pageID + * @access public + * @return void + */ + public function viewCommit($designID = 0, $recTotal = 0, $recPerPage = 20, $pageID = 1) + { + $design = $this->design->getByID($designID); + $productID = $this->commonAction($design->project, $design->product, $designID); + + /* Init pager. */ + $this->app->loadClass('pager', $static = true); + $pager = pager::init(0, $recPerPage, $pageID); + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->submission; + $this->view->position[] = $this->lang->design->submission; + + $this->view->design = $this->design->getCommit($designID, $pager); + $this->view->pager = $pager; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + $this->display(); + } + + /** + * A version of the repository. + * + * @param int $repoID + * @param int $projectID + * @access public + * @return void + */ + public function revision($repoID = 0, $projectID = 0) + { + $repo = $this->dao->select('*')->from(TABLE_REPOHISTORY)->where('id')->eq($repoID)->fetch(); + $repoURL = $this->createLink('repo', 'revision', "repoID=$repo->repo&objectID=$projectID&revistion=$repo->revision"); + header("location:" . $repoURL); + } + + /** + * Ajax get design drop menu. + * + * @param int $projectID + * @param int $productID + * @param string $extra + * @access public + * @return void + */ + public function ajaxGetDropMenu($projectID, $productID) + { + $products = $this->loadModel('product')->getProducts($projectID); + + $this->view->link = helper::createLink('design', 'browse', "projectID=$projectID&productID=%s"); + $this->view->productID = $productID; + $this->view->products = $products; + $this->view->projectID = $projectID; + $this->display(); + } + + /** + * Delete a design. + * + * @param int $designID + * @param string $confirm + * @access public + * @return void + */ + public function delete($designID = 0, $confirm = 'no') + { + if($confirm == 'no') + { + die(js::confirm($this->lang->design->confirmDelete, inlink('delete', "designID=$designID&confirm=yes"))); + } + else + { + $this->design->delete(TABLE_DESIGN, $designID); + $this->dao->delete()->from(TABLE_RELATION)->where('Atype')->eq('design')->andWhere('AID')->eq($designID)->andWhere('Btype')->eq('commit')->andwhere('relation')->eq('completedin')->exec(); + $this->dao->delete()->from(TABLE_RELATION)->where('Atype')->eq('commit')->andWhere('BID')->eq($designID)->andWhere('Btype')->eq('design')->andwhere('relation')->eq('completedfrom')->exec(); + + die(js::locate($this->session->designList, 'parent')); + } + } + + /** + * Update assign of design. + * + * @param int $designID + * @access public + * @return void + */ + public function assignTo($designID = 0) + { + if($_POST) + { + $changes = $this->design->assign($designID); + if(dao::isError()) die(js::error(dao::getError())); + + $this->loadModel('action'); + if(!empty($changes)) + { + $actionID = $this->action->create('design', $designID, 'Assigned', $this->post->comment, $this->post->assignedTo); + $this->action->logHistory($actionID, $changes); + } + + if(isonlybody()) die(js::closeModal('parent.parent', 'this')); + die(js::locate($this->createLink('design', 'browse'), 'parent')); + } + + $design = $this->design->getByID($designID); + + $this->view->title = $this->lang->design->common . $this->lang->colon . $this->lang->design->assignedTo; + $this->view->position[] = $this->lang->design->assignedTo; + + $this->view->design = $design; + $this->view->users = $this->loadModel('project')->getTeamMemberPairs($design->project); + $this->display(); + } +} diff --git a/module/design/css/browse.css b/module/design/css/browse.css new file mode 100644 index 0000000000..b3ee542a8e --- /dev/null +++ b/module/design/css/browse.css @@ -0,0 +1,3 @@ +#featurebar {display:inline-block;} +#querybox #searchform {border-bottom: 1px solid #ddd; margin-bottom: 20px;} +#designTable td {white-space:nowrap; text-overflow:ellipsis; overflow: hidden} diff --git a/module/design/css/edit.css b/module/design/css/edit.css new file mode 100644 index 0000000000..98893529a9 --- /dev/null +++ b/module/design/css/edit.css @@ -0,0 +1 @@ +.tabs .tab-pane .table{border: 1px solid #ddd; border-top: none} diff --git a/module/design/css/linkcommit.css b/module/design/css/linkcommit.css new file mode 100644 index 0000000000..d1a2a856a5 --- /dev/null +++ b/module/design/css/linkcommit.css @@ -0,0 +1,8 @@ +#mainContent {min-height: 350px;} +.searchBox{min-height: 45px;} +.searchBox .srearch-date{float: left; width: 20%} +.searchBox h4{float:left;display: inline-block} +.searchBox span{float:left;line-height:30px} +#logForm .table thead th{background: #efefef} +#begin{margin-right:5px} +#end{margin-left:5px} diff --git a/module/design/js/batchcreate.js b/module/design/js/batchcreate.js new file mode 100644 index 0000000000..169bc7dcd8 --- /dev/null +++ b/module/design/js/batchcreate.js @@ -0,0 +1,4 @@ +$(function() +{ + $('#subNavbar .nav li[data-id=' + type.toLowerCase() + ']').addClass('active'); +}) diff --git a/module/design/js/browse.js b/module/design/js/browse.js new file mode 100644 index 0000000000..67aeb16078 --- /dev/null +++ b/module/design/js/browse.js @@ -0,0 +1,5 @@ +$(function() +{ + $('#subNavbar .nav li').removeClass('active'); + $('#subNavbar .nav li[data-id=' + type + ']').addClass('active'); +}) diff --git a/module/design/js/common.js b/module/design/js/common.js new file mode 100644 index 0000000000..228284b775 --- /dev/null +++ b/module/design/js/common.js @@ -0,0 +1,16 @@ +$(document).on('click', '.ajaxPager', function() +{ + $('#logBox').load($(this).attr('href')); + return false; +}) +$('#product').change(function() +{ + productID = $(this).val(); + var link = createLink('story', 'ajaxGetProductStories', 'productID=' + productID); + $.post(link, function(data) + { + $('#story').replaceWith(data); + $('#story_chosen').remove(); + $('#story').chosen(); + }) +}) diff --git a/module/design/js/create.js b/module/design/js/create.js new file mode 100644 index 0000000000..169bc7dcd8 --- /dev/null +++ b/module/design/js/create.js @@ -0,0 +1,4 @@ +$(function() +{ + $('#subNavbar .nav li[data-id=' + type.toLowerCase() + ']').addClass('active'); +}) diff --git a/module/design/js/edit.js b/module/design/js/edit.js new file mode 100644 index 0000000000..169bc7dcd8 --- /dev/null +++ b/module/design/js/edit.js @@ -0,0 +1,4 @@ +$(function() +{ + $('#subNavbar .nav li[data-id=' + type.toLowerCase() + ']').addClass('active'); +}) diff --git a/module/design/js/linkcommit.js b/module/design/js/linkcommit.js new file mode 100644 index 0000000000..66527962f7 --- /dev/null +++ b/module/design/js/linkcommit.js @@ -0,0 +1,28 @@ +$('#begin, #end, #repo').change(function() +{ + var begin = $('#begin').val(); + var end = $('#end').val(); + var repo = $('#repo').val(); + + if(begin.indexOf('-') != -1) + { + var beginarray = begin.split("-"); + var begin = ''; + for(i = 0; i < beginarray.length; i++) begin = begin + beginarray[i]; + } + if(end.indexOf('-') != -1) + { + var endarray = end.split("-"); + var end = ''; + for(i = 0 ; i < endarray.length ; i++) end = end + endarray[i]; + } + + if(begin > end) + { + alert(errorDate); + location.href = createLink('design', 'linkCommit', "designID=" + designID + '&repoID=' + repo); + die; + } + + location.href = createLink('design', 'linkCommit', "designID=" + designID + '&repoID=' + repo + '&begin=' + begin + '&end=' + end); +}) diff --git a/module/design/js/view.js b/module/design/js/view.js new file mode 100644 index 0000000000..169bc7dcd8 --- /dev/null +++ b/module/design/js/view.js @@ -0,0 +1,4 @@ +$(function() +{ + $('#subNavbar .nav li[data-id=' + type.toLowerCase() + ']').addClass('active'); +}) diff --git a/module/design/lang/de.php b/module/design/lang/de.php new file mode 100644 index 0000000000..27564bc73a --- /dev/null +++ b/module/design/lang/de.php @@ -0,0 +1,78 @@ + + * @package design + * @version $Id: en.php 4729 2020-09-01 07:53:55Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +/* 字段列表. */ +$lang->design->id = 'ID'; +$lang->design->name = 'Name'; +$lang->design->story = 'Story'; +$lang->design->type = 'Type'; +$lang->design->ditto = 'Ditto'; +$lang->design->submission = 'Commit'; +$lang->design->version = 'Revision'; +$lang->design->assignedTo = 'AssignedTo'; +$lang->design->actions = 'Actions'; +$lang->design->byQuery = 'Search'; +$lang->design->products = 'Linked Product'; +$lang->design->story = 'Linked Story'; +$lang->design->file = 'File'; +$lang->design->desc = 'Description'; +$lang->design->range = 'Impact'; +$lang->design->product = 'Linked Product'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->commitBy = 'Commit By'; +$lang->design->commitDate = 'Committed Date'; +$lang->design->affectedStory = "{$lang->SRCommon}"; +$lang->design->affectedTasks = 'Task'; +$lang->design->reviewObject = 'Review Object'; +$lang->design->createdBy = 'CreatedBy'; +$lang->design->createdDate = 'CreatedDate'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->noAssigned = 'Unassigned'; +$lang->design->comment = 'Comment'; + +/* 动作列表. */ +$lang->design->common = 'Design'; +$lang->design->create = 'Create Design'; +$lang->design->batchCreate = 'Batch Create'; +$lang->design->edit = 'Edit'; +$lang->design->delete = 'Delete'; +$lang->design->view = 'View'; +$lang->design->browse = 'List'; +$lang->design->viewCommit = 'View Commit'; +$lang->design->linkCommit = 'Link Commit'; +$lang->design->unlinkCommit = 'Unlink Commit'; +$lang->design->submit = 'Submit Review'; +$lang->design->assignTo = 'Assign'; +$lang->design->revision = 'Linked Code'; + +/* 字段取值. */ +$lang->design->typeList = array(); +$lang->design->typeList[''] = ''; +$lang->design->typeList['HLDS'] = 'High-Level'; +$lang->design->typeList['DDS'] = 'Detailed'; +$lang->design->typeList['DBDS'] = 'Database'; +$lang->design->typeList['ADS'] = 'API'; + +$lang->design->rangeList = array(); +$lang->design->rangeList['all'] = 'All'; +$lang->design->rangeList['assign'] = 'Selected'; + +$lang->design->featureBar['all'] = 'All'; +$lang->design->featureBar += $lang->design->typeList; + +/* 提示信息. */ +$lang->design->errorSelection = 'No record selected!'; +$lang->design->noDesign = 'No record.'; +$lang->design->noCommit = 'No record commited.'; +$lang->design->confirmDelete = 'Do you want to delete this design?'; +$lang->design->confirmUnlink = 'Are you sure you want to remove this submission?'; +$lang->design->errorDate = 'The start date can not be greater than the end date.'; +$lang->design->deleted = 'Deleted'; diff --git a/module/design/lang/en.php b/module/design/lang/en.php new file mode 100644 index 0000000000..8aba9b5c9f --- /dev/null +++ b/module/design/lang/en.php @@ -0,0 +1,80 @@ + + * @package design + * @version $Id: en.php 4729 2020-09-01 07:53:55Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +/* 字段列表. */ +$lang->design->id = 'ID'; +$lang->design->name = 'Name'; +$lang->design->story = 'Story'; +$lang->design->type = 'Type'; +$lang->design->ditto = 'Ditto'; +$lang->design->submission = 'Commit'; +$lang->design->version = 'Revision'; +$lang->design->assignedTo = 'AssignedTo'; +$lang->design->actions = 'Actions'; +$lang->design->byQuery = 'Search'; +$lang->design->products = 'Linked Product'; +$lang->design->story = 'Linked Story'; +$lang->design->file = 'File'; +$lang->design->desc = 'Description'; +$lang->design->range = 'Impact'; +$lang->design->product = 'Linked Product'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->commitBy = 'Commit By'; +$lang->design->commitDate = 'Committed Date'; +$lang->design->affectedStory = "{$lang->SRCommon}"; +$lang->design->affectedTasks = 'Task'; +$lang->design->reviewObject = 'Review Object'; +$lang->design->createdBy = 'CreatedBy'; +$lang->design->createdDate = 'CreatedDate'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->noAssigned = 'Unassigned'; +$lang->design->comment = 'Comment'; + +/* 动作列表. */ +$lang->design->common = 'Design'; +$lang->design->create = 'Create Design'; +$lang->design->batchCreate = 'Batch Create'; +$lang->design->edit = 'Edit'; +$lang->design->delete = 'Delete'; +$lang->design->view = 'View'; +$lang->design->browse = 'List'; +$lang->design->viewCommit = 'View Commit'; +$lang->design->linkCommit = 'Link Commit'; +$lang->design->unlinkCommit = 'Unlink Commit'; +$lang->design->submit = 'Submit Review'; +$lang->design->assignTo = 'Assign'; +$lang->design->revision = 'Linked Code'; + +$lang->design->browseAction = 'Design List'; + +/* 字段取值. */ +$lang->design->typeList = array(); +$lang->design->typeList[''] = ''; +$lang->design->typeList['HLDS'] = 'High-Level'; +$lang->design->typeList['DDS'] = 'Detailed'; +$lang->design->typeList['DBDS'] = 'Database'; +$lang->design->typeList['ADS'] = 'API'; + +$lang->design->rangeList = array(); +$lang->design->rangeList['all'] = 'All'; +$lang->design->rangeList['assign'] = 'Selected'; + +$lang->design->featureBar['all'] = 'All'; +$lang->design->featureBar += $lang->design->typeList; + +/* 提示信息. */ +$lang->design->errorSelection = 'No record selected!'; +$lang->design->noDesign = 'No record.'; +$lang->design->noCommit = 'No record commited.'; +$lang->design->confirmDelete = 'Do you want to delete this design?'; +$lang->design->confirmUnlink = 'Are you sure you want to remove this submission?'; +$lang->design->errorDate = 'The start date can not be greater than the end date.'; +$lang->design->deleted = 'Deleted'; diff --git a/module/design/lang/fr.php b/module/design/lang/fr.php new file mode 100644 index 0000000000..27564bc73a --- /dev/null +++ b/module/design/lang/fr.php @@ -0,0 +1,78 @@ + + * @package design + * @version $Id: en.php 4729 2020-09-01 07:53:55Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +/* 字段列表. */ +$lang->design->id = 'ID'; +$lang->design->name = 'Name'; +$lang->design->story = 'Story'; +$lang->design->type = 'Type'; +$lang->design->ditto = 'Ditto'; +$lang->design->submission = 'Commit'; +$lang->design->version = 'Revision'; +$lang->design->assignedTo = 'AssignedTo'; +$lang->design->actions = 'Actions'; +$lang->design->byQuery = 'Search'; +$lang->design->products = 'Linked Product'; +$lang->design->story = 'Linked Story'; +$lang->design->file = 'File'; +$lang->design->desc = 'Description'; +$lang->design->range = 'Impact'; +$lang->design->product = 'Linked Product'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->commitBy = 'Commit By'; +$lang->design->commitDate = 'Committed Date'; +$lang->design->affectedStory = "{$lang->SRCommon}"; +$lang->design->affectedTasks = 'Task'; +$lang->design->reviewObject = 'Review Object'; +$lang->design->createdBy = 'CreatedBy'; +$lang->design->createdDate = 'CreatedDate'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->noAssigned = 'Unassigned'; +$lang->design->comment = 'Comment'; + +/* 动作列表. */ +$lang->design->common = 'Design'; +$lang->design->create = 'Create Design'; +$lang->design->batchCreate = 'Batch Create'; +$lang->design->edit = 'Edit'; +$lang->design->delete = 'Delete'; +$lang->design->view = 'View'; +$lang->design->browse = 'List'; +$lang->design->viewCommit = 'View Commit'; +$lang->design->linkCommit = 'Link Commit'; +$lang->design->unlinkCommit = 'Unlink Commit'; +$lang->design->submit = 'Submit Review'; +$lang->design->assignTo = 'Assign'; +$lang->design->revision = 'Linked Code'; + +/* 字段取值. */ +$lang->design->typeList = array(); +$lang->design->typeList[''] = ''; +$lang->design->typeList['HLDS'] = 'High-Level'; +$lang->design->typeList['DDS'] = 'Detailed'; +$lang->design->typeList['DBDS'] = 'Database'; +$lang->design->typeList['ADS'] = 'API'; + +$lang->design->rangeList = array(); +$lang->design->rangeList['all'] = 'All'; +$lang->design->rangeList['assign'] = 'Selected'; + +$lang->design->featureBar['all'] = 'All'; +$lang->design->featureBar += $lang->design->typeList; + +/* 提示信息. */ +$lang->design->errorSelection = 'No record selected!'; +$lang->design->noDesign = 'No record.'; +$lang->design->noCommit = 'No record commited.'; +$lang->design->confirmDelete = 'Do you want to delete this design?'; +$lang->design->confirmUnlink = 'Are you sure you want to remove this submission?'; +$lang->design->errorDate = 'The start date can not be greater than the end date.'; +$lang->design->deleted = 'Deleted'; diff --git a/module/design/lang/vi.php b/module/design/lang/vi.php new file mode 100644 index 0000000000..27564bc73a --- /dev/null +++ b/module/design/lang/vi.php @@ -0,0 +1,78 @@ + + * @package design + * @version $Id: en.php 4729 2020-09-01 07:53:55Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +/* 字段列表. */ +$lang->design->id = 'ID'; +$lang->design->name = 'Name'; +$lang->design->story = 'Story'; +$lang->design->type = 'Type'; +$lang->design->ditto = 'Ditto'; +$lang->design->submission = 'Commit'; +$lang->design->version = 'Revision'; +$lang->design->assignedTo = 'AssignedTo'; +$lang->design->actions = 'Actions'; +$lang->design->byQuery = 'Search'; +$lang->design->products = 'Linked Product'; +$lang->design->story = 'Linked Story'; +$lang->design->file = 'File'; +$lang->design->desc = 'Description'; +$lang->design->range = 'Impact'; +$lang->design->product = 'Linked Product'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->commitBy = 'Commit By'; +$lang->design->commitDate = 'Committed Date'; +$lang->design->affectedStory = "{$lang->SRCommon}"; +$lang->design->affectedTasks = 'Task'; +$lang->design->reviewObject = 'Review Object'; +$lang->design->createdBy = 'CreatedBy'; +$lang->design->createdDate = 'CreatedDate'; +$lang->design->basicInfo = 'Basic Information'; +$lang->design->noAssigned = 'Unassigned'; +$lang->design->comment = 'Comment'; + +/* 动作列表. */ +$lang->design->common = 'Design'; +$lang->design->create = 'Create Design'; +$lang->design->batchCreate = 'Batch Create'; +$lang->design->edit = 'Edit'; +$lang->design->delete = 'Delete'; +$lang->design->view = 'View'; +$lang->design->browse = 'List'; +$lang->design->viewCommit = 'View Commit'; +$lang->design->linkCommit = 'Link Commit'; +$lang->design->unlinkCommit = 'Unlink Commit'; +$lang->design->submit = 'Submit Review'; +$lang->design->assignTo = 'Assign'; +$lang->design->revision = 'Linked Code'; + +/* 字段取值. */ +$lang->design->typeList = array(); +$lang->design->typeList[''] = ''; +$lang->design->typeList['HLDS'] = 'High-Level'; +$lang->design->typeList['DDS'] = 'Detailed'; +$lang->design->typeList['DBDS'] = 'Database'; +$lang->design->typeList['ADS'] = 'API'; + +$lang->design->rangeList = array(); +$lang->design->rangeList['all'] = 'All'; +$lang->design->rangeList['assign'] = 'Selected'; + +$lang->design->featureBar['all'] = 'All'; +$lang->design->featureBar += $lang->design->typeList; + +/* 提示信息. */ +$lang->design->errorSelection = 'No record selected!'; +$lang->design->noDesign = 'No record.'; +$lang->design->noCommit = 'No record commited.'; +$lang->design->confirmDelete = 'Do you want to delete this design?'; +$lang->design->confirmUnlink = 'Are you sure you want to remove this submission?'; +$lang->design->errorDate = 'The start date can not be greater than the end date.'; +$lang->design->deleted = 'Deleted'; diff --git a/module/design/lang/zh-cn.php b/module/design/lang/zh-cn.php new file mode 100644 index 0000000000..f98c52a288 --- /dev/null +++ b/module/design/lang/zh-cn.php @@ -0,0 +1,80 @@ + + * @package design + * @version $Id: zh-cn.php 4729 2020-09-01 07:53:55Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +/* 字段列表. */ +$lang->design->id = '编号'; +$lang->design->name = '设计名称'; +$lang->design->story = '需求'; +$lang->design->type = '设计类型'; +$lang->design->ditto = '同上'; +$lang->design->submission = '相关提交'; +$lang->design->version = '版本号'; +$lang->design->assignedTo = '指派给'; +$lang->design->actions = '操作'; +$lang->design->byQuery = '搜索'; +$lang->design->products = '所属产品'; +$lang->design->story = '相关需求'; +$lang->design->file = '附件'; +$lang->design->desc = '设计描述'; +$lang->design->range = '影响范围'; +$lang->design->product = '所属产品'; +$lang->design->basicInfo = '基础信息'; +$lang->design->commitBy = '由谁提交'; +$lang->design->commitDate = '提交时间'; +$lang->design->affectedStory = "影响{$lang->SRCommon}"; +$lang->design->affectedTasks = '影响任务'; +$lang->design->reviewObject = '评审对象'; +$lang->design->createdBy = '由谁创建'; +$lang->design->createdDate = '创建时间'; +$lang->design->basicInfo = '基本信息'; +$lang->design->noAssigned = '未指派'; +$lang->design->comment = '注释'; + +/* 动作列表. */ +$lang->design->common = '设计'; +$lang->design->create = '创建设计'; +$lang->design->batchCreate = '批量创建'; +$lang->design->edit = '变更'; +$lang->design->delete = '删除'; +$lang->design->view = '设计概况'; +$lang->design->browse = '浏览列表'; +$lang->design->viewCommit = '查看提交'; +$lang->design->linkCommit = '关联提交'; +$lang->design->unlinkCommit = '取消关联'; +$lang->design->submit = '提交评审'; +$lang->design->assignTo = '指派'; +$lang->design->revision = '查看关联代码'; + +$lang->design->browseAction = '设计列表'; + +/* 字段取值. */ +$lang->design->typeList = array(); +$lang->design->typeList[''] = ''; +$lang->design->typeList['HLDS'] = '概要设计'; +$lang->design->typeList['DDS'] = '详细设计'; +$lang->design->typeList['DBDS'] = '数据库设计'; +$lang->design->typeList['ADS'] = '接口设计'; + +$lang->design->rangeList = array(); +$lang->design->rangeList['all'] = '全部记录'; +$lang->design->rangeList['assign'] = '选中记录'; + +$lang->design->featureBar['all'] = '所有'; +$lang->design->featureBar += $lang->design->typeList; + +/* 提示信息. */ +$lang->design->errorSelection = '还没有选中记录!'; +$lang->design->noDesign = '暂时没有记录'; +$lang->design->noCommit = '暂时没有提交记录'; +$lang->design->confirmDelete = '您确定要删除这个设计吗?'; +$lang->design->confirmUnlink = '您确定要移除这个提交吗?'; +$lang->design->errorDate = '开始日期不能大于结束日期'; +$lang->design->deleted = '已删除'; diff --git a/module/design/lang/zh-tw.php b/module/design/lang/zh-tw.php new file mode 100644 index 0000000000..b5877740ed --- /dev/null +++ b/module/design/lang/zh-tw.php @@ -0,0 +1,78 @@ + + * @package design + * @version $Id: zh-tw.php 4729 2020-09-01 07:53:55Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +/* 欄位列表. */ +$lang->design->id = '編號'; +$lang->design->name = '設計名稱'; +$lang->design->story = '需求'; +$lang->design->type = '設計類型'; +$lang->design->ditto = '同上'; +$lang->design->submission = '相關提交'; +$lang->design->version = '版本號'; +$lang->design->assignedTo = '指派給'; +$lang->design->actions = '操作'; +$lang->design->byQuery = '搜索'; +$lang->design->products = '所屬產品'; +$lang->design->story = '相關需求'; +$lang->design->file = '附件'; +$lang->design->desc = '設計描述'; +$lang->design->range = '影響範圍'; +$lang->design->product = '所屬產品'; +$lang->design->basicInfo = '基礎信息'; +$lang->design->commitBy = '由誰提交'; +$lang->design->commitDate = '提交時間'; +$lang->design->affectedStory = "影響{$lang->SRCommon}"; +$lang->design->affectedTasks = '影響任務'; +$lang->design->reviewObject = '評審對象'; +$lang->design->createdBy = '由誰創建'; +$lang->design->createdDate = '創建時間'; +$lang->design->basicInfo = '基本信息'; +$lang->design->noAssigned = '未指派'; +$lang->design->comment = '註釋'; + +/* 動作列表. */ +$lang->design->common = '設計'; +$lang->design->create = '創建設計'; +$lang->design->batchCreate = '批量創建'; +$lang->design->edit = '變更'; +$lang->design->delete = '刪除'; +$lang->design->view = '設計概況'; +$lang->design->browse = '瀏覽列表'; +$lang->design->viewCommit = '查看提交'; +$lang->design->linkCommit = '關聯提交'; +$lang->design->unlinkCommit = '取消關聯'; +$lang->design->submit = '提交評審'; +$lang->design->assignTo = '指派'; +$lang->design->revision = '查看關聯代碼'; + +/* 欄位取值. */ +$lang->design->typeList = array(); +$lang->design->typeList[''] = ''; +$lang->design->typeList['HLDS'] = '概要設計'; +$lang->design->typeList['DDS'] = '詳細設計'; +$lang->design->typeList['DBDS'] = '資料庫設計'; +$lang->design->typeList['ADS'] = '介面設計'; + +$lang->design->rangeList = array(); +$lang->design->rangeList['all'] = '全部記錄'; +$lang->design->rangeList['assign'] = '選中記錄'; + +$lang->design->featureBar['all'] = '所有'; +$lang->design->featureBar += $lang->design->typeList; + +/* 提示信息. */ +$lang->design->errorSelection = '還沒有選中記錄!'; +$lang->design->noDesign = '暫時沒有記錄'; +$lang->design->noCommit = '暫時沒有提交記錄'; +$lang->design->confirmDelete = '您確定要刪除這個設計嗎?'; +$lang->design->confirmUnlink = '您確定要移除這個提交嗎?'; +$lang->design->errorDate = '開始日期不能大於結束日期'; +$lang->design->deleted = '已刪除'; diff --git a/module/design/model.php b/module/design/model.php new file mode 100644 index 0000000000..9f5b86efb7 --- /dev/null +++ b/module/design/model.php @@ -0,0 +1,465 @@ + + * @package design + * @version $Id: model.php 5107 2020-09-02 09:46:12Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> +stripTags('desc', $this->config->allowedTags) + ->add('createdBy', $this->app->user->account) + ->add('createdDate', helper::now()) + ->add('project', $projectID) + ->add('version', 1) + ->remove('files,labels') + ->get(); + + $design = $this->loadModel('file')->processImgURL($design, 'desc', $this->post->uid); + $this->dao->insert(TABLE_DESIGN)->data($design) + ->autoCheck() + ->batchCheck($this->config->design->create->requiredFields, 'notempty') + ->exec(); + + if(!dao::isError()) + { + $designID = $this->dao->lastInsertID(); + $this->file->updateObjectID($this->post->uid, $designID, 'design'); + $files = $this->file->saveUpload('design', $designID); + + $spec = new stdclass(); + $spec->design = $designID; + $spec->version = 1; + $spec->name = $design->name; + $spec->desc = $design->desc; + $spec->files = empty($files) ? '' : implode(',', array_keys($files)); + $this->dao->insert(TABLE_DESIGNSPEC)->data($spec)->exec(); + + return $designID; + } + + return false; + } + + /** + * Batch create designs. + * + * @param int $projectID + * @param int $productID + * @access public + * @return bool + */ + public function batchCreate($projectID = 0, $productID = 0) + { + $data = fixer::input('post')->get(); + + $this->loadModel('action'); + foreach($data->name as $i => $name) + { + if(!trim($name)) continue; + + $design = new stdclass(); + $design->story = isset($data->story[$i]) ? $data->story[$i] : ''; + $design->type = $data->type[$i]; + $design->name = $name; + $design->product = $productID; + $design->project = $projectID; + $design->createdBy = $this->app->user->account; + $design->createdDate = helper::now(); + + $this->dao->insert(TABLE_DESIGN)->data($design)->autoCheck()->batchCheck($this->config->design->create->requiredFields, 'notempty')->exec(); + + $designID = $this->dao->lastInsertID(); + $this->action->create('design', $designID, 'Opened'); + } + + return true; + } + + /** + * Update a design. + * + * @param int $designID + * @access public + * @return bool + */ + public function update($designID = 0) + { + $oldDesign = $this->getByID($designID); + $design = fixer::input('post') + ->add('editedBy', $this->app->user->account) + ->add('editedDate', helper::now()) + ->stripTags($this->config->design->editor->edit['id'], $this->config->allowedTags) + ->remove('file,files,labels,children,toList') + ->get(); + + $design = $this->loadModel('file')->processImgURL($design, 'desc', $this->post->uid); + $this->dao->update(TABLE_DESIGN)->data($design)->autoCheck()->batchCheck('name,type', 'notempty')->where('id')->eq($designID)->exec(); + + if(!dao::isError()) + { + $this->file->updateObjectID($this->post->uid, $designID, 'design'); + $files = $this->file->saveUpload('design', $designID); + $designChanged = ($oldDesign->name != $design->name || $oldDesign->desc != $design->desc || !empty($files)); + + if($designChanged) + { + $design = $this->getByID($designID); + $version = $design->version + 1; + $spec = new stdclass(); + $spec->design = $designID; + $spec->version = $version; + $spec->name = $design->name; + $spec->desc = $design->desc; + $spec->files = empty($files) ? '' : implode(',', array_keys($files)); + $this->dao->insert(TABLE_DESIGNSPEC)->data($spec)->exec(); + + $this->dao->update(TABLE_DESIGN)->set('version')->eq($version)->where('id')->eq($designID)->exec(); + } + + return common::createChanges($oldDesign, $design); + } + + return false; + } + + /** + * Assign a design. + * + * @param int $designID + * @access public + * @return array|bool + */ + public function assign($designID = 0) + { + $oldDesign = $this->getByID($designID); + + $design = fixer::input('post') + ->add('editedBy', $this->app->user->account) + ->add('editedDate', helper::today()) + ->setDefault('assignedDate', helper::today()) + ->stripTags($this->config->design->editor->assignto['id'], $this->config->allowedTags) + ->remove('uid,comment,files,label') + ->get(); + + $this->dao->update(TABLE_DESIGN)->data($design)->autoCheck()->where('id')->eq((int)$designID)->exec(); + + if(!dao::isError()) return common::createChanges($oldDesign, $design); + return false; + } + + /** + * LinkCommit a design. + * + * @param int $designID + * @param int $repoID + * @access public + * @return void + */ + public function linkCommit($designID = 0, $repoID = 0) + { + $revisions = $_POST['revision']; + + foreach($revisions as $revision) + { + $data = new stdclass(); + $data->project = $this->session->project; + $data->product = $this->session->product; + $data->AType = 'design'; + $data->AID = $designID; + $data->BType = 'commit'; + $data->BID = $revision; + $data->relation = 'completedin'; + $data->extra = $repoID; + + $this->dao->replace(TABLE_RELATION)->data($data)->autoCheck()->exec(); + + $data->AType = 'commit'; + $data->AID = $revision; + $data->BType = 'design'; + $data->BID = $designID; + $data->relation = 'completedfrom'; + + $this->dao->replace(TABLE_RELATION)->data($data)->autoCheck()->exec(); + } + + $oldCommit = $this->dao->findByID($designID)->from(TABLE_DESIGN)->fetch('commit'); + $revisions = join(',', $revisions); + $commit = $oldCommit ? $oldCommit . ',' . $revisions : $revisions; + + $design = new stdclass(); + $design->commit = $commit; + $design->commitedBy = $this->app->user->account; + $this->dao->update(TABLE_DESIGN)->data($design)->autoCheck()->where('id')->eq($designID)->exec(); + } + + /** + * Unlink commit. + * + * @param int $designID + * @param int $commitID + * @access public + * @return void + */ + public function unlinkCommit($designID = 0, $commitID = 0) + { + /* Delete data in the zt_relation.*/ + $this->dao->delete()->from(TABLE_RELATION)->where('AType')->eq('design')->andwhere('AID')->eq($designID)->andwhere('BType')->eq('commit')->andwhere('relation')->eq('completedin')->andWhere('BID')->eq($commitID)->exec(); + $this->dao->delete()->from(TABLE_RELATION)->where('AType')->eq('commit')->andwhere('BID')->eq($designID)->andwhere('BType')->eq('design')->andwhere('relation')->eq('completedfrom')->andWhere('AID')->eq($commitID)->exec(); + + /* Commit after unlinking. */ + $commit = $this->dao->select('BID')->from(TABLE_RELATION)->where('AType')->eq('design')->andWhere('AID')->eq($designID)->andWhere('BType')->eq('commit')->andwhere('relation')->eq('completedin')->fetchAll('BID'); + $commit = implode(",", array_keys($commit)); + + $this->dao->update(TABLE_DESIGN)->set('commit')->eq($commit)->where('id')->eq($designID)->exec(); + } + + /** + * Get a design by id. + * + * @param int $designID + * @access public + * @return object + */ + public function getByID($designID = 0) + { + $design = $this->dao->select('*')->from(TABLE_DESIGN)->where('id')->eq($designID)->fetch(); + if(!$design) return false; + + $design->files = $this->loadModel('file')->getByObject('design', $designID); + $design->productName = $this->dao->findByID($design->product)->from(TABLE_PRODUCT)->fetch('name'); + + + $design->commit = ''; + $relations = $this->loadModel('common')->getRelations('design', $designID, 'commit'); + foreach($relations as $relation) $design->commit .= html::a(helper::createLink('design', 'revision', "repoID=$relation->BID&projectID={$design->project}"), "#$relation->BID", '_blank'); + + return $this->loadModel('file')->replaceImgURL($design, 'desc'); + } + + /** + * Get design pairs. + * + * @param int $productID + * @param string $type all|HLDS|DDS|DBDS|ADS + * @access public + * @return object + */ + public function getPairs($productID = 0, $type = 'all') + { + $designs = $this->dao->select('id, name')->from(TABLE_DESIGN) + ->where('product')->eq($productID) + ->andWhere('deleted')->eq(0) + ->andWhere('type')->eq($type) + ->fetchPairs(); + foreach($designs as $id => $name) $designs[$id] = $id . ':' . $name; + + return $designs; + } + + /** + * Get affected scope. + * + * @param int $design + * @access public + * @return object + */ + public function getAffectedScope($design = 0) + { + /* Get affected tasks. */ + $design->tasks = $this->dao->select('*')->from(TABLE_TASK) + ->where('deleted')->eq(0) + ->andWhere('status')->ne('closed') + ->andWhere('design')->eq($design->id) + ->orderBy('id desc')->fetchAll(); + + return $design; + } + + /** + * Get design list. + * + * @param int $productID + * @param int $projectID + * @param string $type all|bySearch|HLDS|DDS|DBDS|ADS + * @param int $param + * @param string $orderBy + * @param int $pager + * @access public + * @return array + */ + public function getList($projectID = 0, $productID = 0, $type = 'all', $param = 0, $orderBy = 'id_desc', $pager = null) + { + if($type == 'bySearch') + { + $designs = $this->getBySearch($projectID, $productID, $param, $orderBy, $pager); + } + else + { + $designs = $this->dao->select('*')->from(TABLE_DESIGN) + ->where('deleted')->eq(0) + ->beginIF($projectID)->andWhere('project')->eq($projectID)->fi() + ->beginIF($type != 'all')->andWhere('type')->in($type)->fi() + ->andWhere('product')->eq($productID) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + } + + return $designs; + } + + /** + * Get commit. + * + * @param int $designID + * @param int $pager + * @access public + * @return object + */ + public function getCommit($designID = 0, $pager = null) + { + $design = $this->dao->select('*')->from(TABLE_DESIGN)->where('id')->eq($designID)->fetch(); + + $design->commit = $this->dao->select('*')->from(TABLE_REPOHISTORY)->where('id')->in($design->commit)->page($pager)->fetchAll('id'); + + return $design; + } + + /** + * Get designs by search. + * + * @param int $projectID + * @param int $productID + * @param int $queryID + * @param string $orderBy + * @param int $pager + * @access public + * @return object + */ + public function getBySearch($projectID = 0, $productID = 0, $queryID = 0, $orderBy = 'id_desc', $pager = null) + { + if($queryID) + { + $query = $this->loadModel('search')->getQuery($queryID); + if($query) + { + $this->session->set('designQuery', $query->sql); + $this->session->set('designForm', $query->form); + } + else + { + $this->session->set('designQuery', ' 1 = 1'); + } + } + else + { + if($this->session->designQuery == false) $this->session->set('designQuery', ' 1 = 1'); + } + + $designQuery = $this->session->designQuery; + + $designs = $this->dao->select('*')->from(TABLE_DESIGN) + ->where($designQuery) + ->andWhere('deleted')->eq('0') + ->andWhere('project')->eq($projectID) + ->andWhere('product')->eq($productID) + ->orderBy($orderBy) + ->page($pager) + ->fetchAll('id'); + + return $designs; + } + + /** + * Set design menu. + * + * @param int $projectID + * @param int $products + * @param int $productID + * @param string $currentModule + * @param string $currentMethod + * @param string $extra + * @param int $branch + * @access public + * @return void + */ + public function setMenu($projectID = 0, $products, $productID = 0) + { + if($this->app->rawMethod != 'browse') unset($this->lang->waterfall->menu->design['subMenu']->bysearch); + if(empty($products) || !$productID) return ''; + $currentProduct = $this->loadModel('product')->getById($productID); + setCookie("lastProduct", $productID, $this->config->cookieLife, $this->config->webRoot, '', false, true); + + $output = ''; + if(!empty($products)) + { + $dropMenuLink = helper::createLink('design', 'ajaxGetDropMenu', "projectID=$projectID&productID=$productID"); + $output = "
"; + } + + return $output; + } + + /** + * Build search form. + * + * @param int $queryID + * @param string $actionURL + * @access public + * @return void + */ + public function buildSearchForm($queryID = 0, $actionURL = '') + { + $this->config->design->search['actionURL'] = $actionURL; + $this->config->design->search['queryID'] = $queryID; + + $this->loadModel('search')->setSearchParams($this->config->design->search); + } + + /** + * Print assignedTo html. + * + * @param object $design + * @param array $users + * @access public + * @return string + */ + public function printAssignedHtml($design = '', $users = '') + { + $btnTextClass = ''; + $assignedToText = zget($users, $design->assignedTo); + + if(empty($design->assignedTo)) + { + $btnTextClass = 'text-primary'; + $assignedToText = $this->lang->design->noAssigned; + } + if($design->assignedTo == $this->app->user->account) $btnTextClass = 'text-red'; + + $btnClass = $design->assignedTo == 'closed' ? ' disabled' : ''; + $btnClass = "iframe btn btn-icon-left btn-sm {$btnClass}"; + $assignToLink = helper::createLink('design', 'assignTo', "designID=$design->id", '', true); + $assignToHtml = html::a($assignToLink, " {$assignedToText}", '', "class='$btnClass'"); + + echo !common::hasPriv('design', 'assignTo', $design) ? "{$assignedToText}" : $assignToHtml; + } +} diff --git a/module/design/view/ajaxgetdropmenu.html.php b/module/design/view/ajaxgetdropmenu.html.php new file mode 100644 index 0000000000..d2aaa4b0bd --- /dev/null +++ b/module/design/view/ajaxgetdropmenu.html.php @@ -0,0 +1,64 @@ + +status == 'normal' and $product->PO == $this->app->user->account) $iCharges++; + if($product->status == 'normal' and !($product->PO == $this->app->user->account)) $others++; + if($product->status == 'closed') $closeds++; + $productNames[] = $product->name; +} +$productsPinYin = common::convert2Pinyin($productNames); +$myProductsHtml = ''; +$normalProductsHtml = ''; +$closedProductsHtml = ''; + +foreach($products as $product) +{ + $selected = $product->id == $productID ? 'selected' : ''; + $productName = $product->name; + $linkHtml = sprintf($link, $product->id); + if($product->status == 'normal' and $product->PO == $this->app->user->account) + { + $myProductsHtml .= html::a($linkHtml, $productName, '', "class='text-important $selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='$tab'"); + } + else if($product->status == 'normal' and !($product->PO == $this->app->user->account)) + { + $normalProductsHtml .= html::a($linkHtml, $productName, '', "class='$selected' title='{$productName}' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='$tab'"); + } + else if($product->status == 'closed') + { + $closedProductsHtml .= html::a($linkHtml, $productName, '', "class='$selected' title='{$productName}' class='closed' data-key='" . zget($productsPinYin, $product->name, '') . "' data-app='$tab'"); + } +} +?> +
+
+
+ {$lang->product->mine}
"; + echo $myProductsHtml; + if(!empty($myProductsHtml)) + { + echo "
{$lang->product->other}
"; + } + } + echo $normalProductsHtml; + ?> +
+ +
+
+
+
+
+ diff --git a/module/design/view/assignto.html.php b/module/design/view/assignto.html.php new file mode 100644 index 0000000000..aa68967212 --- /dev/null +++ b/module/design/view/assignto.html.php @@ -0,0 +1,40 @@ + + * @package design + * @version $Id: assignto.html.php 4903 2020-09-02 09:32:59Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + + +
+
+

+ id;?> + name'>" . $design->name . '';?> +

+
+
+ + + + + + + + + + + + + + +
design->assignedTo;?>assignedTo, "class='form-control chosen'");?>
comment;?>
+
+
+ diff --git a/module/design/view/batchcreate.html.php b/module/design/view/batchcreate.html.php new file mode 100644 index 0000000000..51c027d4eb --- /dev/null +++ b/module/design/view/batchcreate.html.php @@ -0,0 +1,45 @@ + + * @package design + * @version $Id: batchcreate.html.php 4903 2020-09-02 09:32:59Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + + +
+

design->batchCreate;?>

+
+ + + + + + + + + + + + + + + + + + + + + + +
design->id;?>design->story;?>design->type;?>design->name;?>
design->typeList, '', "class='form-control chosen'");?>
+ +
+
+
+ diff --git a/module/design/view/browse.html.php b/module/design/view/browse.html.php new file mode 100644 index 0000000000..5fb8fc535d --- /dev/null +++ b/module/design/view/browse.html.php @@ -0,0 +1,69 @@ + + * @package design + * @version $Id: browse.html.php 5102 2020-09-03 10:59:54Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + + + + +
+
+ +
+

design->noDesign;?>

+
+ +
+ + recTotal}&recPerPage={$pager->recPerPage}";?> + + + + + + + + + + + + + + + + + + + + + + + + +
design->id);?> design->type);?> design->name);?> design->createdBy);?> design->createdDate);?>design->assignedTo);?> design->actions;?>
id);?> design->typeList, $design->type);?>createLink('design', 'view', "id={$design->id}"), $design->name);?> createdBy);?>createdDate, 0, 11);?> design->printAssignedHtml($design, $users);?> + id}"; + common::printIcon('design', 'edit', $vars, $design, 'list', 'alter', '', '', '', '', '', $design->project); + common::printIcon('design', 'viewCommit', $vars, $design, 'list', 'list-alt', '', 'iframe showinonlybody', true); + common::printIcon('design', 'delete', $vars, $design, 'list', 'trash', 'hiddenwin', '', '', '', '', $design->project); + ?> +
+ +
+ +
+ diff --git a/module/design/view/create.html.php b/module/design/view/create.html.php new file mode 100644 index 0000000000..4a0be47622 --- /dev/null +++ b/module/design/view/create.html.php @@ -0,0 +1,60 @@ + + * @package design + * @version $Id: create.html.php 4903 2020-09-02 09:32:59Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + + + +
+
+
+

design->create;?>

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
design->product;?>
design->story;?>
design->type;?>design->typeList, '', "class='form-control chosen'");?>
design->name;?>
design->desc;?>
design->file;?>fetch('file', 'buildform', 'fileCount=1&percent=0.85');?>
+
+
+
+ diff --git a/module/design/view/edit.html.php b/module/design/view/edit.html.php new file mode 100644 index 0000000000..06afd43ef0 --- /dev/null +++ b/module/design/view/edit.html.php @@ -0,0 +1,98 @@ + + * @package design + * @version $Id: edit.html.php 4903 2020-09-02 09:32:59Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + + +type);?> +
+
+
+

design->edit;?>

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
design->product;?>product, "class='form-control chosen'");?>
design->story;?>story, "class='form-control chosen'");?>
design->type;?>design->typeList, $design->type, "class='form-control chosen'");?>
design->name;?>name, "class='form-control'");?>
design->desc;?>desc, 'class="form-control"');?>
design->file;?>fetch('file', 'buildform', 'fileCount=1&percent=0.85');?>
story->checkAffection;?> +
+ +
+
+ + + + + + + + + + + + + tasks as $task):?> + + + ; + + + + + + + +
task->id;?> task->name;?> task->assignedTo;?>task->status;?> task->consumed;?> task->left;?>
id?>createLink('task', 'view', "taskID=$task->id"), $task->name, '_blank');?>assignedTo);?>processStatus('task', $task);?>consumed;?>left;?>
+
+
+
+
+
+
+
+ diff --git a/module/design/view/linkcommit.html.php b/module/design/view/linkcommit.html.php new file mode 100644 index 0000000000..540e59b1f8 --- /dev/null +++ b/module/design/view/linkcommit.html.php @@ -0,0 +1,88 @@ + + * @package design + * @version $Id: linkcommit.html.php 4903 2020-09-02 09:32:59Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + +
+
+

+ id;?> + name?> + arrow . $lang->design->linkCommit;?> +

+
+ +
+

design->noCommit;?>

+
+ + +
method='post'> + + + + + + SCM) and $repo->SCM == 'Git'):?> + + + + + + + + + + + + + SCM == 'Git'):?> + + + + + comment, ENT_QUOTES);?> + + + + +
repo->revisionA?>repo->commit?>repo->time?>repo->committer?>repo->comment?>
+
+ + +
+
repo->createLink('revision', "repoID=$repoID&revision={$log->revision}"), $repo->SCM == 'Git' ? substr($log->revision, 0, 10) : $log->revision);?>commit?>time, 0, 10);?>committer, $log->committer);?>comment?>
+ +
+ +
+ +design->errorDate);?> + diff --git a/module/design/view/view.html.php b/module/design/view/view.html.php new file mode 100644 index 0000000000..e7b71d3a08 --- /dev/null +++ b/module/design/view/view.html.php @@ -0,0 +1,92 @@ + + * @package design + * @version $Id: view.html.php 4903 2020-09-02 09:32:59Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + +type);?> + +
+
+
+
+
design->desc;?>
+
+ desc;?> +
+
+ fetch('file', 'printFiles', array('files' => $design->files, 'fieldset' => 'true'));?> +
+
+
+
+ session->designList);?> +
";?> + deleted):?> + id", $design, 'button', '', '', 'iframe showinonlybody', true); + common::printIcon('design', 'linkCommit', "designID=$design->id", $design, 'button', 'link', '', 'iframe showinonlybody', true); + common::printIcon('design', 'edit', "designID=$design->id", $design, 'button', 'alter'); + common::printIcon('design', 'delete', "designID=$design->id", $design, 'button', 'trash', 'hiddenwin'); + ?> + +
+
+
+
+
+
+
design->basicInfo;?>
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
design->type;?>design->typeList, $design->type);?>
design->product;?>productName;?>
design->story;?>story ? html::a($this->createLink('story', 'view', "id=$design->story"), zget($stories, $design->story)) : '';?>
design->submission;?>commit;?>
design->createdBy;?>createdBy);?>
design->createdDate;?>createdDate, 0, 11);?>
+
+
+
+
+
+ diff --git a/module/design/view/viewcommit.html.php b/module/design/view/viewcommit.html.php new file mode 100644 index 0000000000..883dcd88b5 --- /dev/null +++ b/module/design/view/viewcommit.html.php @@ -0,0 +1,63 @@ + + * @package design + * @version $Id: viewcommit.html.php 4903 2020-09-02 09:32:59Z tianshujie@easycorp.ltd $ + * @link http://www.zentao.net + */ +?> + + +
+
+

+ id;?> + name?> + arrow . $lang->design->submission;?> +

+
+
+ id", "" . $lang->design->linkCommit, '_blank', "class='btn btn-primary'");?> +
+ commit)):?> +
+

design->noCommit;?>

+
+ + + + + + + + + + + + + commit as $commit):?> + + + + + + + + + +
design->submission;?>design->commitBy;?>design->commitDate;?>design->comment;?> design->actions;?>
id"), "#$commit->id", '_blank');?>committer, $commit->committer);?>time, 0, 11);?>comment;?> + id&commitID=$commit->id", $design, 'list', 'unlink', 'hiddenwin', 'iframe showinonlybody', true);?> +
+ + +
+ diff --git a/module/doc/css/common.css b/module/doc/css/common.css index 6e3ba241d8..0e737a7fca 100644 --- a/module/doc/css/common.css +++ b/module/doc/css/common.css @@ -96,3 +96,5 @@ ol, ul {margin-bottom: 0} .c-product, .c-execution, .c-lib {width: 80px !important;} .header-btn .btn > .text {text-overflow: unset !important;} + +.tree li.active > .tree-group a {font-weight: 700; color: #0c64eb;} diff --git a/module/group/lang/resource.php b/module/group/lang/resource.php index 59273efd0c..05027ab43e 100644 --- a/module/group/lang/resource.php +++ b/module/group/lang/resource.php @@ -26,8 +26,10 @@ $lang->moduleOrder[45] = 'project'; $lang->moduleOrder[50] = 'projectstory'; $lang->moduleOrder[55] = 'execution'; $lang->moduleOrder[56] = 'kanban'; +$lang->moduleOrder[57] = 'programplan'; $lang->moduleOrder[60] = 'task'; $lang->moduleOrder[65] = 'build'; +$lang->moduleOrder[66] = 'design'; $lang->moduleOrder[70] = 'qa'; $lang->moduleOrder[75] = 'bug'; @@ -47,6 +49,7 @@ $lang->moduleOrder[130] = 'group'; $lang->moduleOrder[135] = 'user'; $lang->moduleOrder[140] = 'admin'; +$lang->moduleOrder[142] = 'stage'; $lang->moduleOrder[145] = 'extension'; $lang->moduleOrder[150] = 'custom'; $lang->moduleOrder[155] = 'action'; @@ -161,6 +164,32 @@ if($config->systemMode == 'new') { $lang->resource->my->project = 'project'; + /* Design. */ + $lang->resource->design = new stdclass(); + $lang->resource->design->browse = 'browse'; + $lang->resource->design->view = 'view'; + $lang->resource->design->create = 'create'; + $lang->resource->design->batchCreate = 'batchCreate'; + $lang->resource->design->edit = 'edit'; + $lang->resource->design->assignTo = 'assignTo'; + $lang->resource->design->delete = 'delete'; + $lang->resource->design->linkCommit = 'linkCommit'; + $lang->resource->design->viewCommit = 'viewCommit'; + $lang->resource->design->unlinkCommit = 'unlinkCommit'; + $lang->resource->design->revision = 'revision'; + + $lang->design->methodOrder[5] = 'browse'; + $lang->design->methodOrder[10] = 'view'; + $lang->design->methodOrder[15] = 'create'; + $lang->design->methodOrder[20] = 'batchCreate'; + $lang->design->methodOrder[25] = 'edit'; + $lang->design->methodOrder[30] = 'assignTo'; + $lang->design->methodOrder[35] = 'delete'; + $lang->design->methodOrder[40] = 'linkCommit'; + $lang->design->methodOrder[45] = 'viewCommit'; + $lang->design->methodOrder[50] = 'unlinkCommit'; + $lang->design->methodOrder[55] = 'revision'; + /* Program. */ $lang->resource->program = new stdclass(); $lang->resource->program->browse = 'browse'; @@ -204,6 +233,16 @@ if($config->systemMode == 'new') $lang->program->methodOrder[95] = 'export'; $lang->program->methodOrder[100] = 'updateOrder'; + /* Program plan. */ + $lang->resource->programplan = new stdclass(); + $lang->resource->programplan->browse = 'browse'; + $lang->resource->programplan->create = 'create'; + $lang->resource->programplan->edit = 'edit'; + + $lang->programplan->methodOrder[5] = 'browse'; + $lang->programplan->methodOrder[10] = 'create'; + $lang->programplan->methodOrder[15] = 'edit'; + /* Project. */ $lang->resource->project = new stdclass(); $lang->resource->project->index = 'index'; @@ -336,6 +375,22 @@ if($config->systemMode == 'new') $lang->projectrelease->methodOrder[65] = 'batchUnlinkBug'; $lang->projectrelease->methodOrder[70] = 'changeStatus'; + /* Stage. */ + $lang->resource->stage = new stdclass(); + $lang->resource->stage->browse = 'browse'; + $lang->resource->stage->create = 'create'; + $lang->resource->stage->batchCreate = 'batchCreate'; + $lang->resource->stage->edit = 'edit'; + $lang->resource->stage->setType = 'setType'; + $lang->resource->stage->delete = 'delete'; + + $lang->stage->methodOrder[5] = 'browse'; + $lang->stage->methodOrder[10] = 'create'; + $lang->stage->methodOrder[15] = 'batchCreate'; + $lang->stage->methodOrder[20] = 'edit'; + $lang->stage->methodOrder[25] = 'setType'; + $lang->stage->methodOrder[30] = 'delete'; + /* Stakeholer. */ $lang->resource->stakeholder = new stdclass(); $lang->resource->stakeholder->browse = 'browse'; diff --git a/module/programplan/config.php b/module/programplan/config.php new file mode 100644 index 0000000000..2710d95c98 --- /dev/null +++ b/module/programplan/config.php @@ -0,0 +1,54 @@ +programplan->create = new stdclass(); +$config->programplan->edit = new stdclass(); +$config->programplan->create->requiredFields = 'name,begin,end'; +$config->programplan->edit->requiredFields = 'name,begin,end'; + +$config->programplan->datatable = new stdclass(); +$config->programplan->datatable->defaultField = array('id', 'name', 'percent', 'attribute', 'begin', 'end', 'realBegan', 'realEnd', 'actions'); + +$config->programplan->datatable->fieldList['id']['title'] = 'idAB'; +$config->programplan->datatable->fieldList['id']['fixed'] = 'left'; +$config->programplan->datatable->fieldList['id']['width'] = '70'; +$config->programplan->datatable->fieldList['id']['required'] = 'yes'; + +$config->programplan->datatable->fieldList['name']['title'] = 'name'; +$config->programplan->datatable->fieldList['name']['fixed'] = 'left'; +$config->programplan->datatable->fieldList['name']['width'] = 'auto'; +$config->programplan->datatable->fieldList['name']['required'] = 'yes'; + +$config->programplan->datatable->fieldList['percent']['title'] = 'percent'; +$config->programplan->datatable->fieldList['percent']['fixed'] = 'no'; +$config->programplan->datatable->fieldList['percent']['width'] = '100'; +$config->programplan->datatable->fieldList['percent']['required'] = 'no'; + +$config->programplan->datatable->fieldList['attribute']['title'] = 'attribute'; +$config->programplan->datatable->fieldList['attribute']['fixed'] = 'no'; +$config->programplan->datatable->fieldList['attribute']['width'] = '90'; +$config->programplan->datatable->fieldList['attribute']['required'] = 'no'; + +$config->programplan->datatable->fieldList['begin']['title'] = 'begin'; +$config->programplan->datatable->fieldList['begin']['fixed'] = 'no'; +$config->programplan->datatable->fieldList['begin']['width'] = '90'; +$config->programplan->datatable->fieldList['begin']['required'] = 'no'; + +$config->programplan->datatable->fieldList['end']['title'] = 'end'; +$config->programplan->datatable->fieldList['end']['fixed'] = 'no'; +$config->programplan->datatable->fieldList['end']['width'] = '90'; +$config->programplan->datatable->fieldList['end']['required'] = 'no'; + +$config->programplan->datatable->fieldList['realBegan']['title'] = 'realBegan'; +$config->programplan->datatable->fieldList['realBegan']['fixed'] = 'no'; +$config->programplan->datatable->fieldList['realBegan']['width'] = '90'; +$config->programplan->datatable->fieldList['realBegan']['required'] = 'no'; + +$config->programplan->datatable->fieldList['realEnd']['title'] = 'realEnd'; +$config->programplan->datatable->fieldList['realEnd']['fixed'] = 'no'; +$config->programplan->datatable->fieldList['realEnd']['width'] = '90'; +$config->programplan->datatable->fieldList['realEnd']['required'] = 'no'; + +$config->programplan->datatable->fieldList['actions']['title'] = 'actions'; +$config->programplan->datatable->fieldList['actions']['fixed'] = 'right'; +$config->programplan->datatable->fieldList['actions']['width'] = '150'; +$config->programplan->datatable->fieldList['actions']['required'] = 'yes'; +$config->programplan->datatable->fieldList['actions']['sort'] = 'no'; diff --git a/module/programplan/control.php b/module/programplan/control.php new file mode 100644 index 0000000000..f261191566 --- /dev/null +++ b/module/programplan/control.php @@ -0,0 +1,201 @@ + + * @package programplan + * @version $Id: control.php 5107 2013-07-12 01:46:12Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +class programplan extends control +{ + /** + * __construct + * + * @param string $moduleName + * @param string $methodName + * @access public + * @return void + */ + public function __construct($moduleName = '', $methodName = '') + { + parent::__construct($moduleName, $methodName); + } + + /** + * Common action. + * + * @param int $projectID + * @param int $productID + * @param string $extra + * @access public + * @return void + */ + public function commonAction($projectID, $productID = 0, $extra = '') + { + $products = $this->loadModel('product')->getProductPairsByProject($projectID); + $productID = $this->product->saveState($productID, $products); + + $this->productID = $productID; + $this->loadModel('project')->setMenu($projectID); + } + + /** + * Browse program plans. + * + * @param int $projectID + * @param int $productID + * @param string $type + * @param string $orderBy + * @param int $baselineID + * @access public + * @return void + */ + public function browse($projectID = 0, $productID = 0, $type = 'gantt', $orderBy = 'id_asc', $baselineID = 0) + { + $this->app->loadLang('stage'); + $this->commonAction($projectID, $productID, $type); + $this->session->set('projectPlanList', $this->app->getURI(true), 'project'); + + if(!defined('RUN_MODE') || RUN_MODE != 'api') $projectID = $this->project->saveState((int)$projectID, $this->project->getPairsByProgram()); + + $products = $this->project->getProducts($projectID); + $this->lang->modulePageNav = $this->product->select($products, $this->productID, 'programplan', 'browse', $type, 0, 0, '', false); + + if(common::hasPriv('programplan', 'create')) $this->lang->TRActions = html::a($this->createLink('programplan', 'create', "projectID=$projectID"), " " . $this->lang->programplan->create, '', "class='btn btn-primary'"); + + $selectCustom = 0; // Display date and task settings. + $dateDetails = 1; // Gantt chart detail date display. + if($type == 'gantt') + { + $owner = $this->app->user->account; + $module = 'programplan'; + $section = 'browse'; + $object = 'stageCustom'; + $selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}§ion={$section}&key={$object}"); + if(strpos($selectCustom, 'date') !== false) $dateDetails = 0; + + $plans = $this->programplan->getDataForGantt($projectID, $this->productID, $baselineID); + } + + if($type == 'lists') + { + $sort = $this->loadModel('common')->appendOrder($orderBy); + $this->loadModel('datatable'); + $plans = $this->programplan->getPlans($projectID, $this->productID, $sort); + } + + $this->view->title = $this->lang->programplan->browse; + $this->view->position[] = $this->lang->programplan->browse; + $this->view->projectID = $projectID; + $this->view->productID = $this->productID; + $this->view->type = $type; + $this->view->plans = $plans; + $this->view->orderBy = $orderBy; + $this->view->selectCustom = $selectCustom; + $this->view->dateDetails = $dateDetails; + $this->view->users = $this->loadModel('user')->getPairs('noletter'); + + $this->display(); + } + + /** + * Create a project plan. + * + * @param int $projectID + * @param int $productID + * @param int $planID + * @access public + * @return void + */ + public function create($projectID = 0, $productID = 0, $planID = 0) + { + $this->commonAction($projectID, $productID); + $this->app->loadLang('project'); + if($_POST) + { + $this->programplan->create($projectID, $this->productID, $planID); + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + + $locate = $this->session->projectPlanList ? $this->session->projectPlanList : $this->createLink('programplan', 'browse', "projectID=$projectID"); + return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locate)); + } + + $this->app->loadLang('stage'); + $project = $this->loadModel('project')->getById($projectID); + + $this->view->title = $this->lang->programplan->create . $this->lang->colon . $project->name; + $this->view->position[] = html::a($this->createLink('programplan', 'browse', "projectID=$projectID"), $project->name); + $this->view->position[] = $this->lang->programplan->create; + + $this->view->project = $project; + $this->view->stages = empty($planID) ? $this->loadModel('stage')->getStages('id_asc') : array(); + $this->view->programPlan = $this->project->getById($planID, 'stage'); + $this->view->plans = $this->programplan->getStage($planID ? $planID : $projectID, $this->productID, 'parent'); + $this->view->planID = $planID; + $this->view->type = 'lists'; + + $this->display(); + } + + /** + * Edit a project plan. + * + * @param int $planID + * @param int $projectID + * @access public + * @return void + */ + public function edit($planID = 0, $projectID = 0) + { + $this->app->loadLang('project'); + $plan = $this->programplan->getByID($planID); + if($_POST) + { + $changes = $this->programplan->update($planID, $projectID); + + if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); + if($changes) + { + $actionID = $this->loadModel('action')->create('execution', $planID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + $locate = isonlybody() ? 'parent' : inlink('browse', "program=$plan->program&type=lists"); + return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locate)); + } + + $this->app->loadLang('stage'); + $this->view->title = $this->lang->programplan->edit; + $this->view->position[] = $this->lang->programplan->edit; + $this->view->parentStage = $this->programplan->getParentStageList($this->session->project, $planID, $plan->product); + $this->view->isCreateTask = $this->programplan->isCreateTask($planID); + $this->view->plan = $plan; + + $this->display(); + } + + /** + * Save custom settings via ajax. + * + * @access public + * @return void + */ + public function ajaxCustom() + { + $data = fixer::input('post')->get(); + $owner = $this->app->user->account; + $module = 'programplan'; + $section = 'browse'; + $object = 'stageCustom'; + $setting = $this->loadModel('setting'); + $custom = empty($data->stageCustom) ? '' : implode(',', $data->stageCustom); + $setting->setItem("$owner.$module.$section.$object", $custom); + + $response = array(); + $response['result'] = 'success'; + $response['message'] = ''; + return $this->send($response); + } +} diff --git a/module/programplan/js/browse.js b/module/programplan/js/browse.js new file mode 100644 index 0000000000..480420dc76 --- /dev/null +++ b/module/programplan/js/browse.js @@ -0,0 +1,34 @@ +$(function() +{ + setTimeout(function() + { + fixScroll(); + }, 500); +}) + +function fixScroll() +{ + var $scrollwrapper = $('div.datatable').first().find('.scroll-wrapper:first'); + if($scrollwrapper.size() == 0)return; + + var $tfoot = $('div.datatable').first().find('table tfoot:last'); + var scrollOffset = $scrollwrapper.offset().top + $scrollwrapper.find('.scroll-slide').height(); + if($tfoot.size() > 0) scrollOffset += $tfoot.height(); + if($('div.datatable.head-fixed').size() == 0) scrollOffset -= '29'; + var windowH = $(window).height(); + if(scrollOffset > windowH + $(window).scrollTop()) $scrollwrapper.css({'position': 'fixed', 'bottom': 50 + 'px'}); + $(window).scroll(function() + { + newBottom = $tfoot.hasClass('fixedTfootAction') ? 50 + $tfoot.height() : 50; + if(typeof(ssoRedirect) != "undefined") newBottom = 50; + if(scrollOffset <= windowH + $(window).scrollTop()) + { + $scrollwrapper.css({'position':'relative', 'bottom': '0px'}); + } + else if($scrollwrapper.css('position') != 'fixed') + { + $scrollwrapper.css({'position': 'fixed', 'bottom': newBottom + 'px'}); + bottom = newBottom; + } + }); +} diff --git a/module/programplan/js/create.js b/module/programplan/js/create.js new file mode 100644 index 0000000000..62a08dbd0e --- /dev/null +++ b/module/programplan/js/create.js @@ -0,0 +1,16 @@ +function addItem(obj) +{ + var item = $('#addItem').html().replace(/%i%/g, i); + $(obj).closest('tr').after('' + item + ''); + var newItem = $('#names' + i).closest('tr'); + newItem.find('.form-date').datepicker(); + $("#output" + i).chosen(); + $("#output_i__chosen").remove(); + i ++; +} + +function deleteItem(obj) +{ + if($('#planForm .table tbody').children().length < 2) return false; + $(obj).closest('tr').remove(); +} diff --git a/module/programplan/lang/de.php b/module/programplan/lang/de.php new file mode 100644 index 0000000000..37a10b3e13 --- /dev/null +++ b/module/programplan/lang/de.php @@ -0,0 +1,73 @@ + + * @package programplan + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +$lang->programplan->common = 'Program Plan'; +$lang->programplan->browse = 'Program Plan'; +$lang->programplan->gantt = 'Gantt Chart'; +$lang->programplan->list = 'Stage List'; +$lang->programplan->create = 'Create'; +$lang->programplan->edit = 'Edit'; +$lang->programplan->delete = 'Delete Stage'; +$lang->programplan->createSubPlan = 'Create Sub Plan'; + +$lang->programplan->parent = 'Parent Stage'; +$lang->programplan->emptyParent = 'N/A'; +$lang->programplan->name = 'Stage Name'; +$lang->programplan->subStageName = 'Sub Stage Name'; +$lang->programplan->percent = 'Workload Ratio'; +$lang->programplan->percentAB = 'Workload Ratio'; +$lang->programplan->planPercent = 'Workload'; +$lang->programplan->attribute = 'Stage Type'; +$lang->programplan->milestone = 'Milestone'; +$lang->programplan->taskProgress = 'Task Progress'; +$lang->programplan->task = 'Task'; +$lang->programplan->begin = 'Begin'; +$lang->programplan->end = 'End'; +$lang->programplan->realBegan = 'Actual Started'; +$lang->programplan->realEnd = 'Actual End'; +$lang->programplan->ac = 'Actual cost'; +$lang->programplan->sv = 'Schedule Variance'; +$lang->programplan->cv = 'Cost Variance'; +$lang->programplan->planDateRange = 'Planned Start'; +$lang->programplan->realDateRange = 'Actual Start'; +$lang->programplan->output = 'Output'; +$lang->programplan->openedBy = 'Created By'; +$lang->programplan->openedDate = 'Created Date'; +$lang->programplan->editedBy = 'Edited By'; +$lang->programplan->editedDate = 'Edited Date'; +$lang->programplan->duration = 'Duration'; +$lang->programplan->version = 'Version'; +$lang->programplan->full = 'Full Screen'; +$lang->programplan->today = 'Today'; +$lang->programplan->exporting = 'Exporting'; +$lang->programplan->exportFail = 'Export failed'; +$lang->programplan->hideCriticalPath = 'Hide Critical Path'; +$lang->programplan->showCriticalPath = 'Show Critical Path'; + +$lang->programplan->milestoneList[1] = 'Yes'; +$lang->programplan->milestoneList[0] = 'No'; + +$lang->programplan->noData = 'No Data'; +$lang->programplan->children = 'Sub Plan'; +$lang->programplan->childrenAB = 'Child'; +$lang->programplan->confirmDelete = 'Do you want to delete the current plan?'; +$lang->programplan->workloadTips = 'The proportion of the sub stage workload is divided by 100%.'; + +$lang->programplan->stageCustom = new stdClass(); +$lang->programplan->stageCustom->date = 'Show Date'; +$lang->programplan->stageCustom->task = 'Show Task'; + +$lang->programplan->error = new stdclass(); +$lang->programplan->error->percentNumber = '"Workload %" must be digits.'; +$lang->programplan->error->planFinishSmall = 'The "End" date must be > the "Begin" date.'; +$lang->programplan->error->percentOver = 'The sum of "Workload %" cannot exceed 100%.'; +$lang->programplan->error->createdTask = 'The task has been decomposed. Sub phases cannot be added.'; +$lang->programplan->error->parentWorkload = 'The sum of the workload of the child phase cannot be greater than that of the parent phase: %s.'; diff --git a/module/programplan/lang/en.php b/module/programplan/lang/en.php new file mode 100644 index 0000000000..37a10b3e13 --- /dev/null +++ b/module/programplan/lang/en.php @@ -0,0 +1,73 @@ + + * @package programplan + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +$lang->programplan->common = 'Program Plan'; +$lang->programplan->browse = 'Program Plan'; +$lang->programplan->gantt = 'Gantt Chart'; +$lang->programplan->list = 'Stage List'; +$lang->programplan->create = 'Create'; +$lang->programplan->edit = 'Edit'; +$lang->programplan->delete = 'Delete Stage'; +$lang->programplan->createSubPlan = 'Create Sub Plan'; + +$lang->programplan->parent = 'Parent Stage'; +$lang->programplan->emptyParent = 'N/A'; +$lang->programplan->name = 'Stage Name'; +$lang->programplan->subStageName = 'Sub Stage Name'; +$lang->programplan->percent = 'Workload Ratio'; +$lang->programplan->percentAB = 'Workload Ratio'; +$lang->programplan->planPercent = 'Workload'; +$lang->programplan->attribute = 'Stage Type'; +$lang->programplan->milestone = 'Milestone'; +$lang->programplan->taskProgress = 'Task Progress'; +$lang->programplan->task = 'Task'; +$lang->programplan->begin = 'Begin'; +$lang->programplan->end = 'End'; +$lang->programplan->realBegan = 'Actual Started'; +$lang->programplan->realEnd = 'Actual End'; +$lang->programplan->ac = 'Actual cost'; +$lang->programplan->sv = 'Schedule Variance'; +$lang->programplan->cv = 'Cost Variance'; +$lang->programplan->planDateRange = 'Planned Start'; +$lang->programplan->realDateRange = 'Actual Start'; +$lang->programplan->output = 'Output'; +$lang->programplan->openedBy = 'Created By'; +$lang->programplan->openedDate = 'Created Date'; +$lang->programplan->editedBy = 'Edited By'; +$lang->programplan->editedDate = 'Edited Date'; +$lang->programplan->duration = 'Duration'; +$lang->programplan->version = 'Version'; +$lang->programplan->full = 'Full Screen'; +$lang->programplan->today = 'Today'; +$lang->programplan->exporting = 'Exporting'; +$lang->programplan->exportFail = 'Export failed'; +$lang->programplan->hideCriticalPath = 'Hide Critical Path'; +$lang->programplan->showCriticalPath = 'Show Critical Path'; + +$lang->programplan->milestoneList[1] = 'Yes'; +$lang->programplan->milestoneList[0] = 'No'; + +$lang->programplan->noData = 'No Data'; +$lang->programplan->children = 'Sub Plan'; +$lang->programplan->childrenAB = 'Child'; +$lang->programplan->confirmDelete = 'Do you want to delete the current plan?'; +$lang->programplan->workloadTips = 'The proportion of the sub stage workload is divided by 100%.'; + +$lang->programplan->stageCustom = new stdClass(); +$lang->programplan->stageCustom->date = 'Show Date'; +$lang->programplan->stageCustom->task = 'Show Task'; + +$lang->programplan->error = new stdclass(); +$lang->programplan->error->percentNumber = '"Workload %" must be digits.'; +$lang->programplan->error->planFinishSmall = 'The "End" date must be > the "Begin" date.'; +$lang->programplan->error->percentOver = 'The sum of "Workload %" cannot exceed 100%.'; +$lang->programplan->error->createdTask = 'The task has been decomposed. Sub phases cannot be added.'; +$lang->programplan->error->parentWorkload = 'The sum of the workload of the child phase cannot be greater than that of the parent phase: %s.'; diff --git a/module/programplan/lang/fr.php b/module/programplan/lang/fr.php new file mode 100644 index 0000000000..37a10b3e13 --- /dev/null +++ b/module/programplan/lang/fr.php @@ -0,0 +1,73 @@ + + * @package programplan + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +$lang->programplan->common = 'Program Plan'; +$lang->programplan->browse = 'Program Plan'; +$lang->programplan->gantt = 'Gantt Chart'; +$lang->programplan->list = 'Stage List'; +$lang->programplan->create = 'Create'; +$lang->programplan->edit = 'Edit'; +$lang->programplan->delete = 'Delete Stage'; +$lang->programplan->createSubPlan = 'Create Sub Plan'; + +$lang->programplan->parent = 'Parent Stage'; +$lang->programplan->emptyParent = 'N/A'; +$lang->programplan->name = 'Stage Name'; +$lang->programplan->subStageName = 'Sub Stage Name'; +$lang->programplan->percent = 'Workload Ratio'; +$lang->programplan->percentAB = 'Workload Ratio'; +$lang->programplan->planPercent = 'Workload'; +$lang->programplan->attribute = 'Stage Type'; +$lang->programplan->milestone = 'Milestone'; +$lang->programplan->taskProgress = 'Task Progress'; +$lang->programplan->task = 'Task'; +$lang->programplan->begin = 'Begin'; +$lang->programplan->end = 'End'; +$lang->programplan->realBegan = 'Actual Started'; +$lang->programplan->realEnd = 'Actual End'; +$lang->programplan->ac = 'Actual cost'; +$lang->programplan->sv = 'Schedule Variance'; +$lang->programplan->cv = 'Cost Variance'; +$lang->programplan->planDateRange = 'Planned Start'; +$lang->programplan->realDateRange = 'Actual Start'; +$lang->programplan->output = 'Output'; +$lang->programplan->openedBy = 'Created By'; +$lang->programplan->openedDate = 'Created Date'; +$lang->programplan->editedBy = 'Edited By'; +$lang->programplan->editedDate = 'Edited Date'; +$lang->programplan->duration = 'Duration'; +$lang->programplan->version = 'Version'; +$lang->programplan->full = 'Full Screen'; +$lang->programplan->today = 'Today'; +$lang->programplan->exporting = 'Exporting'; +$lang->programplan->exportFail = 'Export failed'; +$lang->programplan->hideCriticalPath = 'Hide Critical Path'; +$lang->programplan->showCriticalPath = 'Show Critical Path'; + +$lang->programplan->milestoneList[1] = 'Yes'; +$lang->programplan->milestoneList[0] = 'No'; + +$lang->programplan->noData = 'No Data'; +$lang->programplan->children = 'Sub Plan'; +$lang->programplan->childrenAB = 'Child'; +$lang->programplan->confirmDelete = 'Do you want to delete the current plan?'; +$lang->programplan->workloadTips = 'The proportion of the sub stage workload is divided by 100%.'; + +$lang->programplan->stageCustom = new stdClass(); +$lang->programplan->stageCustom->date = 'Show Date'; +$lang->programplan->stageCustom->task = 'Show Task'; + +$lang->programplan->error = new stdclass(); +$lang->programplan->error->percentNumber = '"Workload %" must be digits.'; +$lang->programplan->error->planFinishSmall = 'The "End" date must be > the "Begin" date.'; +$lang->programplan->error->percentOver = 'The sum of "Workload %" cannot exceed 100%.'; +$lang->programplan->error->createdTask = 'The task has been decomposed. Sub phases cannot be added.'; +$lang->programplan->error->parentWorkload = 'The sum of the workload of the child phase cannot be greater than that of the parent phase: %s.'; diff --git a/module/programplan/lang/vi.php b/module/programplan/lang/vi.php new file mode 100644 index 0000000000..37a10b3e13 --- /dev/null +++ b/module/programplan/lang/vi.php @@ -0,0 +1,73 @@ + + * @package programplan + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +$lang->programplan->common = 'Program Plan'; +$lang->programplan->browse = 'Program Plan'; +$lang->programplan->gantt = 'Gantt Chart'; +$lang->programplan->list = 'Stage List'; +$lang->programplan->create = 'Create'; +$lang->programplan->edit = 'Edit'; +$lang->programplan->delete = 'Delete Stage'; +$lang->programplan->createSubPlan = 'Create Sub Plan'; + +$lang->programplan->parent = 'Parent Stage'; +$lang->programplan->emptyParent = 'N/A'; +$lang->programplan->name = 'Stage Name'; +$lang->programplan->subStageName = 'Sub Stage Name'; +$lang->programplan->percent = 'Workload Ratio'; +$lang->programplan->percentAB = 'Workload Ratio'; +$lang->programplan->planPercent = 'Workload'; +$lang->programplan->attribute = 'Stage Type'; +$lang->programplan->milestone = 'Milestone'; +$lang->programplan->taskProgress = 'Task Progress'; +$lang->programplan->task = 'Task'; +$lang->programplan->begin = 'Begin'; +$lang->programplan->end = 'End'; +$lang->programplan->realBegan = 'Actual Started'; +$lang->programplan->realEnd = 'Actual End'; +$lang->programplan->ac = 'Actual cost'; +$lang->programplan->sv = 'Schedule Variance'; +$lang->programplan->cv = 'Cost Variance'; +$lang->programplan->planDateRange = 'Planned Start'; +$lang->programplan->realDateRange = 'Actual Start'; +$lang->programplan->output = 'Output'; +$lang->programplan->openedBy = 'Created By'; +$lang->programplan->openedDate = 'Created Date'; +$lang->programplan->editedBy = 'Edited By'; +$lang->programplan->editedDate = 'Edited Date'; +$lang->programplan->duration = 'Duration'; +$lang->programplan->version = 'Version'; +$lang->programplan->full = 'Full Screen'; +$lang->programplan->today = 'Today'; +$lang->programplan->exporting = 'Exporting'; +$lang->programplan->exportFail = 'Export failed'; +$lang->programplan->hideCriticalPath = 'Hide Critical Path'; +$lang->programplan->showCriticalPath = 'Show Critical Path'; + +$lang->programplan->milestoneList[1] = 'Yes'; +$lang->programplan->milestoneList[0] = 'No'; + +$lang->programplan->noData = 'No Data'; +$lang->programplan->children = 'Sub Plan'; +$lang->programplan->childrenAB = 'Child'; +$lang->programplan->confirmDelete = 'Do you want to delete the current plan?'; +$lang->programplan->workloadTips = 'The proportion of the sub stage workload is divided by 100%.'; + +$lang->programplan->stageCustom = new stdClass(); +$lang->programplan->stageCustom->date = 'Show Date'; +$lang->programplan->stageCustom->task = 'Show Task'; + +$lang->programplan->error = new stdclass(); +$lang->programplan->error->percentNumber = '"Workload %" must be digits.'; +$lang->programplan->error->planFinishSmall = 'The "End" date must be > the "Begin" date.'; +$lang->programplan->error->percentOver = 'The sum of "Workload %" cannot exceed 100%.'; +$lang->programplan->error->createdTask = 'The task has been decomposed. Sub phases cannot be added.'; +$lang->programplan->error->parentWorkload = 'The sum of the workload of the child phase cannot be greater than that of the parent phase: %s.'; diff --git a/module/programplan/lang/zh-cn.php b/module/programplan/lang/zh-cn.php new file mode 100644 index 0000000000..dc91358651 --- /dev/null +++ b/module/programplan/lang/zh-cn.php @@ -0,0 +1,73 @@ + + * @package programplan + * @version $Id: zh-cn.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +$lang->programplan->common = '项目计划'; +$lang->programplan->browse = '浏览阶段计划'; +$lang->programplan->gantt = '甘特图'; +$lang->programplan->list = '阶段列表'; +$lang->programplan->create = '设置阶段'; +$lang->programplan->edit = '编辑'; +$lang->programplan->delete = '删除阶段'; +$lang->programplan->createSubPlan = '创建二级阶段'; + +$lang->programplan->parent = '父阶段'; +$lang->programplan->emptyParent = '无'; +$lang->programplan->name = '阶段名称'; +$lang->programplan->subStageName = '子阶段名称'; +$lang->programplan->percent = '工作量占比'; +$lang->programplan->percentAB = '工作量占比'; +$lang->programplan->planPercent = '工作量'; +$lang->programplan->attribute = '阶段类型'; +$lang->programplan->milestone = '里程碑'; +$lang->programplan->taskProgress = '任务进度'; +$lang->programplan->task = '任务'; +$lang->programplan->begin = '计划开始'; +$lang->programplan->end = '计划完成'; +$lang->programplan->realBegan = '实际开始'; +$lang->programplan->realEnd = '实际完成'; +$lang->programplan->ac = '实际花费'; +$lang->programplan->sv = '进度偏差率'; +$lang->programplan->cv = '成本偏差率'; +$lang->programplan->planDateRange = '计划起始日期'; +$lang->programplan->realDateRange = '实际起始日期'; +$lang->programplan->output = '输出'; +$lang->programplan->openedBy = '由谁创建'; +$lang->programplan->openedDate = '创建日期'; +$lang->programplan->editedBy = '由谁编辑'; +$lang->programplan->editedDate = '编辑日期'; +$lang->programplan->duration = '工期'; +$lang->programplan->version = '版本号'; +$lang->programplan->full = '全屏'; +$lang->programplan->today = '今天'; +$lang->programplan->exporting = '导出'; +$lang->programplan->exportFail = '导出失败'; +$lang->programplan->hideCriticalPath = '隐藏关键路径'; +$lang->programplan->showCriticalPath = '显示关键路径'; + +$lang->programplan->milestoneList[1] = '是'; +$lang->programplan->milestoneList[0] = '否'; + +$lang->programplan->noData = '暂无数据。'; +$lang->programplan->children = '二级计划'; +$lang->programplan->childrenAB = '子'; +$lang->programplan->confirmDelete = '确定要删除当前计划吗?'; +$lang->programplan->workloadTips = '子阶段工作量占比按百分百的比例进行拆分'; + +$lang->programplan->stageCustom = new stdClass(); +$lang->programplan->stageCustom->date = '显示日期'; +$lang->programplan->stageCustom->task = '显示任务'; + +$lang->programplan->error = new stdclass(); +$lang->programplan->error->percentNumber = '"工作量比例"必须为数字'; +$lang->programplan->error->planFinishSmall = '"计划完成时间"必须大于"计划开始时间"'; +$lang->programplan->error->percentOver = '工作量占比累计不应当超过100%'; +$lang->programplan->error->createdTask = '已分解任务,不可添加子阶段'; +$lang->programplan->error->parentWorkload = '子阶段的工作量之和不能大于父阶段的工作量:%s'; diff --git a/module/programplan/lang/zh-tw.php b/module/programplan/lang/zh-tw.php new file mode 100644 index 0000000000..7afefe8a6f --- /dev/null +++ b/module/programplan/lang/zh-tw.php @@ -0,0 +1,73 @@ + + * @package programplan + * @version $Id: zh-tw.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +$lang->programplan->common = '項目計劃'; +$lang->programplan->browse = '瀏覽階段計劃'; +$lang->programplan->gantt = '甘特圖'; +$lang->programplan->list = '階段列表'; +$lang->programplan->create = '設置階段'; +$lang->programplan->edit = '編輯'; +$lang->programplan->delete = '刪除'; +$lang->programplan->createSubPlan = '創建二級階段'; + +$lang->programplan->parent = '父階段'; +$lang->programplan->emptyParent = '無'; +$lang->programplan->name = '階段名稱'; +$lang->programplan->subStageName = '子階段名稱'; +$lang->programplan->percent = '工作量占比'; +$lang->programplan->percentAB = '工作量占比'; +$lang->programplan->planPercent = '工作量'; +$lang->programplan->attribute = '階段類型'; +$lang->programplan->milestone = '里程碑'; +$lang->programplan->taskProgress = '任務進度'; +$lang->programplan->task = '任務'; +$lang->programplan->begin = '計劃開始'; +$lang->programplan->end = '計劃完成'; +$lang->programplan->realBegan = '實際開始'; +$lang->programplan->realEnd = '實際完成'; +$lang->programplan->ac = '實際花費'; +$lang->programplan->sv = '進度偏差率'; +$lang->programplan->cv = '成本偏差率'; +$lang->programplan->planDateRange = '計划起始日期'; +$lang->programplan->realDateRange = '實際起始日期'; +$lang->programplan->output = '輸出'; +$lang->programplan->openedBy = '由誰創建'; +$lang->programplan->openedDate = '創建日期'; +$lang->programplan->editedBy = '由誰編輯'; +$lang->programplan->editedDate = '編輯日期'; +$lang->programplan->duration = '計劃工期'; +$lang->programplan->version = '版本號'; +$lang->programplan->full = '全屏'; +$lang->programplan->today = '今天'; +$lang->programplan->exporting = '導出'; +$lang->programplan->exportFail = '導出失敗'; +$lang->programplan->hideCriticalPath = '隱藏關鍵路徑'; +$lang->programplan->showCriticalPath = '顯示關鍵路徑'; + +$lang->programplan->milestoneList[1] = '是'; +$lang->programplan->milestoneList[0] = '否'; + +$lang->programplan->noData = '暫無數據。'; +$lang->programplan->children = '二級計劃'; +$lang->programplan->childrenAB = '子'; +$lang->programplan->confirmDelete = '確定要刪除當前計劃嗎?'; +$lang->programplan->workloadTips = '子階段工作量占比按百分百的比例進行拆分'; + +$lang->programplan->stageCustom = new stdClass(); +$lang->programplan->stageCustom->date = '顯示日期'; +$lang->programplan->stageCustom->task = '顯示任務'; + +$lang->programplan->error = new stdclass(); +$lang->programplan->error->percentNumber = '"工作量比例"必須為數字'; +$lang->programplan->error->planFinishSmall = '"計劃完成時間"必須大於"計劃開始時間"'; +$lang->programplan->error->percentOver = '工作量占比累計不應當超過100%'; +$lang->programplan->error->createdTask = '已分解任務,不可添加子階段'; +$lang->programplan->error->parentWorkload = '子階段的工作量之和不能大於父階段的工作量:%s'; diff --git a/module/programplan/model.php b/module/programplan/model.php new file mode 100644 index 0000000000..b0f8d556da --- /dev/null +++ b/module/programplan/model.php @@ -0,0 +1,918 @@ + + * @package programplan + * @version $Id: model.php 5079 2013-07-10 00:44:34Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +?> +dao->select('*')->from(TABLE_PROJECT)->where('id')->eq($planID)->fetch(); + + return $this->processPlan($plan); + } + + /** + * Get plans list. + * + * @param int $executionID + * @param int $productID + * @param string $browseType all|parent + * @param string $orderBy + * @access public + * @return array + */ + public function getStage($executionID = 0, $productID = 0, $browseType = 'all', $orderBy = 'id_asc') + { + if(empty($executionID) || empty($productID)) return array(); + + $plans = $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.product')->eq($productID) + ->andWhere('t2.type')->eq('stage') + ->beginIF($browseType == 'all')->andWhere('t2.project')->eq($executionID)->fi() + ->beginIF($browseType == 'parent')->andWhere('t2.parent')->eq($executionID)->fi() + ->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->sprints)->fi() + ->andWhere('t2.deleted')->eq('0') + ->orderBy($orderBy) + ->fetchAll('id'); + + return $this->processPlans($plans); + } + + /** + * Get plans by idList. + * + * @param array $idList + * @access public + * @return array + */ + public function getByList($idList = array()) + { + $plans = $this->dao->select('*')->from(TABLE_PROJECT) + ->where('id')->in($idList) + ->andWhere('type')->eq('project') + ->fetchAll('id'); + + return $this->processPlans($plans); + } + + /** + * Get plans. + * + * @param int $executionID + * @param int $productID + * @param string $orderBy + * @access public + * @return array + */ + public function getPlans($executionID = 0, $productID = 0, $orderBy = 'id_asc') + { + $plans = $this->getStage($executionID, $productID, 'all', $orderBy); + + $parents = array(); + $children = array(); + foreach($plans as $planID => $plan) + { + $plan->grade == 1 ? $parents[$planID] = $plan : $children[$plan->parent][] = $plan; + } + + foreach($parents as $planID => $plan) $parents[$planID]->children = isset($children[$planID]) ? $children[$planID] : array(); + + return $parents; + } + + /** + * Get pairs. + * + * @param int $executionID + * @param int $productID + * @param string $type + * @access public + * @return array + */ + public function getPairs($executionID, $productID = 0, $type = 'all') + { + $plans = $this->getPlans($executionID, $productID); + + $pairs = array(0 => ''); + foreach($plans as $plan) + { + $pairs[$plan->id] = $plan->name; + if(!empty($plan->children)) + { + foreach($plan->children as $child) $pairs[$child->id] = $plan->name . '/' . $child->name; + } + } + + return $pairs; + } + + /** + * Get gantt data. + * + * @param int $executionID + * @param int $productID + * @param int $baselineID + * @param string $selectCustom + * @param bool $returnJson + * @access public + * @return string + */ + public function getDataForGantt($executionID, $productID, $baselineID = 0, $selectCustom = '', $returnJson = true) + { + $this->loadModel('stage'); + + $plans = $this->getStage($executionID, $productID); + if($baselineID) + { + $baseline = $this->loadModel('cm')->getByID($baselineID); + $oldData = json_decode($baseline->data); + $oldPlans = $oldData->stage; + foreach($oldPlans as $id => $oldPlan) + { + if(!isset($plans[$id])) continue; + $plans[$id]->version = $oldPlan->version; + $plans[$id]->name = $oldPlan->name; + $plans[$id]->milestone = $oldPlan->milestone; + $plans[$id]->begin = $oldPlan->begin; + $plans[$id]->end = $oldPlan->end; + } + } + + $datas = array(); + $planIDList = array(); + $isMilestone = " "; + $stageIndex = array(); + foreach($plans as $plan) + { + $planIDList[$plan->id] = $plan->id; + + $start = helper::isZeroDate($plan->begin) ? '' : $plan->begin; + $end = helper::isZeroDate($plan->end) ? '' : $plan->end; + + $data = new stdclass(); + $data->id = $plan->id; + $data->type = 'plan'; + $data->text = empty($plan->milestone) ? $plan->name : $plan->name . $isMilestone ; + $data->percent = $plan->percent; + $data->attribute = zget($this->lang->stage->typeList, $plan->attribute); + $data->milestone = zget($this->lang->programplan->milestoneList, $plan->milestone); + $data->begin = $start; + $data->deadline = $end; + $data->realBegan = helper::isZeroDate($plan->realBegan) ? '' : substr($plan->realBegan, 0, 10); + $data->realEnd = helper::isZeroDate($plan->realEnd) ? '' : substr($plan->realEnd, 0, 10); + $data->parent = $plan->grade == 1 ? 0 :$plan->parent; + $data->open = true; + $data->start_date = $data->realBegan ? $data->realBegan : $data->begin; + $data->endDate = $data->realEnd ? $data->realEnd : $data->deadline; + $data->duration = 0; + + if($data->endDate > $data->start_date) $data->duration = helper::diffDate($data->endDate, $data->start_date) + 1; + if($data->start_date) $data->start_date = date('d-m-Y', strtotime($data->start_date)); + if($data->start_date == '' or $data->endDate == '') $data->duration = 0; + + $datas['data'][] = $data; + $stageIndex[] = array('planID' => $plan->id, 'progress' => array('totalConsumed' => 0, 'totalReal' => 0)); + } + + $taskSign = "[ T ] "; + $taskPri = "%s "; + + /* Judge whether to display tasks under the stage. */ + $owner = $this->app->user->account; + $module = 'programplan'; + $section = 'browse'; + $object = 'stageCustom'; + + if(empty($selectCustom)) $selectCustom = $this->loadModel('setting')->getItem("owner={$owner}&module={$module}§ion={$section}&key={$object}"); + + $tasks = array(); + if(strpos($selectCustom, 'task') !== false) + { + $tasks = $this->dao->select('*')->from(TABLE_TASK)->where('deleted')->eq(0)->andWhere('execution')->in($planIDList)->fetchAll('id'); + } + + if($baselineID) + { + $oldTasks = $oldData->task; + foreach($oldTasks as $id => $oldTask) + { + if(!isset($tasks->$id)) continue; + $tasks->$id->version = $oldTask->version; + $tasks->$id->name = $oldTask->name; + $tasks->$id->estStarted = $oldTask->estStarted; + $tasks->$id->deadline = $oldTask->deadline; + } + } + + foreach($tasks as $task) + { + $start = helper::isZeroDate($task->estStarted) ? '' : $task->estStarted; + $end = helper::isZeroDate($task->deadline) ? '' : $task->deadline; + + $realBegan = helper::isZeroDate($task->realStarted) ? '' : substr($task->realStarted, 0, 10); + $realEnd = helper::isZeroDate($task->finishedDate) ? '' : substr($task->finishedDate, 0, 10); + $priIcon = sprintf($taskPri, $task->pri, $task->pri, $task->pri); + + $data = new stdclass(); + $data->id = $task->execution . '-' . $task->id; + $data->type = 'task'; + $data->text = $taskSign . $priIcon . $task->name; + $data->percent = ''; + $data->attribute = ''; + $data->milestone = ''; + $data->begin = $start; + $data->deadline = $end; + $data->realBegan = $realBegan; + $data->realEnd = $realEnd; + $data->parent = $task->parent > 0 ? $task->execution . '-' . $task->parent : $task->execution; + $data->open = true; + $progress = $task->consumed ? round($task->consumed / ($task->left + $task->consumed), 3) * 100 : 0; + $data->taskProgress = $progress . '%'; + $data->start_date = $data->realBegan ? $data->realBegan : $data->begin; + $data->endDate = $data->realEnd ? $data->realEnd : $data->deadline; + $data->duration = 0; + + if($data->endDate > $data->start_date) $data->duration = helper::diffDate($data->endDate, $data->start_date) + 1; + if($data->start_date) $data->start_date = date('d-m-Y', strtotime($data->start_date)); + if($data->start_date == '' or $data->endDate == '') $data->duration = 0; + + $datas['data'][] = $data; + foreach($stageIndex as $index => $stage) + { + if($stage['planID'] == $task->execution) + { + $stageIndex[$index]['progress']['totalConsumed'] += $task->consumed; + $stageIndex[$index]['progress']['totalReal'] += ($task->left + $task->consumed); + } + } + } + + /* Calculate the progress of the phase. */ + foreach($stageIndex as $index => $stage) + { + $progress = empty($stage['progress']['totalConsumed']) ? 0 : round($stage['progress']['totalConsumed'] / $stage['progress']['totalReal'], 3) * 100; + $progress .= '%'; + $datas['data'][$index]->taskProgress = $progress; + } + + return $returnJson ? json_encode($datas) : $datas; + } + + /** + * Get total percent. + * + * @param object $stage + * @param object $parent + * @access public + * @return int + */ + public function getTotalPercent($stage, $parent = false) + { + /* When parent is equal to true, query the total workload of the subphase. */ + $executionID = $parent ? $stage->id : $stage->project; + $plans = $this->getStage($executionID, $stage->product, 'parent'); + + $totalPercent = 0; + $stageID = $stage->id; + foreach($plans as $id => $stage) + { + if($id == $stageID) continue; + $totalPercent += $stage->percent; + } + + return $totalPercent; + } + + /** + * Process plans. + * + * @param int $plans + * @access public + * @return object + */ + public function processPlans($plans) + { + foreach($plans as $planID => $plan) $plans[$planID] = $this->processPlan($plan); + return $plans; + } + + /** + * Process plan. + * + * @param int $plan + * @access public + * @return object + */ + public function processPlan($plan) + { + $plan->setMilestone = true; + + if($plan->parent) + { + $attribute = $this->dao->select('attribute')->from(TABLE_PROJECT)->where('id')->eq($plan->parent)->fetch('attribute'); + $plan->attribute = $attribute == 'develop' ? $attribute : $plan->attribute; + } + else + { + $milestones = $this->dao->select('count(*) AS count')->from(TABLE_PROJECT) + ->where('parent')->eq($plan->id) + ->andWhere('milestone')->eq(1) + ->andWhere('deleted')->eq(0) + ->fetch('count'); + if($milestones > 0) + { + $plan->milestone = 0; + $plan->setMilestone = false; + } + } + + $plan->begin = $plan->begin == '0000-00-00' ? '' : $plan->begin; + $plan->end = $plan->end == '0000-00-00' ? '' : $plan->end; + $plan->realBegan = $plan->realBegan == '0000-00-00' ? '' : $plan->realBegan; + $plan->realEnd = $plan->realEnd == '0000-00-00' ? '' : $plan->realEnd; + + $plan->product = $this->loadModel('product')->getProductIDByProject($plan->id); + $plan->productName = $this->dao->findByID($plan->product)->from(TABLE_PRODUCT)->fetch('name'); + + return $plan; + } + + /** + * Get duration. + * + * @param int $begin + * @param int $end + * @access public + * @return int + */ + public function getDuration($begin, $end) + { + $duration = $this->loadModel('holiday')->getActualWorkingDays($begin, $end); + return count($duration); + } + + /** + * Create a plan. + * + * @param int $projectID + * @param int $productID + * @param int $parentID + * @access public + * @return bool + */ + public function create($projectID = 0, $productID = 0, $parentID = 0) + { + $data = (array)fixer::input('post')->get(); + extract($data); + + /* Determine if a task has been created under the parent phase. */ + if(!$this->isCreateTask($parentID)) return dao::$errors['message'][] = $this->lang->programplan->error->createdTask; + + /* The child phase type setting is the same as the parent phase. */ + $parentAttribute = ''; + $parentPercent = 0; + if($parentID) + { + $parentStage = $this->getByID($parentID); + $parentAttribute = $parentStage->attribute; + $parentPercent = $parentStage->percent; + $parentACL = $parentStage->acl; + } + + $attributes = array_values($attributes); + $milestone = array_values($milestone); + $datas = array(); + foreach($names as $key => $name) + { + if(empty($name)) continue; + + $plan = new stdclass(); + $plan->id = isset($planIDList[$key]) ? $planIDList[$key] : ''; + $plan->type = 'stage'; + $plan->project = $projectID; + $plan->parent = $parentID ? $parentID : $projectID; + $plan->name = $names[$key]; + $plan->percent = $percents[$key]; + $plan->attribute = empty($parentID) ? $attributes[$key] : $parentAttribute; + $plan->milestone = $milestone[$key]; + $plan->begin = empty($begin[$key]) ? '0000-00-00' : $begin[$key]; + $plan->end = empty($end[$key]) ? '0000-00-00' : $end[$key]; + $plan->realBegan = empty($realBegan[$key]) ? '0000-00-00' : $realBegan[$key]; + $plan->realEnd = empty($realEnd[$key]) ? '0000-00-00' : $realEnd[$key]; + $plan->output = empty($output[$key]) ? '' : implode(',', $output[$key]); + $plan->acl = empty($parentID) ? $acl[$key] : $parentACL; + + $datas[] = $plan; + } + + $totalPercent = 0; + $totalDevType = 0; + $milestone = 0; + foreach($datas as $plan) + { + if($plan->percent and !preg_match("/^[0-9]+(.[0-9]{1,3})?$/", $plan->percent)) + { + dao::$errors['message'][] = $this->lang->programplan->error->percentNumber; + return false; + } + if($plan->end != '0000-00-00' and $plan->end < $plan->begin) + { + dao::$errors['message'][] = $this->lang->programplan->error->planFinishSmall; + return false; + } + + if($plan->begin == '0000-00-00') $plan->begin = ''; + if($plan->end == '0000-00-00') $plan->end = ''; + foreach(explode(',', $this->config->programplan->create->requiredFields) as $field) + { + $field = trim($field); + if($field and empty($plan->$field)) + { + dao::$errors['message'][] = sprintf($this->lang->error->notempty, $this->lang->programplan->$field); + return false; + } + } + + $plan->percent = (float)$plan->percent; + $totalPercent += $plan->percent; + + if($plan->milestone) $milestone = 1; + } + + if($totalPercent > 100) return dao::$errors['message'][] = $this->lang->programplan->error->percentOver; + + $this->loadModel('action'); + $this->loadModel('user'); + $this->loadModel('execution'); + $this->app->loadLang('doc'); + $account = $this->app->user->account; + $now = helper::now(); + foreach($datas as $data) + { + /* Set planDuration and realDuration. */ + $data->planDuration = $this->getDuration($data->begin, $data->end); + $data->realDuration = $this->getDuration($data->realBegan, $data->realEnd); + + $projectChanged = false; + $data->days = helper::diffDate($data->end, $data->begin) + 1; + if($data->id) + { + $stageID = $data->id; + unset($data->id); + + $oldStage = $this->getByID($stageID); + $planChanged = ($oldStage->name != $data->name || $oldStage->milestone != $data->milestone || $oldStage->begin != $data->begin || $oldStage->end != $data->end); + + if($planChanged) $data->version = $oldStage->version + 1; + $this->dao->update(TABLE_PROJECT)->data($data) + ->autoCheck() + ->batchCheck($this->config->programplan->edit->requiredFields, 'notempty') + ->checkIF($plan->percent != '', 'percent', 'float') + ->where('id')->eq($stageID) + ->exec(); + + if($data->acl != 'open') $this->user->updateUserView($stageID, 'sprint'); + + /* Record version change information. */ + if($planChanged) + { + $spec = new stdclass(); + $spec->project = $stageID; + $spec->version = $data->version; + $spec->name = $data->name; + $spec->milestone = $data->milestone; + $spec->begin = $data->begin; + $spec->end = $data->end; + $this->dao->insert(TABLE_PROJECTSPEC)->data($spec)->exec(); + } + + $changes = common::createChanges($oldStage, $data); + $actionID = $this->action->create('execution', $stageID, 'edited'); + $this->action->logHistory($actionID, $changes); + } + else + { + unset($data->id); + $data->status = 'wait'; + $data->version = 1; + $data->parentVersion = $data->parent == 0 ? 0 : $this->dao->findByID($data->parent)->from(TABLE_PROJECT)->fetch('version'); + $data->team = substr($data->name,0, 30); + $data->openedBy = $account; + $data->openedDate = $now; + $data->openedVersion = $this->config->version; + if(!isset($data->acl)) $data->acl = $this->dao->findByID($data->parent)->from(TABLE_PROJECT)->fetch('acl'); + $this->dao->insert(TABLE_PROJECT)->data($data) + ->autoCheck() + ->batchCheck($this->config->programplan->create->requiredFields, 'notempty') + ->checkIF($plan->percent != '', 'percent', 'float') + ->exec(); + + if(!dao::isError()) + { + $stageID = $this->dao->lastInsertID(); + + if($data->acl != 'open') $this->user->updateUserView($stageID, 'sprint'); + $this->dao->update(TABLE_PROJECT)->set('`order`')->eq($stageID * 5)->where('id')->eq($stageID)->exec(); + + /* Create doc lib. */ + $lib = new stdclass(); + $lib->execution = $stageID; + $lib->name = str_replace($this->lang->executionCommon, $this->lang->project->stage, $this->lang->doclib->main['execution']); + $lib->type = 'execution'; + $lib->main = '1'; + $lib->acl = 'default'; + $this->dao->insert(TABLE_DOCLIB)->data($lib)->exec(); + + /* Add creators to stage teams and execution teams. */ + $member = new stdclass(); + $member->root = $stageID; + $member->account = $account; + $member->role = $this->lang->user->roleList[$this->app->user->role]; + $member->join = $now; + $member->type = $data->type; + $member->days = $data->days; + $member->hours = $this->config->execution->defaultWorkhours; + $this->dao->insert(TABLE_TEAM)->data($member)->exec(); + $this->execution->addProjectMembers($data->project, array($member)); + + $this->setTreePath($stageID); + if($data->acl != 'open') $this->user->updateUserView($stageID, 'sprint'); + + $this->post->set('products', array(0 => $productID)); + $this->execution->updateProducts($stageID); + + /* Record version change information. */ + $spec = new stdclass(); + $spec->project = $stageID; + $spec->version = $data->version; + $spec->name = $data->name; + $spec->milestone = $data->milestone; + $spec->begin = $data->begin; + $spec->end = $data->end; + $this->dao->insert(TABLE_PROJECTSPEC)->data($spec)->exec(); + + $this->action->create('execution', $stageID, 'opened', '', join(',', $_POST['products'])); + } + } + + /* If child plans has milestone, update parent plan set milestone eq 0 . */ + if($parentID and $milestone) $this->dao->update(TABLE_PROJECT)->set('milestone')->eq(0)->where('id')->eq($parentID)->exec(); + + if(dao::isError()) die(js::error(dao::getError())); + } + } + + /** + * Set stage tree path. + * + * @param int $planID + * @access public + * @return bool + */ + public function setTreePath($planID) + { + $stage = $this->dao->select('id,type,parent,path,grade')->from(TABLE_PROJECT)->where('id')->eq($planID)->fetch(); + $parent = $this->dao->select('id,type,parent,path,grade')->from(TABLE_PROJECT)->where('id')->eq($stage->parent)->fetch(); + + if($parent->type == 'project') + { + $path['path'] = ",{$parent->id},{$stage->id},"; + $path['grade'] = 1; + } + elseif($parent->type == 'stage') + { + $path['path'] = $parent->path . "{$stage->id},"; + $path['grade'] = $parent->grade + 1; + } + $this->dao->update(TABLE_PROJECT)->set('path')->eq($path['path'])->set('grade')->eq($path['grade'])->where('id')->eq($stage->id)->exec(); + } + + /** + * Update a plan. + * + * @param int $planID + * @param int $projectID + * @access public + * @return bool|array + */ + public function update($planID = 0, $projectID = 0) + { + /* Get oldPlan and the data from the post. */ + $oldPlan = $this->getByID($planID); + $plan = fixer::input('post') + ->setDefault('begin', '0000-00-00') + ->setDefault('end', '0000-00-00') + ->setDefault('realBegan', '0000-00-00') + ->setDefault('realEnd', '0000-00-00') + ->join('output', ',') + ->get(); + + /* Judgment of required items. */ + if($plan->begin == '0000-00-00') dao::$errors['begin'][] = sprintf($this->lang->error->notempty, $this->lang->programplan->begin); + if($plan->end == '0000-00-00') dao::$errors['end'][] = sprintf($this->lang->error->notempty, $this->lang->programplan->end); + + $planChanged = ($oldPlan->name != $plan->name || $oldPlan->milestone != $plan->milestone || $oldPlan->begin != $plan->begin || $oldPlan->end != $plan->end); + + if($plan->parent > 0) + { + $parentStage = $this->getByID($plan->parent); + $plan->attribute = $parentStage->attribute; + $plan->acl = $parentStage->acl; + $parentPercent = $parentStage->percent; + + $childrenTotalPercent = $this->getTotalPercent($parentStage, true); + $childrenTotalPercent = $plan->parent == $oldPlan->parent ? ($childrenTotalPercent - $oldPlan->percent + $plan->percent) : ($childrenTotalPercent + $plan->percent); + if($childrenTotalPercent > 100) return dao::$errors['percent'][] = $this->lang->programplan->error->percentOver; + + /* If child plan has milestone, update parent plan set milestone eq 0 . */ + if($plan->milestone and $parentStage->milestone) $this->dao->update(TABLE_PROJECT)->set('milestone')->eq(0)->where('id')->eq($oldPlan->parent)->exec(); + } + else + { + /* Synchronously update sub-phase permissions. */ + $childrenIDList = $this->dao->select('*')->from(TABLE_PROJECT)->where('parent')->eq($oldPlan->id)->fetch('id'); + if(!empty($childrenIDList)) $this->dao->update(TABLE_PROJECT)->set('acl')->eq($plan->acl)->where('id')->in($childrenIDList)->exec(); + + /* The workload of the parent plan cannot exceed 100%. */ + $oldPlan->parent = $plan->parent; + $totalPercent = $this->getTotalPercent($oldPlan); + $totalPercent = $totalPercent + $plan->percent; + if($totalPercent > 100) return dao::$errors['percent'][] = $this->lang->programplan->error->percentOver; + } + + /* Set planDuration and realDuration. */ + $plan->planDuration = $this->getDuration($plan->begin, $plan->end); + $plan->realDuration = $this->getDuration($plan->realBegan, $plan->realEnd); + + if($planChanged) $plan->version = $oldPlan->version + 1; + if(empty($plan->parent)) $plan->parent = $projectID; + + $this->dao->update(TABLE_PROJECT)->data($plan) + ->autoCheck() + ->batchCheck($this->config->programplan->edit->requiredFields, 'notempty') + ->checkIF($plan->end != '0000-00-00', 'end', 'ge', $plan->begin) + ->checkIF($plan->percent != false, 'percent', 'float') + ->where('id')->eq($planID) + ->exec(); + + if(dao::isError()) return false; + $this->setTreePath($planID); + if($plan->acl != 'open') $this->loadModel('user')->updateUserView($planID, 'sprint'); + + if($planChanged) + { + $spec = new stdclass(); + $spec->project = $planID; + $spec->version = $plan->version; + $spec->name = $plan->name; + $spec->milestone = $plan->milestone; + $spec->begin = $plan->begin; + $spec->end = $plan->end; + + $this->dao->insert(TABLE_PROJECTSPEC)->data($spec)->exec(); + } + + return common::createChanges($oldPlan, $plan); + } + + /** + * Print cell. + * + * @param int $col + * @param int $plan + * @param int $users + * @param int $projectID + * @access public + * @return string + */ + public function printCell($col, $plan, $users, $projectID) + { + $id = $col->id; + if($col->show) + { + $class = 'c-' . $id; + $title = ''; + $idList = array('id','name','output','percent','attribute','version','begin','end','realBegan','realEnd', 'openedBy', 'openedDate'); + if(in_array($id,$idList)) + { + $class .= ' text-left'; + $title = "title='{$plan->$id}'"; + if($id == 'output') $class .= ' text-ellipsis'; + if(!empty($plan->children)) $class .= ' has-child'; + } + else + { + $class .= ' text-center'; + } + if($id == 'actions') $class .= ' c-actions'; + + echo ""; + if(isset($this->config->bizVersion)) $this->loadModel('flow')->printFlowCell('programplan', $plan, $id); + switch($id) + { + case 'id': + echo sprintf('%03d', $plan->id); + break; + case 'name': + $milestoneFlag = $plan->milestone ? " lang->programplan->milestone}'>" : ''; + if($plan->grade > 1) echo '' . $this->lang->programplan->childrenAB . ' '; + echo $plan->name . $milestoneFlag; + if(!empty($plan->children)) echo ''; + break; + case 'percent': + echo $plan->percent . '%'; + break; + case 'attribute': + echo zget($this->lang->stage->typeList, $plan->attribute, ''); + break; + case 'begin': + echo $plan->begin; + break; + case 'end': + echo $plan->end; + break; + case 'realBegan': + echo $plan->realBegan; + break; + case 'realEnd': + echo $plan->realEnd; + break; + case 'output': + echo $plan->output; + break; + case 'version': + echo $plan->version; + break; + case 'editedBy': + echo zget($users, $plan->editedBy); + break; + case 'editedDate': + echo substr($plan->editedDate, 5, 11); + break; + case 'openedBy': + echo zget($users, $plan->openedBy); + break; + case 'openedDate': + echo substr($plan->openedDate, 5, 11); + break; + case 'actions': + common::printIcon('execution', 'start', "executionID={$plan->id}", $plan, 'list', '', '', 'iframe', true); + $class = !empty($plan->children) ? 'disabled' : ''; + common::printIcon('task', 'create', "executionID={$plan->id}", $plan, 'list', '', '', $class, false, "data-app='execution'"); + + if($plan->grade == 1 && $this->isCreateTask($plan->id)) + { + common::printIcon('programplan', 'create', "program={$plan->parent}&productID=$plan->product&planID=$plan->id", $plan, 'list', 'split', '', '', '', '', $this->lang->programplan->createSubPlan); + } + else + { + $disabled = ($plan->grade == 2) ? ' disabled' : ''; + echo html::a('javascript:alert("' . $this->lang->programplan->error->createdTask . '");', '', '', 'class="btn ' . $disabled . '"'); + } + + common::printIcon('programplan', 'edit', "planID=$plan->id&projectID=$projectID", $plan, 'list', '', '', 'iframe', true); + + $disabled = !empty($plan->children) ? ' disabled' : ''; + if(common::hasPriv('execution', 'delete', $plan)) + { + common::printIcon('execution', 'delete', "planID=$plan->id&confirm=no", $plan, 'list', 'trash', 'hiddenwin' , $disabled, '', '', $this->lang->programplan->delete); + } + break; + } + echo ''; + } + } + + /** + * Is create task. + * + * @param int $planID + * @access public + * @return bool + */ + public function isCreateTask($planID) + { + $task = $this->dao->select('*')->from(TABLE_TASK)->where('execution')->eq($planID)->limit(1)->fetch(); + return empty($task) ? true : false; + } + + /** + * Is clickable. + * + * @param int $plan + * @param int $action + * @static + * @access public + * @return bool + */ + public static function isClickable($plan, $action) + { + $action = strtolower($action); + + if($action == 'create' and $plan->grade > 1) return false; + + return true; + } + + /** + * Get the stage set to milestone. + * + * @param int $projectID + * @access public + * @return array + */ + public function getMilestones($projectID = 0) + { + return $this->dao->select('id, name')->from(TABLE_PROJECT) + ->where('project')->eq($projectID) + ->andWhere('type')->eq('stage') + ->andWhere('milestone')->eq(1) + ->andWhere('deleted')->eq(0) + ->orderBy('id_desc') + ->fetchPairs(); + } + + /** + * Get milestone by product. + * + * @param int $productID + * @access public + * @return object + */ + public function getMilestoneByProduct($productID) + { + return $this->dao->select('t1.id, t1.name')->from(TABLE_PROJECT)->alias('t1') + ->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.id=t2.project') + ->where('t2.product')->eq($productID) + ->andWhere('t1.type')->eq('stage') + ->andWhere('t1.milestone')->eq(1) + ->andWhere('t1.deleted')->eq(0) + ->orderBy('t1.begin asc') + ->fetchPairs(); + } + + /** + * Get parent stage list. + * + * @param int $executionID + * @param int $planID + * @param int $productID + * @access public + * @return array + */ + public function getParentStageList($executionID, $planID, $productID) + { + $parentStage = $this->dao->select('t2.id, t2.name')->from(TABLE_PROJECTPRODUCT) + ->alias('t1')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.product')->eq($productID) + ->andWhere('t2.project')->eq($executionID) + ->andWhere('t2.grade')->eq(1) + ->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->sprints)->fi() + ->orderBy('t2.id desc') + ->fetchPairs(); + + /* Remove the currently edited stage. */ + if(isset($parentStage[$planID])) unset($parentStage[$planID]); + + $plan = $this->getByID($planID); + foreach($parentStage as $key => $stage) + { + $isCreate = $this->isCreateTask($key); + if($isCreate === false and $key != $plan->parent) unset($parentStage[$key]); + } + $parentStage[0] = $this->lang->programplan->emptyParent; + ksort($parentStage); + + return $parentStage; + } +} diff --git a/module/programplan/view/browse.html.php b/module/programplan/view/browse.html.php new file mode 100644 index 0000000000..c732b2be1d --- /dev/null +++ b/module/programplan/view/browse.html.php @@ -0,0 +1,38 @@ + + * @package programplan + * @version $Id: browse.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + + + +
+ +
+

+ programplan->noData;?> + + createLink('programplan', 'create', "projectID=$projectID&productID=$productID"), " " . $lang->programplan->create, '', "class='btn btn-info'");?> + +

+
+ + + + +
+ + diff --git a/module/programplan/view/create.html.php b/module/programplan/view/create.html.php new file mode 100644 index 0000000000..0dc384c14b --- /dev/null +++ b/module/programplan/view/create.html.php @@ -0,0 +1,184 @@ + + * @package programplan + * @version $Id: create.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + + + + + + +programplan->name : $lang->programplan->subStageName;?> +
+
+ + + + + + + + + + + + + config->qcVersion)):?> + + + + + + + + + + + + + + + + + + + + config->qcVersion)):?> + + + + + + + + + + + setMilestone ? '' : "disabled='disabled'"?> + id);?> + + + + + + + + + + + config->qcVersion)):?> + output) ? 0 : explode(',', $plan->output);?> + + + + + + + + + + + + + + + + + + + + config->qcVersion)):?> + + + + + + + + + + + + + +
+ programplan->percent;?> + + + + programplan->attribute;?>project->acl;?>programplan->milestone;?>programplan->begin;?>programplan->end;?>programplan->realBegan;?>programplan->realEnd;?>programplan->output;?> actions;?>
+
+ + % +
+
stage->typeList, $stage->type, "class='form-control'");?>project->aclList, 'open', "class='form-control' $class");?>programplan->milestoneList, 0);?> + + +
+
+ + % +
+
stage->typeList, $plan->attribute, "class='form-control'");?>project->aclList, $plan->acl, "class='form-control' $class");?>programplan->milestoneList, $plan->milestone, $disabled);?> + +
+
+ + % +
+
stage->typeList, '', "class='form-control'");?>project->aclList, 'open', "class='form-control' $class");?>programplan->milestoneList, 0);?> + + +
+ +
+
+
+ + + + + + + + + + + + + + config->qcVersion)):?> + + + + + +
+ + diff --git a/module/programplan/view/edit.html.php b/module/programplan/view/edit.html.php new file mode 100644 index 0000000000..adb92bb94f --- /dev/null +++ b/module/programplan/view/edit.html.php @@ -0,0 +1,107 @@ + + * @package programplan + * @version $Id: edit.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + + +
+
+
+

programplan->edit;?>

+
+
+ + + + + + + + + + + + + + + " id="attributeType"> + + + + setMilestone):?> + + + + + + milestone);?> + + + + grade == 2 ? "disabled='disabled'" : '';?> + + + + + + + + + + + config->qcVersion)):?> + + + + + + + + + +
programplan->parent;?>parent, "class='form-control chosen '");?>
programplan->name;?> name, "class='form-control'");?>
programplan->percent;?> +
+ percent, "class='form-control'");?> +
% +
+
programplan->attribute;?> stage->typeList, $plan->attribute, "class='form-control'");?>
programplan->milestone;?> programplan->milestoneList, $plan->milestone);?>
project->acl;?> project->aclList, $plan->acl, "class='form-control' $class");?>
programplan->planDateRange;?> +
+ begin, "class='form-control form-date'");?> + project->to;?> + end, "class='form-control form-date'");?> +
+
programplan->realDateRange;?> +
+ realBegan, "class='form-control form-date'");?> + project->to;?> + realEnd, "class='form-control form-date'");?> +
+
programplan->output;?> output, "class='form-control chosen ' multiple");?>
+
+
+
+ + diff --git a/module/programplan/view/gantt.html.php b/module/programplan/view/gantt.html.php new file mode 100644 index 0000000000..41fda4a4b9 --- /dev/null +++ b/module/programplan/view/gantt.html.php @@ -0,0 +1,436 @@ + + * @package programplan + * @version $Id: gantt.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + + +createLink('programplan', 'ajaxCustom'));?> + +rawModule);?> +rawMethod);?> + +
+
+
+ programplan->full, 'id="fullScreenBtn"', 'btn btn-primary btn-sm')?> + rawModule == 'review' and $app->rawMethod == 'assess') unset($lang->programplan->stageCustom->date); ?> + programplan->stageCustom, $selectCustom);?> +
+
+
+
+
+
+ diff --git a/module/programplan/view/list.html.php b/module/programplan/view/list.html.php new file mode 100644 index 0000000000..0468da3c59 --- /dev/null +++ b/module/programplan/view/list.html.php @@ -0,0 +1,89 @@ + + * @package programplan + * @version $Id: list.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> +programplan->confirmDelete); +?> + +
+
+ +
+ datatable->getSetting('programplan'); + $widths = $this->datatable->setFixedFieldWidth($setting); + $widths['leftWidth'] = 300; + $columns = 0; + ?> + ' data-fixed-right-width='' data-checkbox-name='programplanList[]'> + + + + + + + + + + + + + + + + + $value) $this->programplan->printCell($value, $plan, $users, $projectID);?> + + children)):?> + + children as $key => $child):?> + + children)) ? ' table-child-bottom' : '';?> + + $value) $this->programplan->printCell($value, $child, $users, $projectID);?> + + + + + + +
idAB);?> programplan->name);?>programplan->percent);?>programplan->attribute);?>programplan->begin);?>programplan->end);?>programplan->realBegan);?>programplan->realEnd);?>actions;?>
+
+ diff --git a/module/project/model.php b/module/project/model.php index 8900dc5bab..2e204e57e4 100644 --- a/module/project/model.php +++ b/module/project/model.php @@ -1427,10 +1427,18 @@ class projectModel extends model { $canOrder = common::hasPriv('project', 'updateOrder'); $canBatchEdit = common::hasPriv('project', 'batchEdit'); - $projectLink = $this->config->systemMode == 'new' ? helper::createLink('project', 'index', "projectID=$project->id", '', '', $project->id) : helper::createLink('execution', 'task', "projectID=$project->id"); $account = $this->app->user->account; $id = $col->id; + if($project->model == 'waterfall') + { + $projectLink = helper::createLink('programplan', 'browse', "projectID=$project->id&productID=0&type=lists", '', '', $project->id); + } + else + { + $projectLink = $this->config->systemMode == 'new' ? helper::createLink('project', 'index', "projectID=$project->id", '', '', $project->id) : helper::createLink('execution', 'task', "projectID=$project->id"); + } + if($col->show) { $title = ''; @@ -1480,11 +1488,8 @@ class projectModel extends model case 'name': $prefix = ''; $suffix = ''; - if(isset($this->config->maxVersion)) - { - if($project->model === 'waterfall') $prefix = "{$this->lang->project->waterfall} "; - if($project->model === 'scrum') $prefix = "{$this->lang->project->scrum} "; - } + if($project->model === 'waterfall') $prefix = "{$this->lang->project->waterfall} "; + if($project->model === 'scrum') $prefix = "{$this->lang->project->scrum} "; if(isset($project->delay)) $suffix = "{$this->lang->project->statusList['delay']}"; if(!empty($suffix) || !empty($prefix)) echo '
'; if(!empty($prefix)) echo $prefix; @@ -1938,6 +1943,15 @@ class projectModel extends model global $lang; $project = $this->getByID($objectID); + if(isset($project->model) and $project->model == 'waterfall') + { + global $lang; + $this->loadModel('execution'); + $lang->executionCommon = $lang->project->stage; + + include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php'; + } + $model = 'scrum'; if($project) $model = $project->model; diff --git a/module/project/view/browsebylist.html.php b/module/project/view/browsebylist.html.php index fee692f71b..71ba79a392 100644 --- a/module/project/view/browsebylist.html.php +++ b/module/project/view/browsebylist.html.php @@ -47,7 +47,7 @@  ", '', "class='btn btn-icon' title='{$lang->project->bycard}' id='switchButton' data-type='bycard'");?>
" . $lang->export, '', "class='btn btn-link export'")?> - config->maxVersion) and !defined('TUTORIAL')):?> + ' . $lang->project->create, '', 'class="btn btn-primary create-project-btn" data-toggle="modal"');?> ' . $lang->project->create, '', 'class="btn btn-primary create-project-btn"');?> @@ -71,7 +71,7 @@

project->empty;?> - config->maxVersion) and !defined('TUTORIAL')):?> + ' . $lang->project->create, '', 'class="btn btn-info" data-toggle="modal"');?> config->systemMode == 'new'):?> ' . $lang->project->create, '', 'class="btn btn-info"');?> diff --git a/module/stage/control.php b/module/stage/control.php new file mode 100644 index 0000000000..6fa1d394ae --- /dev/null +++ b/module/stage/control.php @@ -0,0 +1,185 @@ + + * @package stage + * @version $Id: control.php 5107 2013-07-12 01:46:12Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +class stage extends control +{ + /** + * Browse stages. + * + * @param string $orderBy + * @access public + * @return void + */ + public function browse($orderBy = "id_asc") + { + $this->view->stages = $this->stage->getStages($orderBy); + $this->view->orderBy = $orderBy; + $this->view->title = $this->lang->stage->common . $this->lang->colon . $this->lang->stage->browse; + $this->view->position[] = $this->lang->stage->common; + $this->view->position[] = $this->lang->stage->browse; + + $this->display(); + } + + /** + * Create a stage. + * + * @access public + * @return void + */ + public function create() + { + if($_POST) + { + $stageID = $this->stage->create(); + + $response['result'] = 'success'; + $response['message'] = $this->lang->saveSuccess; + if(!$stageID) + { + $response['result'] = 'fail'; + $response['message'] = dao::getError(); + return $this->send($response); + } + + $this->loadModel('action')->create('stage', $stageID, 'Opened'); + $response['locate'] = inlink('browse'); + return $this->send($response); + } + + $this->view->title = $this->lang->stage->common . $this->lang->colon . $this->lang->stage->create; + $this->view->position[] = $this->lang->stage->common; + $this->view->position[] = $this->lang->stage->create; + + $this->display(); + } + + /** + * Batch create stages. + * + * @access public + * @return void + */ + public function batchCreate() + { + if($_POST) + { + $this->stage->batchCreate(); + + $response['result'] = 'success'; + $response['message'] = $this->lang->saveSuccess; + if(dao::isError()) + { + $response['result'] = 'fail'; + $response['message'] = dao::getError(); + return $this->send($response); + } + + $response['locate'] = inlink('browse'); + return $this->send($response); + } + + $this->view->title = $this->lang->stage->common . $this->lang->colon . $this->lang->stage->batchCreate; + $this->view->position[] = $this->lang->stage->common; + $this->view->position[] = $this->lang->stage->batchCreate; + + $this->display(); + } + + /** + * Edit a stage. + * + * @param int $stageID + * @access public + * @return void + */ + public function edit($stageID = 0) + { + $stage = $this->stage->getByID($stageID); + if($_POST) + { + $changes = $this->stage->update($stageID); + + $response['result'] = 'success'; + $response['message'] = $this->lang->saveSuccess; + if(dao::isError()) + { + $response['result'] = 'fail'; + $response['message'] = dao::getError(); + return $this->send($response); + } + + $actionID = $this->loadModel('action')->create('stage', $stageID, 'Edited'); + if(!empty($changes)) $this->action->logHistory($actionID, $changes); + $response['locate'] = inlink('browse'); + return $this->send($response); + } + + $this->view->title = $this->lang->stage->common . $this->lang->colon . $this->lang->stage->edit; + $this->view->position[] = $this->lang->stage->common; + $this->view->position[] = $this->lang->stage->edit; + $this->view->stage = $stage; + + $this->display(); + } + + /** + * Set type. + * + * @access public + * @return void + */ + public function setType() + { + $this->loadModel('custom'); + if($_POST) + { + $data = fixer::input('post')->get(); + $this->custom->deleteItems("lang=all&module=stage§ion=typeList"); + foreach($data->keys as $index => $key) + { + $value = $data->values[$index]; + if(!$value or !$key) continue; + $this->custom->setItem("all.stage.typeList.{$key}", $value); + } + return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink('stage', 'settype'))); + } + + $this->view->title = $this->lang->stage->common . $this->lang->colon . $this->lang->stage->setType; + $this->view->position[] = $this->lang->stage->common; + $this->view->position[] = $this->lang->stage->setType; + $this->display(); + } + + /** + * Delete a stage. + * + * @param int $stageID + * @param string $confirm + * @access public + * @return void + */ + public function delete($stageID, $confirm = 'no') + { + $stage = $this->stage->getById($stageID); + + if($confirm == 'no') + { + die(js::confirm($this->lang->stage->confirmDelete, inlink('delete', "stageID=$stageID&confirm=yes"))); + } + else + { + $this->stage->delete(TABLE_STAGE, $stageID); + + die(js::reload('parent')); + } + } +} diff --git a/module/stage/ext/view/create.cmmi.html.hook.php b/module/stage/ext/view/create.cmmi.html.hook.php new file mode 100644 index 0000000000..6120b9e1a2 --- /dev/null +++ b/module/stage/ext/view/create.cmmi.html.hook.php @@ -0,0 +1 @@ + diff --git a/module/stage/ext/view/edit.cmmi.html.hook.php b/module/stage/ext/view/edit.cmmi.html.hook.php new file mode 100644 index 0000000000..6120b9e1a2 --- /dev/null +++ b/module/stage/ext/view/edit.cmmi.html.hook.php @@ -0,0 +1 @@ + diff --git a/module/stage/lang/de.php b/module/stage/lang/de.php new file mode 100644 index 0000000000..f11a49dfd9 --- /dev/null +++ b/module/stage/lang/de.php @@ -0,0 +1,38 @@ + + * @package stage + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +/* Actions. */ +$lang->stage->browse = 'Stage List'; +$lang->stage->create = 'Create Stage'; +$lang->stage->batchCreate = 'Batch Create'; +$lang->stage->edit = 'Edit'; +$lang->stage->delete = 'Delete'; +$lang->stage->view = 'Details'; + +/* Fields. */ +$lang->stage->common = 'Stage'; +$lang->stage->id = 'ID'; +$lang->stage->name = 'Name'; +$lang->stage->type = 'Type'; +$lang->stage->percent = 'Workload %'; +$lang->stage->setType = 'Set Type'; + +$lang->stage->typeList['request'] = 'Story'; +$lang->stage->typeList['design'] = 'Design'; +$lang->stage->typeList['dev'] = 'Development'; +$lang->stage->typeList['qa'] = 'Test'; +$lang->stage->typeList['release'] = 'Release'; +$lang->stage->typeList['review'] = 'Review'; +$lang->stage->typeList['other'] = 'Other'; + +$lang->stage->viewList = 'Stage List'; +$lang->stage->noStage = 'No stage yet'; +$lang->stage->confirmDelete = 'Do you want to delete it?'; diff --git a/module/stage/lang/en.php b/module/stage/lang/en.php new file mode 100644 index 0000000000..f11a49dfd9 --- /dev/null +++ b/module/stage/lang/en.php @@ -0,0 +1,38 @@ + + * @package stage + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +/* Actions. */ +$lang->stage->browse = 'Stage List'; +$lang->stage->create = 'Create Stage'; +$lang->stage->batchCreate = 'Batch Create'; +$lang->stage->edit = 'Edit'; +$lang->stage->delete = 'Delete'; +$lang->stage->view = 'Details'; + +/* Fields. */ +$lang->stage->common = 'Stage'; +$lang->stage->id = 'ID'; +$lang->stage->name = 'Name'; +$lang->stage->type = 'Type'; +$lang->stage->percent = 'Workload %'; +$lang->stage->setType = 'Set Type'; + +$lang->stage->typeList['request'] = 'Story'; +$lang->stage->typeList['design'] = 'Design'; +$lang->stage->typeList['dev'] = 'Development'; +$lang->stage->typeList['qa'] = 'Test'; +$lang->stage->typeList['release'] = 'Release'; +$lang->stage->typeList['review'] = 'Review'; +$lang->stage->typeList['other'] = 'Other'; + +$lang->stage->viewList = 'Stage List'; +$lang->stage->noStage = 'No stage yet'; +$lang->stage->confirmDelete = 'Do you want to delete it?'; diff --git a/module/stage/lang/fr.php b/module/stage/lang/fr.php new file mode 100644 index 0000000000..f11a49dfd9 --- /dev/null +++ b/module/stage/lang/fr.php @@ -0,0 +1,38 @@ + + * @package stage + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +/* Actions. */ +$lang->stage->browse = 'Stage List'; +$lang->stage->create = 'Create Stage'; +$lang->stage->batchCreate = 'Batch Create'; +$lang->stage->edit = 'Edit'; +$lang->stage->delete = 'Delete'; +$lang->stage->view = 'Details'; + +/* Fields. */ +$lang->stage->common = 'Stage'; +$lang->stage->id = 'ID'; +$lang->stage->name = 'Name'; +$lang->stage->type = 'Type'; +$lang->stage->percent = 'Workload %'; +$lang->stage->setType = 'Set Type'; + +$lang->stage->typeList['request'] = 'Story'; +$lang->stage->typeList['design'] = 'Design'; +$lang->stage->typeList['dev'] = 'Development'; +$lang->stage->typeList['qa'] = 'Test'; +$lang->stage->typeList['release'] = 'Release'; +$lang->stage->typeList['review'] = 'Review'; +$lang->stage->typeList['other'] = 'Other'; + +$lang->stage->viewList = 'Stage List'; +$lang->stage->noStage = 'No stage yet'; +$lang->stage->confirmDelete = 'Do you want to delete it?'; diff --git a/module/stage/lang/vi.php b/module/stage/lang/vi.php new file mode 100644 index 0000000000..f11a49dfd9 --- /dev/null +++ b/module/stage/lang/vi.php @@ -0,0 +1,38 @@ + + * @package stage + * @version $Id: en.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +/* Actions. */ +$lang->stage->browse = 'Stage List'; +$lang->stage->create = 'Create Stage'; +$lang->stage->batchCreate = 'Batch Create'; +$lang->stage->edit = 'Edit'; +$lang->stage->delete = 'Delete'; +$lang->stage->view = 'Details'; + +/* Fields. */ +$lang->stage->common = 'Stage'; +$lang->stage->id = 'ID'; +$lang->stage->name = 'Name'; +$lang->stage->type = 'Type'; +$lang->stage->percent = 'Workload %'; +$lang->stage->setType = 'Set Type'; + +$lang->stage->typeList['request'] = 'Story'; +$lang->stage->typeList['design'] = 'Design'; +$lang->stage->typeList['dev'] = 'Development'; +$lang->stage->typeList['qa'] = 'Test'; +$lang->stage->typeList['release'] = 'Release'; +$lang->stage->typeList['review'] = 'Review'; +$lang->stage->typeList['other'] = 'Other'; + +$lang->stage->viewList = 'Stage List'; +$lang->stage->noStage = 'No stage yet'; +$lang->stage->confirmDelete = 'Do you want to delete it?'; diff --git a/module/stage/lang/zh-cn.php b/module/stage/lang/zh-cn.php new file mode 100644 index 0000000000..15980382a7 --- /dev/null +++ b/module/stage/lang/zh-cn.php @@ -0,0 +1,38 @@ + + * @package stage + * @version $Id: zh-cn.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +/* Actions. */ +$lang->stage->browse = '阶段列表'; +$lang->stage->create = '新建'; +$lang->stage->batchCreate = '批量新建'; +$lang->stage->edit = '编辑'; +$lang->stage->delete = '删除'; +$lang->stage->view = '阶段详情'; + +/* Fields. */ +$lang->stage->common = '阶段'; +$lang->stage->id = '编号'; +$lang->stage->name = '阶段名称'; +$lang->stage->type = '阶段分类'; +$lang->stage->percent = '工作量占比'; +$lang->stage->setType = '阶段类型'; + +$lang->stage->typeList['request'] = '需求'; +$lang->stage->typeList['design'] = '设计'; +$lang->stage->typeList['dev'] = '开发'; +$lang->stage->typeList['qa'] = '测试'; +$lang->stage->typeList['release'] = '发布'; +$lang->stage->typeList['review'] = '总结评审'; +$lang->stage->typeList['other'] = '其他'; + +$lang->stage->viewList = '浏览列表'; +$lang->stage->noStage = '暂时没有阶段'; +$lang->stage->confirmDelete = '您确定要执行删除操作吗?'; diff --git a/module/stage/lang/zh-tw.php b/module/stage/lang/zh-tw.php new file mode 100644 index 0000000000..e4e73d5f49 --- /dev/null +++ b/module/stage/lang/zh-tw.php @@ -0,0 +1,38 @@ + + * @package stage + * @version $Id: zh-tw.php 4729 2013-05-03 07:53:55Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +/* Actions. */ +$lang->stage->browse = '階段列表'; +$lang->stage->create = '新建'; +$lang->stage->batchCreate = '批量新建'; +$lang->stage->edit = '編輯'; +$lang->stage->delete = '刪除'; +$lang->stage->view = '階段詳情'; + +/* Fields. */ +$lang->stage->common = '階段'; +$lang->stage->id = '編號'; +$lang->stage->name = '階段名稱'; +$lang->stage->type = '階段分類'; +$lang->stage->percent = '工作量占比'; +$lang->stage->setType = '階段類型'; + +$lang->stage->typeList['request'] = '需求'; +$lang->stage->typeList['design'] = '設計'; +$lang->stage->typeList['dev'] = '開發'; +$lang->stage->typeList['qa'] = '測試'; +$lang->stage->typeList['release'] = '發佈'; +$lang->stage->typeList['review'] = '總結評審'; +$lang->stage->typeList['other'] = '其他'; + +$lang->stage->viewList = '瀏覽列表'; +$lang->stage->noStage = '暫時沒有階段'; +$lang->stage->confirmDelete = '您確定要執行刪除操作嗎?'; diff --git a/module/stage/model.php b/module/stage/model.php new file mode 100644 index 0000000000..9d4bd1e366 --- /dev/null +++ b/module/stage/model.php @@ -0,0 +1,130 @@ + + * @package stage + * @version $Id: model.php 5079 2013-07-10 00:44:34Z chencongzhi520@gmail.com $ + * @link http://www.zentao.net + */ +?> +add('createdBy', $this->app->user->account) + ->add('createdDate', helper::today()) + ->get(); + + $this->dao->insert(TABLE_STAGE)->data($stage)->autoCheck()->exec(); + + if(!dao::isError()) return $this->dao->lastInsertID(); + return false; + } + + /** + * Batch create stages. + * + * @access public + * @return bool + */ + public function batchCreate() + { + $data = fixer::input('post')->get(); + + $this->loadModel('action'); + foreach($data->name as $i => $name) + { + if(!$name) continue; + + $stage = new stdclass(); + $stage->name = $name; + $stage->percent = $data->percent[$i]; + $stage->type = $data->type[$i]; + $stage->createdBy = $this->app->user->account; + $stage->createdDate = helper::today(); + + $this->dao->insert(TABLE_STAGE)->data($stage)->autoCheck()->exec(); + + $stageID = $this->dao->lastInsertID(); + $this->action->create('stage', $stageID, 'Opened'); + } + + return true; + } + + /** + * Update a stage. + * + * @param int $stageID + * @access public + * @return bool + */ + public function update($stageID) + { + $oldStage = $this->dao->select('*')->from(TABLE_STAGE)->where('id')->eq((int)$stageID)->fetch(); + + $stage = fixer::input('post') + ->add('editedBy', $this->app->user->account) + ->add('editedDate', helper::today()) + ->get(); + + $this->dao->update(TABLE_STAGE)->data($stage)->autoCheck()->where('id')->eq((int)$stageID)->exec(); + + if(!dao::isError()) return common::createChanges($oldStage, $stage); + return false; + } + + /** + * Get stages. + * + * @param string $orderBy + * @access public + * @return array + */ + public function getStages($orderBy = 'id_desc') + { + return $this->dao->select('*')->from(TABLE_STAGE)->where('deleted')->eq(0)->orderBy($orderBy)->fetchAll('id'); + } + + /** + * Get pairs of stage. + * + * @access public + * @return array + */ + public function getPairs() + { + $stages = $this->getStages(); + + $pairs = array(); + foreach($stages as $stageID => $stage) + { + $pairs[$stageID] = $stage->name; + } + + return $pairs; + } + + /** + * Get a stage by id. + * + * @param int $stageID + * @access public + * @return object + */ + public function getByID($stageID) + { + return $this->dao->select('*')->from(TABLE_STAGE)->where('deleted')->eq(0)->andWhere('id')->eq((int)$stageID)->fetch(); + } +} diff --git a/module/stage/view/batchcreate.html.php b/module/stage/view/batchcreate.html.php new file mode 100644 index 0000000000..6be8c8f996 --- /dev/null +++ b/module/stage/view/batchcreate.html.php @@ -0,0 +1,46 @@ + + * @package stage + * @version $Id: batchCreate.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + +

+
+

stage->batchCreate;?>

+
+
+ + + + + + + + + + + + + + + + + + + + + + +
stage->id;?>stage->name;?>stage->percent;?>stage->type;?>
stage->typeList, '', "class='form-control chosen'");?>
+ +
+
+
+ diff --git a/module/stage/view/browse.html.php b/module/stage/view/browse.html.php new file mode 100644 index 0000000000..b60412afff --- /dev/null +++ b/module/stage/view/browse.html.php @@ -0,0 +1,73 @@ + + * @package stage + * @version $Id: browse.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + + +
+ +
+

+ stage->noStage;?> + + createLink('stage', 'create'), " " . $lang->stage->create, '', "class='btn btn-info'");?> + +

+
+ +
+
+
+
+ stage->setType);?> + stage->browse, '', "class='selected'");?> +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
stage->id);?>stage->name);?>stage->percent);?>stage->type);?>actions;?>
id;?>name;?>percent;?>stage->typeList, $stage->type);?> + id", "", "list"); + common::printIcon('stage', 'delete', "stageID=$stage->id", "", "list", '', 'hiddenwin'); + ?> +
+
+ +
+ diff --git a/module/stage/view/create.html.php b/module/stage/view/create.html.php new file mode 100644 index 0000000000..3d53f89f39 --- /dev/null +++ b/module/stage/view/create.html.php @@ -0,0 +1,52 @@ + + * @package stage + * @version $Id: create.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + +
+
+
+

stage->create;?>

+
+
+ + + + + + + + + + + + + + + + + + + + + +
stage->name;?>
stage->percent;?> +
+ + % +
+
stage->type;?>stage->typeList, '', "class='form-control chosen'");?>
+ +
+
+
+
+ diff --git a/module/stage/view/edit.html.php b/module/stage/view/edit.html.php new file mode 100644 index 0000000000..05c393bdbb --- /dev/null +++ b/module/stage/view/edit.html.php @@ -0,0 +1,51 @@ + + * @package stage + * @version $Id: edit.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + +
+
+
+

stage->edit;?>

+
+
+ + + + + + + + + + + + + + + + + + + + + +
stage->name;?>name, "class='form-control'");?>
stage->percent;?> +
+ percent, "class='form-control'");?> + % +
+
stage->type;?>stage->typeList, $stage->type, "class='form-control chosen'");?>
+ +
+
+
+ diff --git a/module/stage/view/settype.html.php b/module/stage/view/settype.html.php new file mode 100644 index 0000000000..75d234e5be --- /dev/null +++ b/module/stage/view/settype.html.php @@ -0,0 +1,86 @@ + + * @package stage + * @version $Id: setType.html.php 4903 2013-06-26 05:32:59Z wyd621@gmail.com $ + * @link http://www.zentao.net + */ +?> + + + + + + + + + + + + + +EOT; +?> + +
+
+
+
+
+ stage->setType, '', "class='selected'");?> + stage->browse);?> +
+
+
+
+
+
+ + + + + + + + + + stage->typeList as $key => $value):?> + + + + + + + + + + + +
custom->key;?>custom->value;?>
+ + + + + +
+
+
+
+ +