Merge branch 'master' of https://gitlab.zcorp.cc/easycorp/zentaopms into importExport

This commit is contained in:
tanghucheng
2022-08-04 14:10:36 +08:00
143 changed files with 1544 additions and 762 deletions
+17 -197
View File
@@ -1,204 +1,24 @@
ALTER TABLE `zt_story` ADD COLUMN `linkRequirements` varchar(255) NOT NULL AFTER `linkStories`;
ALTER TABLE `zt_acl` ENGINE='InnoDB';
ALTER TABLE `zt_action` ENGINE='InnoDB';
ALTER TABLE `zt_api_lib_release` ENGINE='InnoDB';
ALTER TABLE `zt_api` ENGINE='InnoDB';
ALTER TABLE `zt_apispec` ENGINE='InnoDB';
ALTER TABLE `zt_apistruct` ENGINE='InnoDB';
ALTER TABLE `zt_apistruct_spec` ENGINE='InnoDB';
ALTER TABLE `zt_approval` ENGINE='InnoDB';
ALTER TABLE `zt_approvalflow` ENGINE='InnoDB';
ALTER TABLE `zt_approvalflowobject` ENGINE='InnoDB';
ALTER TABLE `zt_approvalflowspec` ENGINE='InnoDB';
ALTER TABLE `zt_approvalnode` ENGINE='InnoDB';
ALTER TABLE `zt_approvalobject` ENGINE='InnoDB';
ALTER TABLE `zt_approvalrole` ENGINE='InnoDB';
ALTER TABLE `zt_block` ENGINE='InnoDB';
ALTER TABLE `zt_branch` ENGINE='InnoDB';
ALTER TABLE `zt_bug` ENGINE='InnoDB';
ALTER TABLE `zt_build` ENGINE='InnoDB';
ALTER TABLE `zt_burn` ENGINE='InnoDB';
ALTER TABLE `zt_case` ENGINE='InnoDB';
ALTER TABLE `zt_casestep` ENGINE='InnoDB';
ALTER TABLE `zt_cfd` ENGINE='InnoDB';
ALTER TABLE `zt_company` ENGINE='InnoDB';
ALTER TABLE `zt_compile` ENGINE='InnoDB';
ALTER TABLE `zt_config` ENGINE='InnoDB';
ALTER TABLE `zt_cron` ENGINE='InnoDB';
ALTER TABLE `zt_dept` ENGINE='InnoDB';
ALTER TABLE `zt_design` ENGINE='InnoDB';
ALTER TABLE `zt_designspec` ENGINE='InnoDB';
ALTER TABLE `zt_doc` ENGINE='InnoDB';
ALTER TABLE `zt_doccontent` ENGINE='InnoDB';
ALTER TABLE `zt_doclib` ENGINE='InnoDB';
ALTER TABLE `zt_effort` ENGINE='InnoDB';
ALTER TABLE `zt_entry` ENGINE='InnoDB';
ALTER TABLE `zt_expect` ENGINE='InnoDB';
ALTER TABLE `zt_extension` ENGINE='InnoDB';
ALTER TABLE `zt_file` ENGINE='InnoDB';
ALTER TABLE `zt_group` ENGINE='InnoDB';
ALTER TABLE `zt_grouppriv` ENGINE='InnoDB';
ALTER TABLE `zt_holiday` ENGINE='InnoDB';
ALTER TABLE `zt_history` ENGINE='InnoDB';
ALTER TABLE `zt_job` ENGINE='InnoDB';
ALTER TABLE `zt_kanbanspace` ENGINE='InnoDB';
ALTER TABLE `zt_kanban` ENGINE='InnoDB';
ALTER TABLE `zt_kanbanregion` ENGINE='InnoDB';
ALTER TABLE `zt_kanbancard` ENGINE='InnoDB';
ALTER TABLE `zt_kanbancell` ENGINE='InnoDB';
ALTER TABLE `zt_kanbangroup` ENGINE='InnoDB';
ALTER TABLE `zt_kanbanlane` ENGINE='InnoDB';
ALTER TABLE `zt_kanbancolumn` ENGINE='InnoDB';
ALTER TABLE `zt_lang` ENGINE='InnoDB';
ALTER TABLE `zt_log` ENGINE='InnoDB';
ALTER TABLE `zt_module` ENGINE='InnoDB';
ALTER TABLE `zt_mr` ENGINE='InnoDB';
ALTER TABLE `zt_mrapproval` ENGINE='InnoDB';
ALTER TABLE `zt_notify` ENGINE='InnoDB';
ALTER TABLE `zt_oauth` ENGINE='InnoDB';
ALTER TABLE `zt_pipeline` ENGINE='InnoDB';
ALTER TABLE `zt_planstory` ENGINE='InnoDB';
ALTER TABLE `zt_product` ENGINE='InnoDB';
ALTER TABLE `zt_productplan` ENGINE='InnoDB';
ALTER TABLE `zt_project` ENGINE='InnoDB';
ALTER TABLE `zt_projectadmin` ENGINE='InnoDB';
ALTER TABLE `zt_projectcase` ENGINE='InnoDB';
ALTER TABLE `zt_projectproduct` ENGINE='InnoDB';
ALTER TABLE `zt_projectspec` ENGINE='InnoDB';
ALTER TABLE `zt_projectstory` ENGINE='InnoDB';
ALTER TABLE `zt_relation` ENGINE='InnoDB';
ALTER TABLE `zt_release` ENGINE='InnoDB';
ALTER TABLE `zt_repo` ENGINE='InnoDB';
ALTER TABLE `zt_repobranch` ENGINE='InnoDB';
ALTER TABLE `zt_repofiles` ENGINE='InnoDB';
ALTER TABLE `zt_repohistory` ENGINE='InnoDB';
ALTER TABLE `zt_score` ENGINE='InnoDB';
ALTER TABLE `zt_searchdict` ENGINE='InnoDB';
ALTER TABLE `zt_stage` ENGINE='InnoDB';
ALTER TABLE `zt_stakeholder` ENGINE='InnoDB';
ALTER TABLE `zt_story` ENGINE='InnoDB';
ALTER TABLE `zt_storyreview` ENGINE='InnoDB';
ALTER TABLE `zt_storyestimate` ENGINE='InnoDB';
ALTER TABLE `zt_storyspec` ENGINE='InnoDB';
ALTER TABLE `zt_storystage` ENGINE='InnoDB';
ALTER TABLE `zt_suitecase` ENGINE='InnoDB';
ALTER TABLE `zt_task` ENGINE='InnoDB';
ALTER TABLE `zt_taskestimate` ENGINE='InnoDB';
ALTER TABLE `zt_taskspec` ENGINE='InnoDB';
ALTER TABLE `zt_team` ENGINE='InnoDB';
ALTER TABLE `zt_testreport` ENGINE='InnoDB';
ALTER TABLE `zt_testresult` ENGINE='InnoDB';
ALTER TABLE `zt_testrun` ENGINE='InnoDB';
ALTER TABLE `zt_testsuite` ENGINE='InnoDB';
ALTER TABLE `zt_testtask` ENGINE='InnoDB';
ALTER TABLE `zt_todo` ENGINE='InnoDB';
ALTER TABLE `zt_user` ENGINE='InnoDB';
ALTER TABLE `zt_usercontact` ENGINE='InnoDB';
ALTER TABLE `zt_usergroup` ENGINE='InnoDB';
ALTER TABLE `zt_userquery` ENGINE='InnoDB';
ALTER TABLE `zt_usertpl` ENGINE='InnoDB';
ALTER TABLE `zt_userview` ENGINE='InnoDB';
ALTER TABLE `zt_weeklyreport` ENGINE='InnoDB';
ALTER TABLE `zt_webhook` ENGINE='InnoDB';
ALTER TABLE `zt_im_chat` ENGINE='InnoDB';
ALTER TABLE `zt_im_chatuser` ENGINE='InnoDB';
ALTER TABLE `zt_im_client` ENGINE='InnoDB';
ALTER TABLE `zt_im_message` ENGINE='InnoDB';
ALTER TABLE `zt_im_message_backup` ENGINE='InnoDB';
ALTER TABLE `zt_im_message_index` ENGINE='InnoDB';
ALTER TABLE `zt_im_chat_message_index` ENGINE='InnoDB';
ALTER TABLE `zt_im_messagestatus` ENGINE='InnoDB';
ALTER TABLE `zt_im_queue` ENGINE='InnoDB';
ALTER TABLE `zt_im_conference` ENGINE='InnoDB';
ALTER TABLE `zt_im_conferenceaction` ENGINE='InnoDB';
ALTER TABLE `zt_im_userdevice` ENGINE='InnoDB';
ALTER TABLE `zt_relationoftasks` ENGINE='InnoDB';
ALTER TABLE `zt_report` ENGINE='InnoDB';
ALTER TABLE `zt_feedback` ENGINE='InnoDB';
ALTER TABLE `zt_feedbackview` ENGINE='InnoDB';
ALTER TABLE `zt_serverroom` ENGINE='InnoDB';
ALTER TABLE `zt_account` ENGINE='InnoDB';
ALTER TABLE `zt_asset` ENGINE='InnoDB';
ALTER TABLE `zt_host` ENGINE='InnoDB';
ALTER TABLE `zt_service` ENGINE='InnoDB';
ALTER TABLE `zt_attend` ENGINE='InnoDB';
ALTER TABLE `zt_attendstat` ENGINE='InnoDB';
ALTER TABLE `zt_overtime` ENGINE='InnoDB';
ALTER TABLE `zt_holiday` ENGINE='InnoDB';
ALTER TABLE `zt_leave` ENGINE='InnoDB';
ALTER TABLE `zt_lieu` ENGINE='InnoDB';
ALTER TABLE `zt_trip` ENGINE='InnoDB';
ALTER TABLE `zt_deploy` ENGINE='InnoDB';
ALTER TABLE `zt_deployproduct` ENGINE='InnoDB';
ALTER TABLE `zt_deploystep` ENGINE='InnoDB';
ALTER TABLE `zt_deployscope` ENGINE='InnoDB';
ALTER TABLE `zt_vm` ENGINE='InnoDB';
ALTER TABLE `zt_baseimage` ENGINE='InnoDB';
ALTER TABLE `zt_vmtemplate` ENGINE='InnoDB';
ALTER TABLE `zt_browser` ENGINE='InnoDB';
ALTER TABLE `zt_baseimagebrowser` ENGINE='InnoDB';
ALTER TABLE `zt_traincourse` ENGINE='InnoDB';
ALTER TABLE `zt_traincontents` ENGINE='InnoDB';
ALTER TABLE `zt_traincategory` ENGINE='InnoDB';
ALTER TABLE `zt_trainrecords` ENGINE='InnoDB';
ALTER TABLE `zt_faq` ENGINE='InnoDB';
ALTER TABLE `zt_domain` ENGINE='InnoDB';
ALTER TABLE `zt_workflow` ENGINE='InnoDB';
ALTER TABLE `zt_workflowaction` ENGINE='InnoDB';
ALTER TABLE `zt_workflowdatasource` ENGINE='InnoDB';
ALTER TABLE `zt_workflowfield` ENGINE='InnoDB';
ALTER TABLE `zt_workflowlayout` ENGINE='InnoDB';
ALTER TABLE `zt_workflowlabel` ENGINE='InnoDB';
ALTER TABLE `zt_workflowlinkdata` ENGINE='InnoDB';
ALTER TABLE `zt_workflowrelation` ENGINE='InnoDB';
ALTER TABLE `zt_workflowrelationlayout` ENGINE='InnoDB';
ALTER TABLE `zt_workflowrule` ENGINE='InnoDB';
ALTER TABLE `zt_workflowsql` ENGINE='InnoDB';
ALTER TABLE `zt_workflowversion` ENGINE='InnoDB';
ALTER TABLE `zt_workflowreport` ENGINE='InnoDB';
ALTER TABLE `zt_durationestimation` ENGINE='InnoDB';
ALTER TABLE `zt_workestimation` ENGINE='InnoDB';
ALTER TABLE `zt_intervention` ENGINE='InnoDB';
ALTER TABLE `zt_activity` ENGINE='InnoDB';
ALTER TABLE `zt_auditcl` ENGINE='InnoDB';
ALTER TABLE `zt_auditplan` ENGINE='InnoDB';
ALTER TABLE `zt_auditresult` ENGINE='InnoDB';
ALTER TABLE `zt_nc` ENGINE='InnoDB';
ALTER TABLE `zt_zoutput` ENGINE='InnoDB';
ALTER TABLE `zt_process` ENGINE='InnoDB';
ALTER TABLE `zt_programactivity` ENGINE='InnoDB';
ALTER TABLE `zt_programoutput` ENGINE='InnoDB';
ALTER TABLE `zt_programprocess` ENGINE='InnoDB';
ALTER TABLE `zt_basicmeas` ENGINE='InnoDB';
ALTER TABLE `zt_budget` ENGINE='InnoDB';
ALTER TABLE `zt_researchplan` ENGINE='InnoDB';
ALTER TABLE `zt_researchreport` ENGINE='InnoDB';
ALTER TABLE `zt_meeting` ENGINE='InnoDB';
ALTER TABLE `zt_meetingroom` ENGINE='InnoDB';
ALTER TABLE `zt_assetlib` ENGINE='InnoDB';
ALTER TABLE `zt_meastemplate` ENGINE='InnoDB';
ALTER TABLE `zt_programreport` ENGINE='InnoDB';
ALTER TABLE `zt_measrecords` ENGINE='InnoDB';
ALTER TABLE `zt_object` ENGINE='InnoDB';
ALTER TABLE `zt_review` ENGINE='InnoDB';
ALTER TABLE `zt_reviewcl` ENGINE='InnoDB';
ALTER TABLE `zt_reviewresult` ENGINE='InnoDB';
ALTER TABLE `zt_reviewissue` ENGINE='InnoDB';
ALTER TABLE `zt_reviewlist` ENGINE='InnoDB';
ALTER TABLE `zt_cmcl` ENGINE='InnoDB';
ALTER TABLE `zt_solutions` ENGINE='InnoDB';
ALTER TABLE `zt_measqueue` ENGINE='InnoDB';
ALTER TABLE `zt_issue` ENGINE='InnoDB';
ALTER TABLE `zt_risk` ENGINE='InnoDB';
ALTER TABLE `zt_riskissue` ENGINE='InnoDB';
ALTER TABLE `zt_opportunity` ENGINE='InnoDB';
ALTER TABLE `zt_trainplan` ENGINE='InnoDB';
ALTER TABLE `zt_gapanalysis` ENGINE='InnoDB';
ALTER TABLE `zt_sqlview` ENGINE='InnoDB';
ALTER TABLE `zt_searchindex` ADD FULLTEXT `title_content` (`title`, `content`);
ALTER TABLE `zt_searchindex` DROP INDEX `title`;
ALTER TABLE `zt_searchindex` DROP INDEX `content`;
ALTER TABLE `zt_productplan` ADD `createdBy` varchar(30) NOT NULL AFTER `closedReason`;
ALTER TABLE `zt_productplan` ADD `createdDate` datetime NOT NULL AFTER `createdBy`;
ALTER TABLE `zt_release` ADD `createdBy` varchar(30) NOT NULL AFTER `subStatus`;
ALTER TABLE `zt_release` ADD `createdDate` datetime NOT NULL AFTER `createdBy`;
ALTER TABLE `zt_testtask` ADD `createdBy` varchar(30) NOT NULL AFTER `subStatus`;
ALTER TABLE `zt_testtask` ADD `createdDate` datetime NOT NULL AFTER `createdBy`;
INSERT IGNORE INTO `zt_workflowfield` (`module`, `field`, `type`, `length`, `name`, `control`, `expression`, `options`, `default`, `rules`, `placeholder`, `order`, `searchOrder`, `exportOrder`, `canExport`, `canSearch`, `isValue`, `readonly`, `buildin`, `role`, `desc`, `createdBy`, `createdDate`, `editedBy`, `editedDate`) VALUES
('testtask', 'createdBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 393, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
('testtask', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 394, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
('productplan', 'createdBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 11, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
('productplan', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 12, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
('release', 'createdBy', 'varchar', '30', '由谁创建', 'select', '', 'user', '', '', '', 14, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00'),
('release', 'createdDate', 'datetime', '', '创建时间', 'datetime', '', '', '', '', '', 15, 0, 0, '0', '0', '0', '1', 1, 'buildin', '', '', '2022-08-02 14:49', '', '0000-00-00 00:00:00');
UPDATE `zt_project` SET `closedDate`='' AND `closedBy`='' WHERE `status` != 'closed';
+7 -2
View File
@@ -1091,6 +1091,8 @@ CREATE TABLE IF NOT EXISTS `zt_productplan` (
`end` date NOT NULL,
`order` text NOT NULL,
`closedReason` varchar(20) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `product` (`product`),
@@ -1242,6 +1244,8 @@ CREATE TABLE IF NOT EXISTS `zt_release` (
`notify` varchar(255),
`status` varchar(20) NOT NULL default 'normal',
`subStatus` varchar(30) NOT NULL default '',
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `product` (`product`),
@@ -1348,8 +1352,7 @@ CREATE TABLE IF NOT EXISTS `zt_searchindex` (
PRIMARY KEY (`id`),
UNIQUE KEY `object` (`objectType`,`objectID`),
KEY `addedDate` (`addedDate`),
FULLTEXT KEY `content` (`content`),
FULLTEXT KEY `title` (`title`)
FULLTEXT KEY `title_content` (`title`, `content`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_stage`;
CREATE TABLE IF NOT EXISTS `zt_stage` (
@@ -1671,6 +1674,8 @@ CREATE TABLE IF NOT EXISTS `zt_testtask` (
`testreport` mediumint(8) unsigned NOT NULL,
`auto` varchar(10) NOT NULL DEFAULT 'no',
`subStatus` varchar(30) NOT NULL default '',
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`),
KEY `product` (`product`),
+7
View File
@@ -82,6 +82,13 @@
33530 资产机会库机会列表页面审批字段居左显示
33823 问题指派页面增加备注
34097 修改执行QA不符合项详情页面中解决图标
34729 QA质量保证计划可以批量编辑
30071 项目甘特图中增加任务名称的显示
28556 瀑布项目中计划的甘特图支持按日/周/月维度查看
29700 项目甘特图中的任务支持点击查看详情
29944 项目甘特图中支持显示阶段和任务的负责人
34795 项目甘特图可以在阶段或任务前增加图标显示状态
34742 项目甘特图中没有起止日期的任务的时间显示为所属阶段时间
禅道客户端:
34124 XXD可以从XXB主动拉取配置
34123 喧喧增加禅道的checktable.php以便自动修复数据库
+2 -9
View File
@@ -996,14 +996,7 @@ class baseRouter
if($writable)
{
$ztSessionHandler = new ztSessionHandler($_GET['tid']);
session_set_save_handler(
array($ztSessionHandler, "open"),
array($ztSessionHandler, "close"),
array($ztSessionHandler, "read"),
array($ztSessionHandler, "write"),
array($ztSessionHandler, "destroy"),
array($ztSessionHandler, "gc")
);
session_set_save_handler($ztSessionHandler, true);
}
}
@@ -3107,7 +3100,7 @@ class EndResponseException extends \Exception
*
* @package framework
*/
class ztSessionHandler
class ztSessionHandler implements SessionHandlerInterface
{
public $sessSavePath;
public $tagID;
+22 -3
View File
@@ -157,6 +157,21 @@ class model extends baseModel
}
if(empty($relations)) $relations = $this->dao->select('next, actions')->from(TABLE_WORKFLOWRELATION)->where('prev')->eq($moduleName)->fetchPairs();
$this->loadModel('flow');
$approvalProgressMenu = '';
if($type == 'view' && !empty($this->config->openedApproval) && commonModel::hasPriv('approval', 'progress'))
{
$flow = $this->loadModel('workflow', 'flow')->getByModule($moduleName);
if($flow->approval == 'enabled')
{
$approvalID = isset($data->approval) ? $data->approval : 0;
$extraClass = strpos(',testsuite,build,release,productplan,', ",{$moduleName},") !== false ? 'btn-link' : '';
$approvalProgressMenu .= "<div class='divider'></div>";
$approvalProgressMenu .= baseHTML::a(helper::createLink('approval', 'progress', "approvalID={$approvalID}", '', true), $this->lang->flow->approvalProgress, "class='btn {$extraClass} iframe'");
}
}
$menu = '';
if($show)
{
@@ -164,8 +179,10 @@ class model extends baseModel
{
if(strpos($action->position, $type) === false || $action->show != $show) continue;
$menu .= $this->loadModel('flow')->buildActionMenu($moduleName, $action, $data, $type, $relations);
$menu .= $this->flow->buildActionMenu($moduleName, $action, $data, $type, $relations);
}
if($approvalProgressMenu) $menu .= $approvalProgressMenu;
}
else
{
@@ -174,10 +191,12 @@ class model extends baseModel
{
if(strpos($action->position, $type) === false) continue;
if($type == 'view' || $action->show == 'direct') $menu .= $this->loadModel('flow')->buildActionMenu($moduleName, $action, $data, $type, $relations);
if($type == 'browse' && $action->show == 'dropdownlist') $dropdownMenu .= $this->loadModel('flow')->buildActionMenu($moduleName, $action, $data, $type, $relations);
if($type == 'view' || $action->show == 'direct') $menu .= $this->flow->buildActionMenu($moduleName, $action, $data, $type, $relations);
if($type == 'browse' && $action->show == 'dropdownlist') $dropdownMenu .= $this->flow->buildActionMenu($moduleName, $action, $data, $type, $relations);
}
if($approvalProgressMenu) $menu .= $approvalProgressMenu;
if($type == 'browse' && $dropdownMenu)
{
$menu .= "<div class='dropdown'><a href='javascript:;' data-toggle='dropdown'>{$this->lang->more}<span class='caret'> </span></a>";
+9 -8
View File
@@ -599,7 +599,7 @@ class block extends control
{
$limit = ($this->viewType == 'json' or !isset($this->params->count)) ? 0 : (int)$this->params->count;
$todos = $this->loadModel('todo')->getList('all', $this->app->user->account, 'wait, doing', $limit, $pager = null, $orderBy = 'date, begin');
$uri = $this->app->getURI(true);
$uri = $this->createLink('my', 'index');
$this->session->set('todoList', $uri, 'my');
$this->session->set('bugList', $uri, 'qa');
@@ -629,7 +629,7 @@ class block extends control
*/
public function printTaskBlock()
{
$this->session->set('taskList', $this->app->getURI(true), 'execution');
$this->session->set('taskList', $this->createLink('my', 'index'), 'execution');
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$account = $this->app->user->account;
@@ -647,7 +647,7 @@ class block extends control
*/
public function printBugBlock()
{
$this->session->set('bugList', $this->app->getURI(true), 'qa');
$this->session->set('bugList', $this->createLink('my', 'index'), 'qa');
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$projectID = $this->lang->navGroup->qa == 'project' ? $this->session->project : 0;
@@ -663,7 +663,7 @@ class block extends control
*/
public function printCaseBlock()
{
$this->session->set('caseList', $this->app->getURI(true), 'qa');
$this->session->set('caseList', $this->createLink('my', 'index'), 'qa');
$this->app->loadLang('testcase');
$this->app->loadLang('testtask');
@@ -708,9 +708,10 @@ class block extends control
{
$this->app->loadLang('testtask');
$this->session->set('productList', $this->app->getURI(true), 'product');
$this->session->set('testtaskList', $this->app->getURI(true), 'qa');
$this->session->set('buildList', $this->app->getURI(true), 'execution');
$uri = $this->createLink('my', 'index');
$this->session->set('productList', $uri, 'product');
$this->session->set('testtaskList', $uri, 'qa');
$this->session->set('buildList', $uri, 'execution');
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$this->view->testtasks = $this->dao->select('distinct t1.*,t2.name as productName,t3.name as buildName,t4.name as projectName')->from(TABLE_TESTTASK)->alias('t1')
@@ -736,7 +737,7 @@ class block extends control
*/
public function printStoryBlock()
{
$this->session->set('storyList', $this->app->getURI(true), 'product');
$this->session->set('storyList', $this->createLink('my', 'index'), 'product');
if(preg_match('/[^a-zA-Z0-9_]/', $this->params->type)) return;
$this->app->loadClass('pager', $static = true);
+7 -2
View File
@@ -59,7 +59,7 @@ $useGuest = $this->app->user->account == 'guest';
<?php if($hasHeading):?>
</div>
<?php endif;?>
<?php echo $this->fetch('block', 'printBlock', "id=$block->id&module=$module")?>
<div class='panel-body scrollbar-hover'></div>
</div>
<?php endforeach;?>
</div>
@@ -94,7 +94,7 @@ $useGuest = $this->app->user->account == 'guest';
<?php if($hasHeading):?>
</div>
<?php endif;?>
<?php echo $this->fetch('block', 'printBlock', "id=$block->id&module=$module")?>
<div class='panel-body scrollbar-hover'></div>
</div>
<?php endforeach;?>
</div>
@@ -136,6 +136,11 @@ $(function()
});
}
setTimeout(checkRemind, 1000);
$('#dashboard .row .panel').each(function()
{
refreshBlock($(this));
})
});
</script>
<?php if($extView = $this->getExtViewFile(__FILE__)){include $extView; return helper::cd();}?>
+33
View File
@@ -401,6 +401,7 @@ class bugModel extends model
elseif($browseType == 'bysearch') $bugs = $this->getBySearch($productIDList, $branch, $queryID, $sort, '', $pager, $projectID);
elseif($browseType == 'overduebugs') $bugs = $this->getOverdueBugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'assignedbyme') $bugs = $this->getByAssignedbyme($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
elseif($browseType == 'review') $bugs = $this->getReviewBugs($productIDList, $branch, $modules, $executions, $sort, $pager, $projectID);
return $this->checkDelayedBugs($bugs);
}
@@ -2902,6 +2903,38 @@ class bugModel extends model
return $bugs;
}
/**
* Get bugs to review.
*
* @param array $productIDList
* @param int|string $branch
* @param array $modules
* @param array $executions
* @param string $orderBy
* @param object $pager
* @param int $projectID
* @access public
* @return array
*/
public function getReviewBugs($productIDList, $branch, $modules, $executions, $orderBy, $pager = null, $projectID = 0)
{
$bugs = $this->dao->select('t1.*, t2.title as planTitle')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id')
->where('t1.product')->in($productIDList)
->andWhere('t1.execution')->in(array_keys($executions))
->beginIF($branch !== 'all')->andWhere('t1.branch')->eq($branch)->fi()
->beginIF($modules)->andWhere('t1.module')->in($modules)->fi()
->beginIF($projectID)->andWhere('t1.project')->eq($projectID)->fi()
->andWhere('t1.deleted')->eq(0)
->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")
->beginIF(!$this->app->user->admin)->andWhere('t1.project')->in('0,' . $this->app->user->view->projects)->fi()
->orderBy($orderBy)->page($pager)->fetchAll();
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug');
return $bugs;
}
/**
* Get bug query.
*
+1
View File
@@ -37,6 +37,7 @@ $currentBrowseType = isset($lang->bug->mySelects[$browseType]) && in_array($brow
</div>
<div class="btn-toolbar pull-left">
<?php
common::sortFeatureMenu();
$menus = customModel::getFeatureMenu($this->moduleName, $this->methodName);
foreach($menus as $menuItem)
{
+2
View File
@@ -68,3 +68,5 @@ $lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, erstellt von <strong>$actor</strong>, Build <strong>$extra</strong>.' . "\n";
$lang->backhome = 'zurück';
$lang->build->featureBar['browse']['all'] = 'Build List';
+2
View File
@@ -68,3 +68,5 @@ $lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, created by <strong>$actor</strong>, Build <strong>$extra</strong>.' . "\n";
$lang->backhome = 'back';
$lang->build->featureBar['browse']['all'] = 'Build List';
+2
View File
@@ -68,3 +68,5 @@ $lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, Build <strong>$extra</strong> créé par <strong>$actor</strong>.' . "\n";
$lang->backhome = 'Retour';
$lang->build->featureBar['browse']['all'] = 'Build List';
+2
View File
@@ -64,3 +64,5 @@ $lang->build->action = new stdclass();
$lang->build->action->buildopened = '$date, được tạo bởi <strong>$actor</strong>, Bản dựng <strong>$extra</strong>.' . "\n";
$lang->backhome = 'Trở lại';
$lang->build->featureBar['browse']['all'] = 'Build List';
+2
View File
@@ -72,6 +72,7 @@ class buildModel extends model
->beginIF($projectID)->andWhere('t1.project')->eq((int)$projectID)->fi()
->beginIF($type == 'product' and $param)->andWhere('t1.product')->eq($param)->fi()
->beginIF($type == 'bysearch')->andWhere($param)->fi()
->beginIF($type == 'review')->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
@@ -136,6 +137,7 @@ class buildModel extends model
->beginIF($executionID)->andWhere('t1.execution')->eq((int)$executionID)->fi()
->beginIF($type == 'product' and $param)->andWhere('t1.product')->eq($param)->fi()
->beginIF($type == 'bysearch')->andWhere($param)->fi()
->beginIF($type == 'review')->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
+3
View File
@@ -44,3 +44,6 @@ $lang->caselib->legendDesc = 'Description';
$lang->caselib->libraryDelete = 'Do you want to delete this library?';
$lang->caselib->noModule = '<div>You have no modules.</div><div>Manage it now.</div>';
$lang->caselib->featureBar['browse']['all'] = 'All';
$lang->caselib->featureBar['browse']['wait'] = 'Waiting';
+3
View File
@@ -44,3 +44,6 @@ $lang->caselib->legendDesc = 'Description';
$lang->caselib->libraryDelete = 'Do you want to delete this library?';
$lang->caselib->noModule = '<div>You have no modules.</div><div>Manage it now.</div>';
$lang->caselib->featureBar['browse']['all'] = 'All';
$lang->caselib->featureBar['browse']['wait'] = 'Waiting';
+3
View File
@@ -44,3 +44,6 @@ $lang->caselib->legendDesc = 'Description';
$lang->caselib->libraryDelete = 'Voulez vous supprimer cette library ?';
$lang->caselib->noModule = "<div>Vous n'avez aucun modules.</div><div>Gérer les modules maintenant.</div>";
$lang->caselib->featureBar['browse']['all'] = 'All';
$lang->caselib->featureBar['browse']['wait'] = 'Waiting';
+3
View File
@@ -39,3 +39,6 @@ $lang->caselib->legendDesc = 'Mô tả';
$lang->caselib->libraryDelete = 'Bạn có muốn xóa thư viện này?';
$lang->caselib->noModule = '<div>Chưa có Module.</div><div>Quản lý ngay.</div>';
$lang->caselib->featureBar['browse']['all'] = 'All';
$lang->caselib->featureBar['browse']['wait'] = 'Waiting';
+3
View File
@@ -44,3 +44,6 @@ $lang->caselib->legendDesc = '描述';
$lang->caselib->libraryDelete = '您确认要删除该用例库吗?';
$lang->caselib->noModule = '<div>您现在还没有模块信息</div><div>请维护用例库模块</div>';
$lang->caselib->featureBar['browse']['all'] = '所有';
$lang->caselib->featureBar['browse']['wait'] = '待评审';
+2 -1
View File
@@ -220,13 +220,14 @@ class caselibModel extends model
$browseType = ($browseType == 'bymodule' and $this->session->libBrowseType and $this->session->libBrowseType != 'bysearch') ? $this->session->libBrowseType : $browseType;
$cases = array();
if($browseType == 'bymodule' or $browseType == 'all' or $browseType == 'wait')
if($browseType == 'bymodule' or $browseType == 'all' or $browseType == 'wait' or $browseType == 'review')
{
$cases = $this->dao->select('*')->from(TABLE_CASE)
->where('lib')->eq((int)$libID)
->andWhere('product')->eq(0)
->beginIF($moduleIdList)->andWhere('module')->in($moduleIdList)->fi()
->beginIF($browseType == 'wait')->andWhere('status')->eq($browseType)->fi()
->beginIF($browseType == 'review')->andWhere("FIND_IN_SET('{$this->app->user->account}', `reviewers`)")->fi()
->andWhere('deleted')->eq('0')
->orderBy($sort)->page($pager)->fetchAll('id');
}
+5 -3
View File
@@ -40,10 +40,12 @@ js::set('flow', $config->global->flow);
</div>
<div class='btn-toolbar pull-left'>
<?php
if(common::hasPriv('caselib', 'browse'))
common::sortFeatureMenu();
if(!$config->testcase->needReview && empty($config->testcase->forceReview)) unset($lang->caselib->featureBar['browse']['wait']);
foreach($lang->caselib->featureBar['browse'] as $featureType => $label)
{
echo html::a($this->inlink('browse', "libID=$libID&browseType=all"), "<span class='text'>{$lang->testcase->allCases}</span>", '', "id='allTab' class='btn btn-link'");
if($config->testcase->needReview or !empty($config->testcase->forceReview)) echo html::a($this->inlink('browse', "libID=$libID&browseType=wait"), "<span class='text'>" . $lang->testcase->statusList['wait'] . "</span>", '', "id='waitTab' class='btn btn-link'");
$activeClass = $browseType == $featureType ? 'btn-active-text' : '';
echo html::a(inlink('browse', "libID=$libID&browseType=$featureType"), "<span class='text'>$label</span>", '',"class='btn btn-link $activeClass' data-app={$app->tab} id=" . $featureType .'Tab');
}
?>
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->testcase->bySearch;?></a>
+12 -10
View File
@@ -149,16 +149,18 @@ class ci extends control
->fetch();
$testtask = new stdclass();
$testtask->product = $productID;
$testtask->name = !empty($post->name) ? $post->name : sprintf($this->lang->testtask->titleOfAuto, date('Y-m-d H:i:s'));
$testtask->owner = $this->app->user->account;
$testtask->project = $lastProject->project;
$testtask->execution = $lastProject->id;
$testtask->build = 'trunk';
$testtask->auto = strtolower($testType);
$testtask->begin = date('Y-m-d');
$testtask->end = date('Y-m-d', time() + 24 * 3600);
$testtask->status = 'done';
$testtask->product = $productID;
$testtask->name = !empty($post->name) ? $post->name : sprintf($this->lang->testtask->titleOfAuto, date('Y-m-d H:i:s'));
$testtask->owner = $this->app->user->account;
$testtask->project = $lastProject->project;
$testtask->execution = $lastProject->id;
$testtask->build = 'trunk';
$testtask->auto = strtolower($testType);
$testtask->begin = date('Y-m-d');
$testtask->end = date('Y-m-d', time() + 24 * 3600);
$testtask->status = 'done';
$testtask->createdBy = $this->app->user->account;
$testtask->createdDate = helper::now();
$this->dao->insert(TABLE_TESTTASK)->data($testtask)->exec();
$taskID = $this->dao->lastInsertId();
+39
View File
@@ -3373,6 +3373,45 @@ EOD;
return $Parsedown->text($markdown);
}
/**
* Sort featureBar.
*
* @param string $module
* @param string $method
* @static
* @access public
* @return bool
*/
public static function sortFeatureMenu($module = '', $method = '')
{
global $lang, $app;
$module = $module ? $module : $app->rawModule;
$method = $method ? $method : $app->rawMethod;
/* It will be sorted according to the workflow in the future */
if(!empty($lang->featureBarSort[$module][$method]))
{
$featureBar = array();
if(empty($lang->$module->featureBar[$method])) return false;
foreach($lang->$module->featureBar[$method] as $key => $label)
{
foreach($lang->featureBarSort[$module][$method] as $currentKey => $afterKey)
{
if($key == $currentKey) continue;
$featureBar[$method][$key] = $label;
if($key == $afterKey && !empty($lang->$module->featureBar[$method][$currentKey]))
{
$featureBar[$method][$currentKey] = $lang->$module->featureBar[$method][$currentKey];
}
}
}
$lang->$module->featureBar = $featureBar;
}
return true;
}
}
class common extends commonModel
+6 -2
View File
@@ -385,7 +385,9 @@ class redmine11ConvertModel extends redmineConvertModel
/* Insert into zentao */
foreach($productPlans as $id => $productPlan)
{
$productPlan->product = $this->map['products'][$productPlan->execution_id];
$productPlan->product = $this->map['products'][$productPlan->execution_id];
$productPlan->createdBy = $this->app->user->account;
$productPlan->createdDate = helper::now();
unset($productPlan->id);
unset($productPlan->execution_id);
$this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec();
@@ -395,7 +397,9 @@ class redmine11ConvertModel extends redmineConvertModel
foreach($this->map['products'] as $productID)
{
$productPlan = $this->dao->dbh($this->dbh)->select("name as title, createdDate as begin")->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch();
$productPlan->product = $productID;
$productPlan->product = $productID;
$productPlan->createdBy = $this->app->user->account;
$productPlan->createdDate = helper::now();
$this->dao->dbh($this->dbh)->insert(TABLE_PRODUCTPLAN)->data($productPlan)->exec();
$this->map['planOfProduct'][$productID] = $this->dao->lastinsertID();
}
+8 -6
View File
@@ -989,12 +989,14 @@ class convertModel extends model
if(empty($data->RELEASEDATE)) continue;
$release = new stdclass();
$release->product = $build->product;
$release->build = $buildID;
$release->name = $build->name;
$release->date = $build->date;
$release->desc = $data->DESCRIPTION;
$release->status = 'normal';
$release->product = $build->product;
$release->build = $buildID;
$release->name = $build->name;
$release->date = $build->date;
$release->desc = $data->DESCRIPTION;
$release->status = 'normal';
$release->createdBy = $this->app->user->account;
$release->createdDate = helper::now();
$this->dao->dbh($this->dbh)->insert(TABLE_RELEASE)->data($release)->exec();
$releaseID = $this->dao->dbh($this->dbh)->lastInsertID();
+3 -4
View File
@@ -1,10 +1,9 @@
body {margin-bottom: 25px;}
.main-table tbody>tr>td {border-bottom: 0px solid #eee;}
.table-responsive {overflow-y: hidden !important;}
#product_chosen .chosen-single {width: 180px;}
.table-children {border-left: 2px solid #cbd0db; border-right: 2px solid #cbd0db;}
.table tbody > tr.table-children.table-child-top {border-top: 2px solid #cbd0db;}
.table tbody > tr.table-children.table-child-bottom {border-bottom: 2px solid #cbd0db;}
.table td.has-child > a:not(.plan-toggle) {max-width: 90%; max-width: calc(100% - 30px); display: inline-block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
.table td.has-child > .plan-toggle {color: #838a9d; position: relative; top: 1px;overflow: initial !important;}
.table td.has-child > .plan-toggle:hover {color: #006af1; cursor: pointer;}
@@ -14,7 +13,7 @@ body {margin-bottom: 25px;}
.table th.hours {padding-right: 8px !important;}
.main-table tbody > tr.table-children > td:first-child::before {width: 3px;}
td.hours {text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
td.flex {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center; margin-bottom: -1px;}
td.flex {display: flex; flex-flow: row nowrap; justify-content: flex-start; align-items: center; margin-bottom: 0px;}
td.datatable-cell.flex {margin-bottom: -2px;}
td.flex span.label-badge {margin-left: 5px; min-width: 50px;}
td.flex span.label-badge.label-light {min-width: 22px;}
@@ -32,7 +31,7 @@ td.flex span.project-type-label {min-width: 40px;}
.c-project{text-overflow: unset !important;}
canvas {height: 28px;}
.parent.has-child.c-name.flex, .table-child-bottom > .c-name.flex {border-bottom: 1px solid #cbd0db !important;}
.parent.has-child.c-name.flex, .table-child-bottom > .c-name.flex {border-bottom: 0px solid #cbd0db !important;}
.parent.has-child.c-name.flex {margin-bottom: -2px !important;}
#tableCustomBtn {padding-bottom: 5px;}
#bysearchTab {margin-left: 5px;}
+2
View File
@@ -514,6 +514,8 @@ $lang->execution->featureBar['all']['doing'] = $lang->execution->statusList[
$lang->execution->featureBar['all']['suspended'] = $lang->execution->statusList['suspended'];
$lang->execution->featureBar['all']['closed'] = $lang->execution->statusList['closed'];
$lang->execution->featureBar['build']['all'] = 'Build List';
$lang->execution->myExecutions = 'Ich bin beteiligt.';
$lang->execution->doingProject = 'Laufende Projekte';
+2
View File
@@ -514,6 +514,8 @@ $lang->execution->featureBar['all']['doing'] = $lang->execution->statusList[
$lang->execution->featureBar['all']['suspended'] = $lang->execution->statusList['suspended'];
$lang->execution->featureBar['all']['closed'] = $lang->execution->statusList['closed'];
$lang->execution->featureBar['build']['all'] = 'Build List';
$lang->execution->myExecutions = 'Mine';
$lang->execution->doingProject = 'Ongoing Projects';
+2
View File
@@ -514,6 +514,8 @@ $lang->execution->featureBar['all']['doing'] = $lang->execution->statusList[
$lang->execution->featureBar['all']['suspended'] = $lang->execution->statusList['suspended'];
$lang->execution->featureBar['all']['closed'] = $lang->execution->statusList['closed'];
$lang->execution->featureBar['build']['all'] = 'Build List';
$lang->execution->myExecutions = "J'étais impliqué";
$lang->execution->doingProject = 'Projets en cours';
+2
View File
@@ -418,6 +418,8 @@ $lang->execution->featureBar['all']['doing'] = $lang->execution->statusList[
$lang->execution->featureBar['all']['suspended'] = $lang->execution->statusList['suspended'];
$lang->execution->featureBar['all']['closed'] = $lang->execution->statusList['closed'];
$lang->execution->featureBar['build']['all'] = 'Build List';
$lang->execution->myExecutions = 'Tôi tham gia';
$lang->execution->doingProject = 'Hiện trường';
+2
View File
@@ -514,6 +514,8 @@ $lang->execution->featureBar['all']['doing'] = $lang->execution->statusList[
$lang->execution->featureBar['all']['suspended'] = $lang->execution->statusList['suspended'];
$lang->execution->featureBar['all']['closed'] = $lang->execution->statusList['closed'];
$lang->execution->featureBar['build']['all'] = '所有版本';
$lang->execution->myExecutions = '我参与的';
$lang->execution->doingProject = '进行中的项目';
+1
View File
@@ -48,6 +48,7 @@ js::set('isCNLang', !$this->loadModel('common')->checkNotCN())
</ul>
</div>
<?php endif;?>
<?php common::sortFeatureMenu();?>
<?php foreach($lang->execution->featureBar['all'] as $key => $label):?>
<?php $label = "<span class='text'>$label</span>";?>
<?php if($status == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
+1 -1
View File
@@ -49,7 +49,7 @@
<tr>
<th class='c-id'><?php echo $lang->idAB;?></th>
<?php if($config->systemMode == 'new' and isset($project) and $project->model == 'scrum'):?>
<th class='c-project required' style="width:100%"><?php echo $lang->execution->projectName;?></th>
<th class='c-project required <?php echo $minWidth?>' style="width:100%"><?php echo $lang->execution->projectName;?></th>
<?php endif;?>
<th class='required <?php echo $minWidth?>' style="width:100%"><?php echo $lang->execution->$name;?></th>
<?php if(!isset($config->setCode) or $config->setCode == 1):?>
+6 -6
View File
@@ -16,14 +16,14 @@
<div id="mainMenu" class="clearfix table-row">
<div class="btn-toolbar pull-left">
<?php
$label = "<span class='text'>{$lang->execution->build}</span>";
$active = '';
if($type == 'all')
common::sortFeatureMenu();
foreach($lang->execution->featureBar['build'] as $featureType => $label)
{
$active = 'btn-active-text';
$label .= " <span class='label label-light label-badge'>{$buildsTotal}</span>";
$label = "<span class='text'>$label</span>";
$activeClass = $type == $featureType ? 'btn-active-text' : '';
if($type == $featureType) $label .= " <span class='label label-light label-badge'>{$buildsTotal}</span>";
echo html::a(inlink('build', "executionID=$executionID&type=$featureType"), $label, '',"class='btn btn-link $activeClass' data-app={$app->tab} id='$featureType'");
}
echo html::a(inlink('build', "executionID={$executionID}&type=all"), $label, '', "class='btn btn-link $active' id='all'")
?>
<div class="input-control space w-150px"><?php echo html::select('product', $products, $product, "onchange='changeProduct(this.value)' class='form-control chosen' data-placeholder='{$lang->productCommon}'");?></div>
</div>
+6 -7
View File
@@ -49,13 +49,12 @@
</div>
</div>
<div class="btn-toolbar pull-left">
<?php
if(common::hasPriv('execution', 'story'))
{
echo html::a($this->createLink('execution', 'story', "executionID=$execution->id&orderBy=order_desc&type=all"), "<span class='text'>{$lang->all}</span>" . ($type == 'all' ? " <span class='label label-light label-badge'>{$pager->recTotal}</span>" : ''), '', "class='btn btn-link" . ($type == 'all' ? " btn-active-text" : '') . "'");
echo html::a($this->createLink('execution', 'story', "executionID=$execution->id&orderBy=order_desc&type=unclosed"), "<span class='text'>{$lang->story->unclosed}</span>" . ($type == 'unclosed' ? " <span class='label label-light label-badge'>{$pager->recTotal}</span>" : ''), '', "class='btn btn-link" . ($type == 'unclosed' ? " btn-active-text" : '') . "'");
}
?>
<?php foreach($lang->story->featureBar['browse'] as $featureType => $label):?>
<?php $active = $type == $featureType ? 'btn-active-text' : '';?>
<?php $label = "<span class='text'>$label</span>";?>
<?php if($type == $featureType) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
<?php echo html::a(inlink('story', "executionID=$execution->id&orderBy=order_desc&type=$featureType"), $label, '', "class='btn btn-link $active'");?>
<?php endforeach;?>
<a class="btn btn-link querybox-toggle" id='bysearchTab'><i class="icon icon-search muted"></i> <?php echo $lang->product->searchStory;?></a>
</div>
<div class="btn-toolbar pull-right">
+1
View File
@@ -59,6 +59,7 @@ body {margin-bottom: 25px;}
</div>
<div class="btn-toolbar pull-left">
<?php
common::sortFeatureMenu();
foreach(customModel::getFeatureMenu('execution', 'task') as $menuItem)
{
if($execution->type == 'ops' && $menuItem->name == 'needconfirm') continue;
+2 -4
View File
@@ -341,12 +341,10 @@ class file extends control
/* Update test case version for test case synchronization. */
if($file->objectType == 'testcase' and $file->title != $fileName) $this->file->updateTestcaseVersion($file);
$newFile = $this->file->getByID($fileID);
return print(js::reload('parent.parent'));
echo json_encode($newFile);
}
$this->view->file = $this->file->getById($fileID);
$this->display();
}
/**
-62
View File
@@ -1,62 +0,0 @@
<?php
/**
* The export view file of file module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Yangyang Shi <shiyangyang@cnezsoft.com>
* @package file
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.lite.html.php';?>
<style>.main-form {margin: 15px -15px 0}</style>
<script>
function setFileName()
{
time = setInterval("closeWindow()", 200);
return true;
}
function closeWindow()
{
parent.$.closeModal();
clearInterval(time);
}
</script>
<main id="main">
<div class="container">
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->file->inputFileName;?></h2>
</div>
<?php
if(strrpos($file->title, '.') !== false)
{
/* Fix the file name exe.exe */
$title = explode('.', $file->title);
$extension = end($title);
if($file->extension == 'txt' && $extension != $file->extension) $file->extension = $extension;
array_pop($title);
$file->title = join('.', $title);
}
?>
<form class='main-form' method='post' target='hiddenwin' onsubmit='setFileName();'>
<table class='table table-form'>
<tr>
<td>
<div class='input-group'>
<?php echo html::input('fileName', $file->title, "class='form-control' size='40'");?>
<input type="hidden" name="extension" value="<?php echo $file->extension;?>"/>
<strong class='input-group-addon'>.<?php echo $file->extension;?></strong>
</div>
</td>
<td class='w-80px'><?php echo html::submitButton('', '', 'btn btn-primary btn-block');?></td>
</tr>
</table>
</form>
</div>
</div>
</main>
<?php include '../../common/view/footer.lite.html.php';?>
+172 -70
View File
@@ -6,19 +6,39 @@
<div class="detail-content">
<?php endif;?>
<style>
.file {padding-top: 2px;}
.files-list>li>a {display: inline; word-wrap: break-word;}
.files-list>li>.right-icon {opacity: 1;}
.fileAction {color: #0c64eb !important;}
.renameFile {display: flex;}
.renameFile .input-group {margin-left: 10px;}
.renameFile .icon {margin-top: 8px;}
.renameFile .input-group-addon {width: 60px;}
</style>
<script>
/* Delete a file. */
/**
* Delete a file.
*
* @param int $fileID
* @access public
* @return void
*/
function deleteFile(fileID)
{
if(!fileID) return;
hiddenwin.location.href = createLink('file', 'delete', 'fileID=' + fileID);
}
/* Download a file, append the mouse to the link. Thus we call decide to open the file in browser no download it. */
/**
* Download a file, append the mouse to the link. Thus we call decide to open the file in browser no download it.
*
* @param int $fileID
* @param int $extension
* @param int $imageWidth
* @param string $fileTitle
* @access public
* @return void
*/
function downloadFile(fileID, extension, imageWidth, fileTitle)
{
if(!fileID) return;
@@ -45,89 +65,171 @@
}
return false;
}
/* Show edit box for editing file name. */
/**
* Show edit box for editing file name.
*
* @param int $fileID
* @access public
* @return void
*/
function showRenameBox(fileID)
{
$('#renameFile' + fileID).closest('li').addClass('hidden');
$('#renameBox' + fileID).removeClass('hidden');
}
/**
* Show File.
*
* @param int $fileID
* @access public
* @return void
*/
function showFile(fileID)
{
$('#renameBox' + fileID).addClass('hidden');
$('#renameFile' + fileID).closest('li').removeClass('hidden');
}
/**
* Smooth refresh file name.
*
* @param int $fileID
* @access public
* @return void
*/
function setFileName(fileID)
{
var fileName = $('#fileName' + fileID).val();
var extension = $('#extension' + fileID).val();
var postData = {'fileName' : fileName, 'extension' : extension};
$('#renameBox' + fileID ).addClass('hidden');
$.ajax(
{
url:createLink('file', 'edit', 'fileID=' + fileID),
dataType: 'json',
method: 'post',
data: postData,
success: function(data)
{
console.log(data['title']);
$('#fileTitle' + fileID).html("<i class='icon icon-file-text'></i> &nbsp;" + data['title']);
$('#renameFile' + fileID).closest('li').removeClass('hidden');
$('#renameBox' + fileID).addClass('hidden');
}
})
}
</script>
<ul class="files-list">
<?php
foreach($files as $file)
{
if(common::hasPriv('file', 'download'))
<?php foreach($files as $file):?>
<?php if(common::hasPriv('file', 'download')):?>
<?php
$uploadDate = $lang->file->uploadDate . substr($file->addedDate, 0, 10);
$fileTitle = "<i class='icon icon-file-text'></i> &nbsp;" . $file->title;
if(strpos($file->title, ".{$file->extension}") === false && $file->extension != 'txt') $fileTitle .= ".{$file->extension}";
$imageWidth = 0;
if(stripos('jpg|jpeg|gif|png|bmp', $file->extension) !== false)
{
$uploadDate = $lang->file->uploadDate . substr($file->addedDate, 0, 10);
$fileTitle = "<i class='icon icon-file-text'></i> &nbsp;" . $file->title;
if(strpos($file->title, ".{$file->extension}") === false && $file->extension != 'txt') $fileTitle .= ".{$file->extension}";
$imageWidth = 0;
if(stripos('jpg|jpeg|gif|png|bmp', $file->extension) !== false)
$imageSize = $this->file->getImageSize($file);
$imageWidth = $imageSize ? $imageSize[0] : 0;
}
$fileSize = 0;
/* Show size info. */
if($file->size < 1024)
{
$fileSize = $file->size . 'B';
}
elseif($file->size < 1024 * 1024)
{
$file->size = round($file->size / 1024, 2);
$fileSize = $file->size . 'K';
}
elseif($file->size < 1024 * 1024 * 1024)
{
$file->size = round($file->size / (1024 * 1024), 2);
$fileSize = $file->size . 'M';
}
else
{
$file->size = round($file->size / (1024 * 1024 * 1024), 2);
$fileSize = $file->size . 'G';
}
$downloadLink = $this->createLink('file', 'download', "fileID=$file->id");
$downloadLink .= strpos($downloadLink, '?') === false ? '?' : '&';
$downloadLink .= $sessionString;
echo "<li class='file' title='{$uploadDate}'>" . html::a($downloadLink, $fileTitle . " <span class='text-muted'>({$fileSize})</span>", '_blank', "id='fileTitle$file->id' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
$objectType = zget($this->config->file->objectType, $file->objectType);
if(common::hasPriv($objectType, 'edit', $object))
{
echo "<span class='right-icon'>&nbsp; ";
/* Determines whether the file supports preview. */
if($file->extension == 'txt')
{
$imageSize = $this->file->getImageSize($file);
$imageWidth = $imageSize ? $imageSize[0] : 0;
$extension = 'txt';
if(($postion = strrpos($file->title, '.')) !== false) $extension = substr($file->title, $postion + 1);
if($extension != 'txt') $mode = 'down';
$file->extension = $extension;
}
$fileSize = 0;
/* Show size info. */
if($file->size < 1024)
/* For the open source version of the file judgment. */
if(stripos('txt|jpg|jpeg|gif|png|bmp', $file->extension) !== false)
{
$fileSize = $file->size . 'B';
}
elseif($file->size < 1024 * 1024)
{
$file->size = round($file->size / 1024, 2);
$fileSize = $file->size . 'K';
}
elseif($file->size < 1024 * 1024 * 1024)
{
$file->size = round($file->size / (1024 * 1024), 2);
$fileSize = $file->size . 'M';
}
else
{
$file->size = round($file->size / (1024 * 1024 * 1024), 2);
$fileSize = $file->size . 'G';
echo html::a($downloadLink, $lang->file->preview, '_blank', "class='fileAction btn btn-link text-primary' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
}
$downloadLink = $this->createLink('file', 'download', "fileID=$file->id");
$downloadLink .= strpos($downloadLink, '?') === false ? '?' : '&';
$downloadLink .= $sessionString;
echo "<li title='{$uploadDate}'>" . html::a($downloadLink, $fileTitle . " <span class='text-muted'>({$fileSize})</span>", '_blank', "onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
$objectType = zget($this->config->file->objectType, $file->objectType);
if(common::hasPriv($objectType, 'edit', $object))
/* For the max version of the file judgment. */
if(isset($this->config->file->libreOfficeTurnon) and $this->config->file->libreOfficeTurnon == 1)
{
echo "<span class='right-icon'>&nbsp; ";
/* Determines whether the file supports preview. */
if($file->extension == 'txt')
{
$extension = 'txt';
if(($postion = strrpos($file->title, '.')) !== false) $extension = substr($file->title, $postion + 1);
if($extension != 'txt') $mode = 'down';
$file->extension = $extension;
}
/* For the open source version of the file judgment. */
if(stripos('txt|jpg|jpeg|gif|png|bmp', $file->extension) !== false)
$officeTypes = 'doc|docx|xls|xlsx|ppt|pptx|pdf';
if(stripos($officeTypes, $file->extension) !== false)
{
echo html::a($downloadLink, $lang->file->preview, '_blank', "class='fileAction btn btn-link text-primary' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
}
/* For the max version of the file judgment. */
if(isset($this->config->file->libreOfficeTurnon) and $this->config->file->libreOfficeTurnon == 1)
{
$officeTypes = 'doc|docx|xls|xlsx|ppt|pptx|pdf';
if(stripos($officeTypes, $file->extension) !== false)
{
echo html::a($downloadLink, $lang->file->preview, '_blank', "class='fileAction btn btn-link text-primary' onclick=\"return downloadFile($file->id, '$file->extension', $imageWidth, '$file->title')\"");
}
}
common::printLink('file', 'download', "fileID=$file->id", $lang->file->downloadFile, '_blank', "class='fileAction btn btn-link text-primary' title='{$lang->file->downloadFile}'");
common::printLink('file', 'edit', "fileID=$file->id", $lang->file->edit, '', "data-width='400' class='fileAction btn btn-link edit iframe text-primary' title='{$lang->file->edit}'");
if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='fileAction btn btn-link text-primary' onclick='deleteFile($file->id)' title='$lang->delete'");
echo '</span>';
}
echo '</li>';
common::printLink('file', 'download', "fileID=$file->id", $lang->file->downloadFile, '_blank', "class='fileAction btn btn-link text-primary' title='{$lang->file->downloadFile}'");
if(common::hasPriv('file', 'edit')) echo html::a('###', $lang->file->edit, '', "id='renameFile$file->id' class='fileAction btn btn-link edit text-primary' onclick='showRenameBox($file->id)' title='{$lang->file->edit}'");
if(common::hasPriv('file', 'delete')) echo html::a('###', $lang->delete, '', "class='fileAction btn btn-link text-primary' onclick='deleteFile($file->id)' title='$lang->delete'");
echo '</span>';
}
}
?>
echo '</li>';?>
<li class='file'>
<div>
<?php
if(strrpos($file->title, '.') !== false)
{
/* Fix the file name exe.exe */
$title = explode('.', $file->title);
$extension = end($title);
if($file->extension == 'txt' && $extension != $file->extension) $file->extension = $extension;
array_pop($title);
$file->title = join('.', $title);
}
?>
<div class='hidden renameFile w-300px' id='renameBox<?php echo $file->id;?>'>
<i class='icon icon-file-text'></i>
<div class='input-group'>
<?php echo html::input('fileName' . $file->id, $file->title, "class='form-control' size='40'");?>
<input type="hidden" name="extension" id="extension<?php echo $file->id?>" value="<?php echo $file->extension;?>"/>
<strong class='input-group-addon'>.<?php echo $file->extension;?></strong>
</div>
<div class="input-group-btn">
<button type="button" class="btn btn-success file-name-confirm" onclick="setFileName(<?php echo $file->id;?>)" style="border-radius: 0px 2px 2px 0px; border-left-color: transparent;"><i class="icon icon-check"></i></button>
<button type="button" class="btn btn-gray file-name-cancel" onclick="showFile(<?php echo $file->id;?>)" style="border-radius: 0px 2px 2px 0px; border-left-color: transparent;"><i class="icon icon-close"></i></button>
</div>
</div>
</div>
</li>
<?php endif;?>
<?php endforeach;?>
</ul>
<?php if($fieldset == 'true'):?>
</div>
+1
View File
@@ -630,6 +630,7 @@ $lang->resource->kanban->activateSpace = 'activateSpace';
$lang->resource->kanban->sortSpace = 'sortSpace';
$lang->resource->kanban->create = 'create';
$lang->resource->kanban->edit = 'edit';
$lang->resource->kanban->setting = 'setting';
$lang->resource->kanban->view = 'view';
$lang->resource->kanban->activate = 'activate';
$lang->resource->kanban->close = 'close';
+4
View File
@@ -36,6 +36,10 @@ $config->kanban->splitcolumn->requiredFields = 'name,limit';
$config->kanban->editor = new stdclass();
$config->kanban->editor->closespace = array('id' => 'comment', 'tools' => 'simpleTools');
$config->kanban->editor->activatespace = array('id' => 'comment', 'tools' => 'simpleTools');
$config->kanban->editor->createspace = array('id' => 'desc', 'tools' => 'simpleTools');
$config->kanban->editor->editspace = array('id' => 'desc', 'tools' => 'simpleTools');
$config->kanban->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
$config->kanban->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
$config->kanban->editor->createcard = array('id' => 'desc', 'tools' => 'simpleTools');
$config->kanban->editor->activate = array('id' => 'comment', 'tools' => 'simpleTools');
$config->kanban->editor->close = array('id' => 'comment', 'tools' => 'simpleTools');
+28 -2
View File
@@ -277,8 +277,7 @@ class kanban extends control
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
}
$kanban = $this->kanban->getByID($kanbanID);
$kanban->desc = strip_tags(htmlspecialchars_decode($kanban->desc));
$kanban = $this->kanban->getByID($kanbanID);
$space = $this->kanban->getSpaceById($kanban->space);
$spaceUsers = trim($space->owner) . ',' . trim($space->team);
@@ -291,6 +290,33 @@ class kanban extends control
$this->view->kanban = $kanban;
$this->view->type = $space->type;
$this->display();
}
/**
* Setting kanban.
*
* @param int $kanbanID
* @access public
* @return void
*/
public function setting($kanbanID = 0)
{
if(!empty($_POST))
{
$changes = $this->kanban->setting($kanbanID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
$actionID = $this->loadModel('action')->create('kanban', $kanbanID, 'edited');
$this->action->logHistory($actionID, $changes);
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'parent'));
}
$kanban = $this->kanban->getByID($kanbanID);
$this->view->kanban = $kanban;
$this->view->laneCount = $this->kanban->getLaneCount($kanbanID);
$this->view->heightType = $kanban->displayCards > 2 ? 'custom' : 'auto';
$this->view->displayCards = $kanban->displayCards ? $kanban->displayCards : '';
-7
View File
@@ -1,13 +1,6 @@
#mainContent .table-form>tbody>tr>th {width: 105px;}
#mainContent {padding-left: 0px;}
#mainContent .laneHeightBox .radio-inline+.radio-inline, #mainContent .importBox .radio-inline+.radio-inline {margin-left: 20px;}
#mainContent .objectBox {padding-top: 2px;}
#mainContent .objectBox .checkbox-primary {display: inline-block;}
#mainContent .objectBox .checkbox-primary:not(:first-child) {margin-left: 10px;}
#mainContent .objectBox .checkbox-primary>label:not(:first-child) {padding-left: 20px;}
#mainContent .laneHeightBox .tip {color: #999;}
#mainContent .objectBox .checkbox-primary>label:before {top: 2px; left: 0px;}
#mainContent .objectBox .checkbox-primary>label:after {width: 14px; height: 14px;}
[lang^='en'] .columnWidth {width: 120px;}
[lang^='zh-cn'] .columnWidth {width: 80px;}
#team ~ #contactListMenu_chosen {vertical-align: top;}
+7
View File
@@ -0,0 +1,7 @@
#mainContent .objectBox {padding-top: 2px;}
#mainContent .objectBox .checkbox-primary {display: inline-block;}
#mainContent .objectBox .checkbox-primary:not(:first-child) {margin-left: 10px;}
#mainContent .objectBox .checkbox-primary>label:not(:first-child) {padding-left: 20px;}
#mainContent .laneHeightBox .tip {color: #999;}
#mainContent .objectBox .checkbox-primary>label:before {top: 2px; left: 0px;}
#mainContent .objectBox .checkbox-primary>label:after {width: 14px; height: 14px;}
+1 -1
View File
@@ -48,6 +48,7 @@ $lang->kanban->removeCard = 'Remove Card';
$lang->kanban->assigntoCard = 'Assign';
$lang->kanban->setting = 'Setting';
$lang->kanban->settingSpace = 'Setting Space';
$lang->kanban->settingKanban = 'Setting Kanban';
$lang->kanban->activateSpace = 'Activate Space';
$lang->kanban->closeSpace = 'Close Space';
$lang->kanban->deleteSpace = 'Delete Space';
@@ -200,7 +201,6 @@ $lang->kanban->moreAction = 'More Action';
$lang->kanban->noGroup = 'None';
$lang->kanban->limitExceeded = 'Limit Exceeded';
$lang->kanban->fullScreen = 'Full Screen';
$lang->kanban->setting = 'Setting';
$lang->kanban->my = 'My';
$lang->kanban->other = 'Other';
$lang->kanban->showWIP = 'Show WIP';
+1 -1
View File
@@ -48,6 +48,7 @@ $lang->kanban->removeCard = 'Remove Card';
$lang->kanban->assigntoCard = 'Assign';
$lang->kanban->setting = 'Setting';
$lang->kanban->settingSpace = 'Setting Space';
$lang->kanban->settingKanban = 'Setting Kanban';
$lang->kanban->activateSpace = 'Activate Space';
$lang->kanban->closeSpace = 'Close Space';
$lang->kanban->deleteSpace = 'Delete Space';
@@ -200,7 +201,6 @@ $lang->kanban->moreAction = 'More Action';
$lang->kanban->noGroup = 'None';
$lang->kanban->limitExceeded = 'Limit Exceeded';
$lang->kanban->fullScreen = 'Full Screen';
$lang->kanban->setting = 'Setting';
$lang->kanban->my = 'My';
$lang->kanban->other = 'Other';
$lang->kanban->showWIP = 'Show WIP';
+1 -1
View File
@@ -48,6 +48,7 @@ $lang->kanban->removeCard = 'Remove Card';
$lang->kanban->assigntoCard = 'Assign';
$lang->kanban->setting = 'Setting';
$lang->kanban->settingSpace = 'Setting Space';
$lang->kanban->settingKanban = 'Setting Kanban';
$lang->kanban->activateSpace = 'Activate Space';
$lang->kanban->closeSpace = 'Close Space';
$lang->kanban->deleteSpace = 'Delete Space';
@@ -200,7 +201,6 @@ $lang->kanban->moreAction = 'More Action';
$lang->kanban->noGroup = 'None';
$lang->kanban->limitExceeded = 'Limit Exceeded';
$lang->kanban->fullScreen = 'Full Screen';
$lang->kanban->setting = 'Setting';
$lang->kanban->my = 'My';
$lang->kanban->other = 'Other';
$lang->kanban->showWIP = 'Show WIP';
+1 -1
View File
@@ -48,6 +48,7 @@ $lang->kanban->removeCard = '移除卡片';
$lang->kanban->assigntoCard = '指派';
$lang->kanban->setting = '设置';
$lang->kanban->settingSpace = '设置空间';
$lang->kanban->settingKanban = '设置看板';
$lang->kanban->activateSpace = '激活空间';
$lang->kanban->closeSpace = '关闭空间';
$lang->kanban->deleteSpace = '删除空间';
@@ -200,7 +201,6 @@ $lang->kanban->moreAction = '更多操作';
$lang->kanban->noGroup = '无';
$lang->kanban->limitExceeded = '超出在制品限制';
$lang->kanban->fullScreen = '全屏';
$lang->kanban->setting = '设置';
$lang->kanban->my = '我的看板';
$lang->kanban->other = '其他';
$lang->kanban->showWIP = '显示在制品限制';
+50 -13
View File
@@ -1943,6 +1943,7 @@ class kanbanModel extends model
->join('whitelist', ',')
->join('team', ',')
->trim('name')
->stripTags($this->config->kanban->editor->createspace['id'], $this->config->allowedTags)
->remove('uid,contactListMenu')
->get();
@@ -1986,6 +1987,7 @@ class kanbanModel extends model
->join('whitelist', ',')
->join('team', ',')
->trim('name')
->stripTags($this->config->kanban->editor->editspace['id'], $this->config->allowedTags)
->remove('uid,contactListMenu')
->get();
@@ -2198,7 +2200,8 @@ class kanbanModel extends model
->join('whitelist', ',')
->join('team', ',')
->trim('name')
->remove('contactListMenu,type,import,importObjectList,copyKanbanID,copyRegion')
->stripTags($this->config->kanban->editor->create['id'], $this->config->allowedTags)
->remove('contactListMenu,type,import,importObjectList,uid,copyKanbanID,copyRegion')
->get();
if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList);
@@ -2266,24 +2269,15 @@ class kanbanModel extends model
$kanban = fixer::input('post')
->setDefault('lastEditedBy', $account)
->setDefault('lastEditedDate', helper::now())
->setDefault('displayCards', 0)
->setDefault('whitelist', '')
->setDefault('team', '')
->setIF($this->post->import == 'off', 'object', '')
->setIF($this->post->heightType == 'auto', 'displayCards', 0)
->join('whitelist', ',')
->join('team', ',')
->trim('name')
->remove('uid,contactListMenu,import,importObjectList,heightType')
->stripTags($this->config->kanban->editor->edit['id'], $this->config->allowedTags)
->remove('uid,contactListMenu')
->get();
if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList);
if(isset($_POST['heightType']) and $this->post->heightType == 'custom')
{
if(!$this->checkDisplayCards($kanban->displayCards)) return;
}
$this->dao->update(TABLE_KANBAN)->data($kanban)
->autoCheck()
->batchCheck($this->config->kanban->edit->requiredFields, 'notempty')
@@ -2306,6 +2300,48 @@ class kanbanModel extends model
}
}
/**
* Setting kanban.
*
* @param int $kanbanID
* @access public
* @return void
*/
public function setting($kanbanID)
{
$kanbanID = (int)$kanbanID;
$account = $this->app->user->account;
$oldKanban = $this->getByID($kanbanID);
$kanban = fixer::input('post')
->setDefault('lastEditedBy', $account)
->setDefault('lastEditedDate', helper::now())
->setDefault('displayCards', 0)
->setIF($this->post->import == 'off', 'object', '')
->setIF($this->post->heightType == 'auto', 'displayCards', 0)
->remove('import,importObjectList,heightType')
->get();
if($this->post->import == 'on') $kanban->object = implode(',', $this->post->importObjectList);
if(isset($_POST['heightType']) and $this->post->heightType == 'custom')
{
if(!$this->checkDisplayCards($kanban->displayCards)) return;
}
$this->dao->update(TABLE_KANBAN)->data($kanban)
->autoCheck()
->batchCheck($this->config->kanban->edit->requiredFields, 'notempty')
->where('id')->eq($kanbanID)
->exec();
if(!dao::isError())
{
return common::createChanges($oldKanban, $kanban);
}
return false;
}
/**
* Activate a kanban.
*
@@ -3224,7 +3260,8 @@ class kanbanModel extends model
$actions .= $commonActions;
$kanbanActions = '';
if(common::hasPriv('kanban', 'edit')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'edit', "kanbanID=$kanban->id", '', true), '<i class="icon icon-edit"></i>' . $this->lang->kanban->edit, '', "class='iframe btn btn-link' data-width='75%'") . '</li>';
if(common::hasPriv('kanban', 'edit')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'edit', "kanbanID=$kanban->id", '', true), '<i class="icon icon-edit"></i>' . $this->lang->kanban->edit, '', "class='iframe btn btn-link' data-width='75%'") . '</li>';
if(common::hasPriv('kanban', 'setting')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'setting', "kanbanID=$kanban->id", '', true), '<i class="icon icon-cog-outline"></i>' . $this->lang->kanban->settingKanban, '', "class='iframe btn btn-link' data-width='60%'") . '</li>';
if(common::hasPriv('kanban', 'close') and $kanban->status == 'active') $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'close', "kanbanID=$kanban->id", '', true), '<i class="icon icon-off"></i>' . $this->lang->kanban->close, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'activate') and $kanban->status == 'closed') $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'activate', "kanbanID=$kanban->id", '', true), '<i class="icon icon-magic"></i>' . $this->lang->kanban->activate, '', "class='iframe btn btn-link'") . '</li>';
if(common::hasPriv('kanban', 'delete')) $kanbanActions .= '<li>' . html::a(helper::createLink('kanban', 'delete', "kanbanID=$kanban->id"), '<i class="icon icon-trash"></i>' . $this->lang->kanban->delete, 'hiddenwin', "class='btn btn-link'") . '</li>';
-40
View File
@@ -12,7 +12,6 @@
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('enableImport', $enableImport);?>
<?php js::set('vision', $this->config->vision);?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
@@ -24,11 +23,6 @@
<th><?php echo $lang->kanban->space;?></th>
<td><?php echo html::select('space', $spacePairs, $kanban->space, "class='form-control chosen' onchange='loadOwners(this.value)'");?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->WIPCount;?></th>
<td><?php echo html::radio('showWIP', $lang->kanban->showWIPList, $kanban->showWIP);?></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->kanban->name;?></th>
<td><?php echo html::input('name', $kanban->name, "class='form-control'");?></td>
@@ -53,40 +47,6 @@
</td>
</tr>
<?php endif;?>
<tr>
<th class='columnWidth'><?php echo $lang->kanban->columnWidth;?></th>
<td colspan='2'><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, $kanban->fluidBoard));?></td>
</tr>
<?php if($laneCount > 1):?>
<tr>
<th id='c-name'><?php echo $lang->kanban->laneHeight;?></th>
<td colspan='2' class='laneHeightBox'><?php echo nl2br(html::radio('heightType', $lang->kanbanlane->heightTypeList, $heightType, "onclick='setCardCount(this.value);'"));?></td>
</tr>
<tr class="hidden" id='cardBox'>
<th class='c-count'><?php echo $lang->kanban->cardCount;?></th>
<td><?php echo html::input('displayCards', $displayCards, "class='form-control' required placeholder='{$lang->kanban->cardCountTip}' autocomplete='off'");?></td>
</tr>
<?php endif;?>
<tr>
<th rowspan='2'><?php echo $lang->kanban->import?></th>
<td colspan='2' class='importBox'><?php echo nl2br(html::radio('import', $lang->kanban->importList, $enableImport));?></td>
</tr>
<tr>
<td colspan='2' class='objectBox'><?php echo html::checkbox('importObjectList', $lang->kanban->importObjectList, $importObjects);?></td>
</tr>
<tr id='emptyTip' class='hidden'><th></th><td colspan='2' style='color: red;'><?php echo $lang->kanban->error->importObjNotEmpty;?></td></tr>
<tr>
<th class='w-90px'><?php echo $lang->kanban->archive;?></th>
<td><?php echo nl2br(html::radio('archived', $lang->kanban->archiveList, $kanban->archived));?></td>
</tr>
<tr>
<th id='c-title'><?php echo $lang->kanban->manageProgress;?></th>
<td><?php echo nl2br(html::radio('performable', $lang->kanban->enableList, $kanban->performable));?></td>
</tr>
<tr>
<th id='c-title'><?php echo $lang->kanban->alignment;?></th>
<td><?php echo nl2br(html::radio('alignment', $lang->kanban->alignmentList, $kanban->alignment));?></td>
</tr>
<tr>
<th><?php echo $lang->kanban->desc;?></th>
<td colspan='2'>
+70
View File
@@ -0,0 +1,70 @@
<?php
/**
* The setting file of kanban module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Mengyi Liu <liumengyi@easycorp.ltd>
* @package kanban
* @version $Id: edit.html.php 935 2021-12-09 16:15:24Z $
* @link https://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('enableImport', $enableImport);?>
<?php js::set('vision', $this->config->vision);?>
<div id='mainContent' class='main-content'>
<div class='main-header'>
<h2><?php echo $lang->kanban->settingKanban;?></h2>
</div>
<form class='form-indicator main-form form-ajax' method='post' enctype='multipart/form-data' id='dataform'>
<table class='table table-form'>
<tr>
<th><?php echo $lang->kanban->WIPCount;?></th>
<td><?php echo html::radio('showWIP', $lang->kanban->showWIPList, $kanban->showWIP);?></td>
<td></td>
</tr>
<tr>
<th class='columnWidth'><?php echo $lang->kanban->columnWidth;?></th>
<td colspan='2'><?php echo nl2br(html::radio('fluidBoard', $lang->kanbancolumn->fluidBoardList, $kanban->fluidBoard));?></td>
</tr>
<?php if($laneCount > 1):?>
<tr>
<th id='c-name'><?php echo $lang->kanban->laneHeight;?></th>
<td colspan='2' class='laneHeightBox'><?php echo nl2br(html::radio('heightType', $lang->kanbanlane->heightTypeList, $heightType, "onclick='setCardCount(this.value);'"));?></td>
</tr>
<tr class="hidden" id='cardBox'>
<th class='c-count'><?php echo $lang->kanban->cardCount;?></th>
<td><?php echo html::input('displayCards', $displayCards, "class='form-control' required placeholder='{$lang->kanban->cardCountTip}' autocomplete='off'");?></td>
</tr>
<?php endif;?>
<tr>
<th rowspan='2'><?php echo $lang->kanban->import?></th>
<td colspan='2' class='importBox'><?php echo nl2br(html::radio('import', $lang->kanban->importList, $enableImport));?></td>
</tr>
<tr>
<td colspan='2' class='objectBox'><?php echo html::checkbox('importObjectList', $lang->kanban->importObjectList, $importObjects);?></td>
</tr>
<tr id='emptyTip' class='hidden'><th></th><td colspan='2' style='color: red;'><?php echo $lang->kanban->error->importObjNotEmpty;?></td></tr>
<tr>
<th class='w-90px'><?php echo $lang->kanban->archive;?></th>
<td><?php echo nl2br(html::radio('archived', $lang->kanban->archiveList, $kanban->archived));?></td>
</tr>
<tr>
<th id='c-title'><?php echo $lang->kanban->manageProgress;?></th>
<td><?php echo nl2br(html::radio('performable', $lang->kanban->enableList, $kanban->performable));?></td>
</tr>
<tr>
<th id='c-title'><?php echo $lang->kanban->alignment;?></th>
<td><?php echo nl2br(html::radio('alignment', $lang->kanban->alignmentList, $kanban->alignment));?></td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'>
<?php echo html::submitButton();?>
</td>
</tr>
</table>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+5 -1
View File
@@ -272,7 +272,7 @@ class productModel extends model
->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->products)->fi()
->andWhere('t1.vision')->eq($this->config->vision)->fi()
->beginIF($status == 'noclosed')->andWhere('t1.status')->ne('closed')->fi()
->beginIF($status != 'all' and $status != 'noclosed' and $status != 'involved')->andWhere('t1.status')->in($status)->fi()
->beginIF(!in_array($status, array('all', 'noclosed', 'involved', 'review'), true))->andWhere('t1.status')->in($status)->fi()
->beginIF($status == 'involved')
->andWhere('t1.PO', true)->eq($this->app->user->account)
->orWhere('t1.QD')->eq($this->app->user->account)
@@ -280,6 +280,10 @@ class productModel extends model
->orWhere('t1.createdBy')->eq($this->app->user->account)
->markRight(1)
->fi()
->beginIF($status == 'review')
->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")
->andWhere('t1.reviewStatus')->eq('doing')
->fi()
->orderBy('t2.order_asc, t1.line_desc, t1.order_asc')
->beginIF($limit > 0)->limit($limit)->fi()
->fetchAll('id');
+1
View File
@@ -13,6 +13,7 @@
<?php include '../../common/view/sortable.html.php';?>
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<?php common::sortFeatureMenu();?>
<?php foreach($lang->product->featureBar['all'] as $key => $label):?>
<?php $recTotalLabel = $browseType == $key ? " <span class='label label-light label-badge'>{$recTotal}</span>" : '';?>
<?php echo html::a(inlink("all", "browseType=$key&orderBy=$orderBy"), "<span class='text'>{$label}</span>" . $recTotalLabel, '', "class='btn btn-link' id='{$key}Tab'");?>
+4 -1
View File
@@ -105,9 +105,10 @@ class productplanModel extends model
$plans = $this->dao->select('*')->from(TABLE_PRODUCTPLAN)->where('product')->eq($product)
->andWhere('deleted')->eq(0)
->beginIF(!empty($branch) and $branch != 'all')->andWhere('branch')->eq($branch)->fi()
->beginIF(strpos(',all,undone,bySearch,', ",$browseType,") === false)->andWhere('status')->eq($browseType)->fi()
->beginIF(strpos(',all,undone,bySearch,review,', ",$browseType,") === false)->andWhere('status')->eq($browseType)->fi()
->beginIF($browseType == 'undone')->andWhere('status')->in('wait,doing')->fi()
->beginIF($browseType == 'bySearch')->andWhere($productplanQuery)->fi()
->beginIF($browseType == 'review')->andWhere("FIND_IN_SET('{$this->app->user->account}', reviewers)")->fi()
->beginIF(strpos($param, 'skipparent') !== false)->andWhere('parent')->ne(-1)->fi()
->orderBy($orderBy)
->page($pager)
@@ -443,6 +444,8 @@ class productplanModel extends model
$plan = fixer::input('post')->stripTags($this->config->productplan->editor->create['id'], $this->config->allowedTags)
->setIF($this->post->future || empty($_POST['begin']), 'begin', $this->config->productplan->future)
->setIF($this->post->future || empty($_POST['end']), 'end', $this->config->productplan->future)
->setDefault('createdBy', $this->app->user->account)
->setDefault('createdDate', helper::now())
->remove('delta,uid,future')
->get();
@@ -16,6 +16,7 @@
</style>
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<?php common::sortFeatureMenu();?>
<?php foreach(customModel::getFeatureMenu($this->moduleName, $this->methodName) as $menuItem):?>
<?php if(isset($menuItem->hidden)) continue;?>
<?php $label = "<span class='text'>{$menuItem->text}</span>";?>
+29
View File
@@ -718,6 +718,35 @@ class program extends control
echo number_format($budgetLeft, 2);
}
/**
* Ajax get available budget.
*
* @param int $programID
* @param int $selectedProgramID
* @param int $budget
* @access public
* @return void
*/
public function ajaxGetAvailableBudget($programID, $selectedProgramID, $budget)
{
if(!empty($programID))
{
$program = $this->program->getByID($programID);
$selectedProgram = $this->program->getByID($selectedProgramID);
$budgetLeft = $this->program->getBudgetLeft($selectedProgram);
$availableBudget = $program->parent == $selectedProgramID ? $budgetLeft + $program->budget : $budgetLeft;
}
else
{
$selectedProgram = $this->program->getByID($selectedProgramID);
$availableBudget = $this->program->getBudgetLeft($selectedProgram);
}
$tips = '';
if($budget != 0 && $budget !== null && $budget > $availableBudget) $tips = "<span id='beyondBudgetTip' class='text-remind'>" . $this->lang->program->budgetOverrun . zget($this->lang->project->currencySymbol, $selectedProgram->budgetUnit) . $availableBudget . "</span>";
echo json_encode($tips);
}
/**
* Update program order.
*
+1
View File
@@ -1,2 +1,3 @@
.future {display: inline-block;}
.c-number {overflow: hidden; text-align: right !important; text-overflow: ellipsis; white-space: nowrap;}
.text-remind {color: #ffa34d;}
+3 -1
View File
@@ -1,4 +1,6 @@
#budget {border-right: 0px;}
#budgetUnit {border-left: 0px;}
#dateRange {vertical-align: top; padding-top: 13px;}
#dateRange, .futureBox {vertical-align: top !important; padding-top: 13px !important;}
#endList {vertical-align: top; padding-top: 13px;}
[lang^=en] #endList {vertical-align: top; padding-top: 20px;}
#dataform th {vertical-align: top; padding-top: 13px;}
+2 -1
View File
@@ -1,4 +1,5 @@
#budget {border-right: 0px;}
#budgetUnit {border-left: 0px;}
#dateRange {vertical-align: top; padding-top: 13px;}
#dateRange, .futureBox {vertical-align: top !important; padding-top: 13px !important;}
#endList {vertical-align: top; padding-top: 13px;}
#dataform th {vertical-align: top; padding-top: 13px;}
+34 -4
View File
@@ -276,6 +276,7 @@ $(function()
if($(this).prop('checked'))
{
$('#budget').val('').attr('disabled', 'disabled');
if($('#beyondBudgetTip').length > 0) $('#beyondBudgetTip').remove();
}
else
{
@@ -291,13 +292,13 @@ $(function()
* @access public
* @return void
*/
function setBudgetTipsAndAclList(programID)
function setBudgetTipsAndAclList(parentID)
{
if(programID != 0)
if(parentID != 0)
{
$.get(createLink('program', 'ajaxGetBudgetLeft', "ProgramID=" + programID), function(budgetLeft)
$.get(createLink('program', 'ajaxGetBudgetLeft', "ProgramID=" + parentID), function(budgetLeft)
{
parentProgram = programList[programID];
parentProgram = programList[parentID];
programBudget = parentProgram.budget;
PGMBudgetUnit = currencySymbol[parentProgram.budgetUnit];
@@ -311,4 +312,33 @@ function setBudgetTipsAndAclList(programID)
$('#budget').removeAttr('placeholder');
$('.aclBox').html($('#PGMAcl').html());
}
if(typeof(programID) == 'undefined') programID = 0;
budgetOverrunTips();
}
/**
* Append prompt when the budget exceeds the parent project set.
*
* @access public
* @return void
*/
function budgetOverrunTips()
{
var selectedProgramID = $('#parent').val();
var budget = $('#budget').val();
if(selectedProgramID == 0)
{
if($('#beyondBudgetTip').length > 0) $('#beyondBudgetTip').remove();
return false;
}
if(typeof(programID) == 'undefined') programID = 0;
$.get(createLink('program', 'ajaxGetAvailableBudget', 'programID=' + programID + "&selectedProgramID=" + selectedProgramID + "&budget=" + budget), function(data)
{
var data = JSON.parse(data);
if($('#beyondBudgetTip').length > 0) $('#beyondBudgetTip').remove();
$('#budgetBox').after(data);
});
}
+7 -6
View File
@@ -113,6 +113,7 @@ $lang->program->readjustTime = 'Change the program begin&end date.';
$lang->program->accessDenied = 'You have no access to the program.';
$lang->program->beyondParentBudget = 'The remaining budget of the owned program has been exceeded.';
$lang->program->checkedProjects = 'Seleted %s items';
$lang->program->budgetOverrun = "The program's budget has exceeded the remaining budget of the parent program:";
$lang->program->endList[31] = 'One month';
$lang->program->endList[93] = 'Trimester';
@@ -139,12 +140,12 @@ $lang->program->statusList['doing'] = 'Doing';
$lang->program->statusList['suspended'] = 'Suspended';
$lang->program->statusList['closed'] = 'Closed';
$lang->program->featureBar['all'] = 'All';
$lang->program->featureBar['unclosed'] = 'Unclosed';
$lang->program->featureBar['wait'] = 'Waiting';
$lang->program->featureBar['doing'] = 'Doing';
$lang->program->featureBar['suspended'] = 'Suspended';
$lang->program->featureBar['closed'] = 'Closed';
$lang->program->featureBar['browse']['all'] = 'All';
$lang->program->featureBar['browse']['unclosed'] = 'Unclosed';
$lang->program->featureBar['browse']['wait'] = 'Waiting';
$lang->program->featureBar['browse']['doing'] = 'Doing';
$lang->program->featureBar['browse']['suspended'] = 'Suspended';
$lang->program->featureBar['browse']['closed'] = 'Closed';
$lang->program->kanban = new stdclass();
$lang->program->kanban->common = 'Program Kanban';
+7 -6
View File
@@ -113,6 +113,7 @@ $lang->program->readjustTime = 'Change the program begin&end date.';
$lang->program->accessDenied = 'You have no access to the program.';
$lang->program->beyondParentBudget = 'The remaining budget of the owned program has been exceeded.';
$lang->program->checkedProjects = 'Seleted %s items';
$lang->program->budgetOverrun = "The program's budget has exceeded the remaining budget of the parent program:";
$lang->program->endList[31] = 'One month';
$lang->program->endList[93] = 'Trimester';
@@ -139,12 +140,12 @@ $lang->program->statusList['doing'] = 'Doing';
$lang->program->statusList['suspended'] = 'Suspended';
$lang->program->statusList['closed'] = 'Closed';
$lang->program->featureBar['all'] = 'All';
$lang->program->featureBar['unclosed'] = 'Unclosed';
$lang->program->featureBar['wait'] = 'Waiting';
$lang->program->featureBar['doing'] = 'Doing';
$lang->program->featureBar['suspended'] = 'Suspended';
$lang->program->featureBar['closed'] = 'Closed';
$lang->program->featureBar['browse']['all'] = 'All';
$lang->program->featureBar['browse']['unclosed'] = 'Unclosed';
$lang->program->featureBar['browse']['wait'] = 'Waiting';
$lang->program->featureBar['browse']['doing'] = 'Doing';
$lang->program->featureBar['browse']['suspended'] = 'Suspended';
$lang->program->featureBar['browse']['closed'] = 'Closed';
$lang->program->kanban = new stdclass();
$lang->program->kanban->common = 'Program Kanban';
+7 -6
View File
@@ -113,6 +113,7 @@ $lang->program->readjustTime = 'Change the program begin&end date.';
$lang->program->accessDenied = 'You have no access to the program.';
$lang->program->beyondParentBudget = 'The remaining budget of the owned program has been exceeded.';
$lang->program->checkedProjects = "Pour s électionner l'élément% s";
$lang->program->budgetOverrun = "Le budget du programme a dépassé le budget restant du programme parent:";
$lang->program->endList[31] = 'One month';
$lang->program->endList[93] = 'Trimester';
@@ -139,12 +140,12 @@ $lang->program->statusList['doing'] = 'Doing';
$lang->program->statusList['suspended'] = 'Suspended';
$lang->program->statusList['closed'] = 'Closed';
$lang->program->featureBar['all'] = 'All';
$lang->program->featureBar['unclosed'] = 'Unclosed';
$lang->program->featureBar['wait'] = 'En Attente';
$lang->program->featureBar['doing'] = 'En Cours';
$lang->program->featureBar['suspended'] = 'Suspendues';
$lang->program->featureBar['closed'] = 'Fermées';
$lang->program->featureBar['browse']['all'] = 'All';
$lang->program->featureBar['browse']['unclosed'] = 'Unclosed';
$lang->program->featureBar['browse']['wait'] = 'En Attente';
$lang->program->featureBar['browse']['doing'] = 'En Cours';
$lang->program->featureBar['browse']['suspended'] = 'Suspendues';
$lang->program->featureBar['browse']['closed'] = 'Fermées';
$lang->program->kanban = new stdclass();
$lang->program->kanban->common = 'Program Kanban';
+6 -1
View File
@@ -96,7 +96,12 @@ $lang->program->statusList['doing'] = 'Doing';
$lang->program->statusList['suspended'] = 'Suspended';
$lang->program->statusList['closed'] = 'Closed';
$lang->program->featureBar['all'] = 'All';
$lang->program->featureBar['browse']['all'] = 'All';
$lang->program->featureBar['browse']['unclosed'] = 'Unclosed';
$lang->program->featureBar['browse']['wait'] = 'Waiting';
$lang->program->featureBar['browse']['doing'] = 'Doing';
$lang->program->featureBar['browse']['suspended'] = 'Suspended';
$lang->program->featureBar['browse']['closed'] = 'Closed';
$lang->program->kanban = new stdclass();
$lang->program->kanban->common = 'Program Kanban';
+7 -6
View File
@@ -113,6 +113,7 @@ $lang->program->readjustTime = '重新调整项目集起止时间';
$lang->program->accessDenied = '你无权访问该项目集';
$lang->program->beyondParentBudget = '已超出所属项目集的剩余预算';
$lang->program->checkedProjects = '已选择%s项';
$lang->program->budgetOverrun = '项目集的预算已超出父项目集的剩余预算:';
$lang->program->endList[31] = '一个月';
$lang->program->endList[93] = '三个月';
@@ -139,12 +140,12 @@ $lang->program->statusList['doing'] = '进行中';
$lang->program->statusList['suspended'] = '已挂起';
$lang->program->statusList['closed'] = '已关闭';
$lang->program->featureBar['all'] = '所有';
$lang->program->featureBar['unclosed'] = '未关闭';
$lang->program->featureBar['wait'] = '未开始';
$lang->program->featureBar['doing'] = '进行中';
$lang->program->featureBar['suspended'] = '已挂起';
$lang->program->featureBar['closed'] = '已关闭';
$lang->program->featureBar['browse']['all'] = '所有';
$lang->program->featureBar['browse']['unclosed'] = '未关闭';
$lang->program->featureBar['browse']['wait'] = '未开始';
$lang->program->featureBar['browse']['doing'] = '进行中';
$lang->program->featureBar['browse']['suspended'] = '已挂起';
$lang->program->featureBar['browse']['closed'] = '已关闭';
$lang->program->kanban = new stdclass();
$lang->program->kanban->common = '项目集看板';
+5 -54
View File
@@ -574,8 +574,12 @@ class programModel extends model
->beginIF($browseType == 'bysearch')->andWhere($query)->fi()
->beginIF($this->config->systemMode == 'new')->andWhere('t1.type')->eq('project')->fi()
->beginIF($this->config->systemMode == 'new' and ($this->cookie->involved or $involved))->andWhere('t2.type')->eq('project')->fi()
->beginIF($browseType != 'all' and $browseType != 'undone' and $browseType != 'bysearch')->andWhere('t1.status')->eq($browseType)->fi()
->beginIF(!in_array($browseType, array('all', 'undone', 'bysearch', 'review'), true))->andWhere('t1.status')->eq($browseType)->fi()
->beginIF($browseType == 'undone')->andWhere('t1.status')->in('wait,doing')->fi()
->beginIF($browseType == 'review')
->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")
->andWhere('t1.reviewStatus')->eq('doing')
->fi()
->beginIF($path)->andWhere('t1.path')->like($path . '%')->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'new')->andWhere('t1.id')->in($this->app->user->view->projects)->fi()
->beginIF(!$queryAll and !$this->app->user->admin and $this->config->systemMode == 'classic')->andWhere('t1.id')->in($this->app->user->view->sprints)->fi()
@@ -721,32 +725,6 @@ class programModel extends model
->remove('delta,future,contactListMenu')
->get();
if($program->parent)
{
$parentProgram = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($program->parent)->fetch();
if($parentProgram)
{
/* Child program begin cannot less than parent. */
if(!empty($program->name) and $program->begin < $parentProgram->begin) dao::$errors['begin'] = sprintf($this->lang->program->beginLetterParent, $parentProgram->begin);
/* When parent set end then child program end cannot greater than parent. */
if(!empty($program->name) and$parentProgram->end != '0000-00-00' and $program->end > $parentProgram->end) dao::$errors['end'] = sprintf($this->lang->program->endGreaterParent, $parentProgram->end);
/* When parent set end then child program cannot set longTime. */
if(!empty($program->name) and empty($program->end) and $this->post->delta == 999 and $parentProgram->end != '0000-00-00') dao::$errors['end'] = sprintf($this->lang->program->endGreaterParent, $parentProgram->end);
/* The budget of a child program cannot beyond the remaining budget of the parent program. */
$program->budgetUnit = $parentProgram->budgetUnit;
if(isset($program->budget))
{
$availableBudget = $this->getBudgetLeft($parentProgram);
if($program->budget > $availableBudget) dao::$errors['budget'] = $this->lang->program->beyondParentBudget;
}
if(dao::isError()) return false;
}
}
/* Redefines the language entries for the fields in the project table. */
foreach(explode(',', $this->config->program->create->requiredFields) as $field)
{
@@ -817,17 +795,6 @@ class programModel extends model
$program = $this->loadModel('file')->processImgURL($program, $this->config->program->editor->edit['id'], $this->post->uid);
$children = $this->getChildren($programID);
if($children > 0)
{
$minChildBegin = $this->dao->select('type, begin as minBegin')->from(TABLE_PROGRAM)->where('id')->ne($programID)->andWhere('deleted')->eq(0)->andWhere('path')->like("%,{$programID},%")->orderBy('begin_asc')->fetch();
$maxChildEnd = $this->dao->select('type, end as maxEnd')->from(TABLE_PROGRAM)->where('id')->ne($programID)->andWhere('deleted')->eq(0)->andWhere('path')->like("%,{$programID},%")->andWhere('end')->ne('0000-00-00')->orderBy('end_desc')->fetch();
$minChildType = ($minChildBegin->type == 'project') ? $this->lang->project->common : $this->lang->program->childProgram;
$maxChildType = ($maxChildEnd->type == 'project') ? $this->lang->project->common : $this->lang->program->childProgram;
if($minChildBegin and $program->begin > $minChildBegin->minBegin) dao::$errors['begin'] = sprintf($this->lang->program->beginGreateChild, $minChildType, $minChildBegin->minBegin);
if($maxChildEnd and $program->end < $maxChildEnd->maxEnd and $this->post->delta != 999) dao::$errors['end'] = sprintf($this->lang->program->endLetterChild, $maxChildType, $maxChildEnd->maxEnd);
if(dao::isError()) return false;
}
if($program->parent)
{
@@ -836,22 +803,6 @@ class programModel extends model
->where('root')->eq($programID)
->andwhere('type')->eq('line')
->exec();
$parentProgram = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($program->parent)->fetch();
if($parentProgram)
{
if(!empty($program->name) and $program->begin < $parentProgram->begin) dao::$errors['begin'] = sprintf($this->lang->program->beginLetterParent, $parentProgram->begin);
if(!empty($program->name) and $parentProgram->end != '0000-00-00' and $program->end > $parentProgram->end) dao::$errors['end'] = sprintf($this->lang->program->endGreaterParent, $parentProgram->end);
if(!empty($program->name) and empty($program->end) and $this->post->delta == 999 and $parentProgram->end != '0000-00-00') dao::$errors['end'] = sprintf($this->lang->program->endGreaterParent, $parentProgram->end);
}
/* The budget of a child program cannot beyond the remaining budget of the parent program. */
$program->budgetUnit = $parentProgram->budgetUnit;
if($program->budget != 0)
{
$availableBudget = $this->getBudgetLeft($parentProgram);
if($program->budget > $availableBudget + $oldProgram->budget) dao::$errors['budget'] = $this->lang->program->beyondParentBudget;
}
}
if(dao::isError()) return false;
+2 -1
View File
@@ -23,7 +23,8 @@
<?php endif;?>
<div id='mainMenu' class='clearfix'>
<div class="btn-toolBar pull-left">
<?php foreach($lang->program->featureBar as $key => $label):?>
<?php common::sortFeatureMenu();?>
<?php foreach($lang->program->featureBar['browse'] as $key => $label):?>
<?php $active = $status == $key ? 'btn-active-text' : '';?>
<?php $label = "<span class='text'>$label</span>";?>
<?php echo html::a(inlink('browse', "status=$key&orderBy=$orderBy"), $label, '', "class='btn btn-link $active'");?>
+4 -4
View File
@@ -69,9 +69,9 @@
<tr>
<th><?php echo $lang->program->budget;?></th>
<td>
<div class='input-group'>
<?php $placeholder = $parentProgram ? 'placeholder=' . $lang->program->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $budgetLeft : '';?>
<?php echo html::input('budget', '', "class='form-control' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . $placeholder);?>
<div id='budgetBox' class='input-group'>
<?php $placeholder = $parentProgram ? 'placeholder="' . $lang->program->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $budgetLeft . '"' : '';?>
<?php echo html::input('budget', '', "class='form-control' onchange='budgetOverrunTips()' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . $placeholder);?>
<?php if($parentProgram):?>
<span class='input-group-addon fix-border'><?php echo zget($budgetUnitList, $parentProgram->budgetUnit);?></span>
<?php else:?>
@@ -80,7 +80,7 @@
<?php endif;?>
</div>
</td>
<td>
<td class='futureBox'>
<div class='checkbox-primary future w-70px'>
<input type='checkbox' id='future' name='future' value='1' />
<label for='future'><?php echo $lang->project->future;?></label>
+6 -4
View File
@@ -15,6 +15,7 @@
<?php js::set('weekend', $config->execution->weekend);?>
<?php js::set('longTime', $lang->program->longTime);?>
<?php js::set('currencySymbol', $lang->project->currencySymbol);?>
<?php js::set('PGMParentBudget', $lang->program->parentBudget);?>
<?php js::set('parentBudget', $lang->program->parentBudget);?>
<?php js::set('future', $lang->project->future);?>
<?php js::set('programList', $programList);?>
@@ -23,6 +24,7 @@
<?php js::set('exRateNotEmpty', sprintf($lang->error->notempty, $lang->program->exchangeRate));?>
<?php js::set('exRateNum', sprintf($lang->error->float, $lang->program->exchangeRate));?>
<?php js::set('exRateNotNegative', $lang->program->exRateNotNegative);?>
<?php js::set('programID', $program->id);?>
<?php $aclList = $program->parent ? $lang->program->subAclList : $lang->program->aclList;?>
<?php $requiredFields = $config->program->edit->requiredFields;?>
<div id='mainContent' class='main-content'>
@@ -48,9 +50,9 @@
<tr>
<th><?php echo $lang->program->budget;?></th>
<td>
<div class='input-group'>
<?php $placeholder = ($parentProgram and $parentProgram->budget != 0) ? 'placeholder=' . $lang->program->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $availableBudget : '';?>
<?php echo html::input('budget', $program->budget != 0 ? $program->budget : '', "class='form-control' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . ($program->budget == 0 ? 'disabled ' : '') . $placeholder);?>
<div id='budgetBox' class='input-group'>
<?php $placeholder = ($parentProgram and $parentProgram->budget != 0) ? 'placeholder="' . $lang->program->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $availableBudget . '"' : '';?>
<?php echo html::input('budget', $program->budget != 0 ? $program->budget : '', "class='form-control' onchange='budgetOverrunTips()' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . ($program->budget == 0 ? 'disabled ' : '') . $placeholder);?>
<?php if($parentProgram):?>
<span class='input-group-addon'><?php echo zget($budgetUnitList, $program->budgetUnit);?></span>
<?php else:?>
@@ -61,7 +63,7 @@
<?php endif;?>
</div>
</td>
<td>
<td class='futureBox'>
<div class='checkbox-primary future w-70px'>
<input type='checkbox' id='future' name='future' value='1' <?php if($program->budget == 0) echo 'checked';?> />
<label for='future'><?php echo $lang->project->future;?></label>
+2 -1
View File
@@ -17,7 +17,8 @@ js::set('browseType', $browseType);
?>
<div id="mainMenu" class="clearfix">
<div class="btn-toolBar pull-left">
<?php foreach($lang->program->featureBar as $key => $label):?>
<?php common::sortFeatureMenu('program', 'browse');?>
<?php foreach($lang->program->featureBar['browse'] as $key => $label):?>
<?php $active = $browseType == $key ? 'btn-active-text' : '';?>
<?php $label = "<span class='text'>$label</span>";?>
<?php if($browseType == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
+6 -4
View File
@@ -28,10 +28,12 @@
<a href='javascript:;' class='btn btn-link btn-limit' data-toggle='dropdown'><span class='text' title='<?php echo $viewName;?>'><?php echo $viewName;?></span> <span class='caret'></span></a>
<ul class='dropdown-menu' style='max-height:240px; max-width: 300px; overflow-y:auto'>
<?php
foreach($productList as $key => $product)
{
echo "<li>" . html::a($this->createLink('programplan', 'create', "projectID=$project->id&productID=$key"), $product) . "</li>";
}
$class = '';
foreach($productList as $key => $product)
{
$class = $productID == $key ? 'class="active"' : '';
echo "<li $class>" . html::a($this->createLink('programplan', 'create', "projectID=$project->id&productID=$key"), $product) . "</li>";
}
?>
</ul>
</div>
+34
View File
@@ -219,6 +219,40 @@ class project extends control
echo json_encode($productsWithBranch);
}
/**
* Ajax get available budget.
*
* @param int $programID
* @param int $selectedProgramID
* @param int $budget
* @access public
* @return void
*/
public function ajaxGetAvailableBudget($projectID, $selectedProgramID, $budget)
{
if(!empty($projectID))
{
$project = $this->project->getByID($projectID);
$selectedProgram = $this->loadModel('program')->getByID($selectedProgramID);
$budgetLeft = $this->program->getBudgetLeft($selectedProgram);
$availableBudget = $project->parent == $selectedProgramID ? $budgetLeft + $project->budget : $budgetLeft;
}
else
{
$selectedProgram = $this->loadModel('program')->getByID($selectedProgramID);
$availableBudget = $this->program->getBudgetLeft($selectedProgram);
}
$tip = '';
if($budget != 0 && $budget !== null && $budget > $availableBudget) $tip = "<span id='beyondBudgetTip' class='text-remind'>" . $this->lang->project->budgetOverrun . zget($this->lang->project->currencySymbol, $selectedProgram->budgetUnit) . $availableBudget . "</span>";
$placeholder = '';
if($selectedProgram and $selectedProgram->budget != 0) $placeholder = $this->lang->project->parentBudget . zget($this->lang->project->currencySymbol, $selectedProgram->budgetUnit) . $availableBudget;
$tipList = array('tip' => $tip, 'placeholder' => $placeholder);
echo json_encode($tipList);
}
/**
* Project index view.
*
+1
View File
@@ -1,2 +1,3 @@
.future {display: inline-block;}
.c-number {overflow: hidden; text-align: right !important; text-overflow: ellipsis; white-space: nowrap;}
.text-remind {color: #ffa34d;}
+3
View File
@@ -21,3 +21,6 @@
#productsBox .input-group-addon > div {display: inline-block !important;}
#plansBox .row {display: inline-table; width: 102%;}
#plansBox .col-sm-4 {float: none; display: inline-block; padding-right: 5px;}
#dataform th {vertical-align: top; padding-top: 13px;}
.futureBox {vertical-align: top !important; padding-top: 13px !important;}
#linkPlan {padding-top: 25px !important;}
+3 -1
View File
@@ -2,5 +2,7 @@
#budgetUnit {border-left: 0px;}
#plansBox .row {display: inline-table; width: 102%;}
#plansBox .col-sm-4 {float: none; display: inline-block;}
#dateRange {vertical-align: top; padding-top: 13px;}
#dateRange, .futureBox {vertical-align: top !important; padding-top: 13px !important;}
#endList {vertical-align: top; padding-top: 13px;}
#dataform th {vertical-align: top; padding-top: 13px;}
#linkPlan {padding-top: 25px !important;}
+4
View File
@@ -3,3 +3,7 @@
#executionsSummary {padding-left: 10px;}
#mainMenu .pull-left .checkbox-primary {margin-top: 5px;}
.main-table tbody>tr>td:first-child, .main-table thead>tr>th:first-child { padding-left: 8px; }
th.table-nest-title-edit {padding-left: 50px !important;}
th.table-nest-title-edit .table-nest-toggle {left: 28px;}
th.table-nest-title .check-all {position: absolute; left: 15px; top: 7px;}
+32
View File
@@ -287,6 +287,7 @@ $(function()
if($(this).prop('checked'))
{
$('#budget').val('').attr('disabled', 'disabled');
if($('#beyondBudgetTip').length > 0) $('#beyondBudgetTip').remove();
}
else
{
@@ -343,3 +344,34 @@ $(document).on('change', "#plansBox select[name^='plans']", function()
}
});
});
/**
* Append prompt when the budget exceeds the parent project set.
*
* @param int $projectID
* @access public
* @return void
*/
function budgetOverrunTips()
{
var selectedProgramID = $('#parent').val();
var budget = $('#budget').val();
if(selectedProgramID == 0)
{
if($('#beyondBudgetTip').length > 0) $('#beyondBudgetTip').remove();
return false;
}
if(typeof(projectID) == 'undefined') projectID = 0;
$.get(createLink('project', 'ajaxGetAvailableBudget', 'projectID=' + projectID + "&selectedProgramID=" + selectedProgramID + "&budget=" + budget), function(data)
{
var data = JSON.parse(data);
if($('#beyondBudgetTip').length > 0) $('#beyondBudgetTip').remove();
$('#budgetBox').after(data.tip);
if($('#budget').attr('placeholder')) $('#budget').removeAttr('placeholder')
$('#budget').attr('placeholder', data.placeholder);
});
}
+1
View File
@@ -4,6 +4,7 @@ $(function()
{
var programID = $(this).val();
setAclList(programID);
budgetOverrunTips();
/* Determine whether the project can change the project set. */
link = createLink('project', 'ajaxCheckProduct', 'programID=' + programID + '&projectID=' + projectID);
+10 -5
View File
@@ -30,12 +30,13 @@ $(function()
var checkedLength = $(":checkbox[name^='executionIDList']:checked").length;
if(checkedLength > 0) $('#executionForm').addClass('has-row-checked');
if(notCheckedLength == 0) $('.table-footer #checkAll').prop('checked', true);
if(notCheckedLength == 0) $('#executionForm .checkAll').prop('checked', true);
if(checkedLength == 0)
{
$('.table-footer #checkAll').prop('checked', false);
$('#executionForm .checkAll').prop('checked', false);
$('#executionForm').removeClass('has-row-checked');
}
if(notCheckedLength > 0) $('#executionForm .checkAll').prop('checked', false);
var summary = checkedExecutions.replace('%s', checkedLength);
if(cilentLang == "en" && checkedLength < 2) summary = summary.replace('items', 'item');
@@ -54,11 +55,12 @@ $(function()
});
$(document).on('click', ".table-footer #checkAll", function()
$(document).on('click', "#executionForm .checkAll", function()
{
if($(this).prop('checked'))
{
$(":checkbox[name^='executionIDList']").prop('checked', true);
$("#executionForm .checkAll").prop('checked', true);
$('#executionForm').addClass('has-row-checked');
var checkedLength = $(":checkbox[name^='executionIDList']:checked").length;
var summary = checkedExecutions.replace('%s', checkedLength);
@@ -72,6 +74,7 @@ $(function()
else
{
$(":checkbox[name^='executionIDList']").prop('checked', false);
$("#executionForm .checkAll").prop('checked', false);
$('#executionForm').removeClass('has-row-checked');
$('#executionSummary').removeClass('hidden');
$('#executionsSummary').addClass('hidden');
@@ -86,7 +89,7 @@ $(function()
{
$(this).prop('checked', false);
});
$('.table-footer #checkAll').prop('checked', false);
$('#executionsForm .checkAll').prop('checked', false);
}, 10);
})
@@ -195,13 +198,15 @@ function showEditCheckbox(show)
});
if(show)
{
var tableFooter = "<div class='editCheckbox'><div class='checkbox-primary check-all'><input type='checkbox' id='checkAll' /><label>" + selectAll + "</label></div><div class='table-actions btn-toolbar'><button type='submit' class='btn'>" + edit + "</button></div></div>";
$('.table-nest-title').prepend("<div class='checkbox-primary check-all'><input type='checkbox' class='checkAll' /><label></label></div>").addClass('table-nest-title-edit');
var tableFooter = "<div class='editCheckbox'><div class='checkbox-primary check-all'><input type='checkbox' id='checkAll' class='checkAll' /><label>" + selectAll + "</label></div><div class='table-actions btn-toolbar'><button type='submit' class='btn'>" + edit + "</button></div></div>";
$('#executionForm').attr('action', createLink('execution', 'batchEdit'));
$('.table-footer').prepend(tableFooter).show();
$('body').scroll();
}
else
{
$('.table-nest-title').removeClass('table-nest-title-edit').find('.check-all').remove();
$('#executionForm').find('.editCheckbox').remove();
if($('#executionForm .pager').length == 0) $('.table-footer').hide();
$('#executionForm').removeAttr('action');
+9 -6
View File
@@ -196,6 +196,7 @@ $lang->project->unlinkExecutionMember = "The user participated in %s executions
$lang->project->unlinkExecutionMembers = "The team members you are removing are also in the execution team of this project. Do you want to remove them from the execution team too?";
$lang->project->productTip = 'After clicking New Product, the project will not be linked to the selected product.';
$lang->project->noDevStage = 'There is no R&D stage under this project, or you do not have access permissions. The creation of builds is not supported at the moment.';
$lang->project->budgetOverrun = "The project's budget has exceeded the remaining budget of the parent program:";
$lang->project->tenThousand = '';
$lang->project->hundredMillion = 'Hundred Million';
@@ -241,12 +242,14 @@ $lang->project->modelList['scrum'] = "Scrum";
$lang->project->modelList['waterfall'] = "CMMI";
$lang->project->modelList['kanban'] = "Kanban";
$lang->project->featureBar['all'] = 'All';
$lang->project->featureBar['undone'] = 'Unfinished';
$lang->project->featureBar['wait'] = 'Waiting';
$lang->project->featureBar['doing'] = 'Doing';
$lang->project->featureBar['suspended'] = 'Suspended';
$lang->project->featureBar['closed'] = 'Closed';
$lang->project->featureBar['browse']['all'] = 'All';
$lang->project->featureBar['browse']['undone'] = 'Unfinished';
$lang->project->featureBar['browse']['wait'] = 'Waiting';
$lang->project->featureBar['browse']['doing'] = 'Doing';
$lang->project->featureBar['browse']['suspended'] = 'Suspended';
$lang->project->featureBar['browse']['closed'] = 'Closed';
$lang->project->featureBar['build']['all'] = 'Build List';
$lang->project->aclList['private'] = 'Private (For team members and stakeholders only)';
$lang->project->aclList['open'] = "Open (accessible with project view permissions)";
+9 -6
View File
@@ -196,6 +196,7 @@ $lang->project->unlinkExecutionMember = "The user participated in %s executions
$lang->project->unlinkExecutionMembers = "The team members you are removing are also in the execution team of this project. Do you want to remove them from the execution team too?";
$lang->project->productTip = 'After clicking New Product, the project will not be linked to the selected product.';
$lang->project->noDevStage = 'There is no R&D stage under this project, or you do not have access permissions. The creation of builds is not supported at the moment.';
$lang->project->budgetOverrun = "The project's budget has exceeded the remaining budget of the parent program:";
$lang->project->tenThousand = 'Ten Thousand';
$lang->project->hundredMillion = 'Hundred Million';
@@ -241,12 +242,14 @@ $lang->project->modelList['scrum'] = "Scrum";
$lang->project->modelList['waterfall'] = "CMMI";
$lang->project->modelList['kanban'] = "Kanban";
$lang->project->featureBar['all'] = 'All';
$lang->project->featureBar['undone'] = 'Unfinished';
$lang->project->featureBar['wait'] = 'Waiting';
$lang->project->featureBar['doing'] = 'Doing';
$lang->project->featureBar['suspended'] = 'Suspended';
$lang->project->featureBar['closed'] = 'Closed';
$lang->project->featureBar['browse']['all'] = 'All';
$lang->project->featureBar['browse']['undone'] = 'Unfinished';
$lang->project->featureBar['browse']['wait'] = 'Waiting';
$lang->project->featureBar['browse']['doing'] = 'Doing';
$lang->project->featureBar['browse']['suspended'] = 'Suspended';
$lang->project->featureBar['browse']['closed'] = 'Closed';
$lang->project->featureBar['build']['all'] = 'Build List';
$lang->project->aclList['private'] = 'Private (For the project leader, team members and stakeholders only)';
$lang->project->aclList['open'] = "Open (accessible with project view permissions)";
+9 -6
View File
@@ -196,6 +196,7 @@ $lang->project->unlinkExecutionMember = "The user participated in %s executions
$lang->project->unlinkExecutionMembers = "The team members you are removing are also in the execution team of this project. Do you want to remove them from the execution team too?";
$lang->project->productTip = 'After clicking New Product, the project will not be linked to the selected product.';
$lang->project->noDevStage = "Il n'y a pas de phase R&D dans ce projet, ou vous n'avez pas la permission d'accès. La version ne peut pas être créée pour le moment.";
$lang->project->budgetOverrun = "Le budget du projet a dépassé le budget restant du programme parent:";
$lang->project->tenThousand = '';
$lang->project->hundredMillion = 'Hundred Million';
@@ -241,12 +242,14 @@ $lang->project->modelList['scrum'] = "Scrum";
$lang->project->modelList['waterfall'] = "CMMI";
$lang->project->modelList['kanban'] = "Kanban";
$lang->project->featureBar['all'] = 'All';
$lang->project->featureBar['undone'] = 'Non Terminées';
$lang->project->featureBar['wait'] = 'En Attente';
$lang->project->featureBar['doing'] = 'En Cours';
$lang->project->featureBar['suspended'] = 'Suspendues';
$lang->project->featureBar['closed'] = 'Fermées';
$lang->project->featureBar['browse']['all'] = 'All';
$lang->project->featureBar['browse']['undone'] = 'Non Terminées';
$lang->project->featureBar['browse']['wait'] = 'En Attente';
$lang->project->featureBar['browse']['doing'] = 'En Cours';
$lang->project->featureBar['browse']['suspended'] = 'Suspendues';
$lang->project->featureBar['browse']['closed'] = 'Fermées';
$lang->project->featureBar['build']['all'] = 'Build List';
$lang->project->aclList['private'] = 'Private (For team members and stakeholders only)';
$lang->project->aclList['open'] = "Open (accessible with project view permissions)";
+7 -5
View File
@@ -160,11 +160,13 @@ $lang->project->currencySymbol['SGD'] = 'S$';
$lang->project->modelList['scrum'] = "Scrum";
$lang->project->modelList['waterfall'] = "CMMI";
$lang->project->featureBar['all'] = 'All';
$lang->project->featureBar['doing'] = 'Doing';
$lang->project->featureBar['wait'] = 'Waiting';
$lang->project->featureBar['suspended'] = 'Suspended';
$lang->project->featureBar['closed'] = 'Closed';
$lang->project->featureBar['browse']['all'] = 'All';
$lang->project->featureBar['browse']['doing'] = 'Doing';
$lang->project->featureBar['browse']['wait'] = 'Waiting';
$lang->project->featureBar['browse']['suspended'] = 'Suspended';
$lang->project->featureBar['browse']['closed'] = 'Closed';
$lang->project->featureBar['build']['all'] = 'Build List';
$lang->project->aclList['private'] = 'Private (For team members and stakeholders only)';
$lang->project->aclList['open'] = "Open (accessible with project view permissions)";
+9 -6
View File
@@ -196,6 +196,7 @@ $lang->project->unlinkExecutionMember = "该用户参与了%s%s%s个{$lang->exe
$lang->project->unlinkExecutionMembers = "移除的团队成员还参与了项目下的执行,是否同步从执行团队中移除?";
$lang->project->productTip = '点击新建产品后,项目将不会关联已选中的产品。';
$lang->project->noDevStage = '该项目下没有研发类型的阶段,或者您没有权限访问,暂时不支持创建版本。';
$lang->project->budgetOverrun = '项目的预算已超出父项目集的剩余预算:';
$lang->project->tenThousand = '万';
$lang->project->hundredMillion = '亿';
@@ -241,12 +242,14 @@ $lang->project->modelList['scrum'] = "Scrum";
$lang->project->modelList['waterfall'] = "瀑布";
$lang->project->modelList['kanban'] = "看板";
$lang->project->featureBar['all'] = '所有';
$lang->project->featureBar['undone'] = '未完成';
$lang->project->featureBar['wait'] = '未开始';
$lang->project->featureBar['doing'] = '进行中';
$lang->project->featureBar['suspended'] = '已挂起';
$lang->project->featureBar['closed'] = '已关闭';
$lang->project->featureBar['browse']['all'] = '所有';
$lang->project->featureBar['browse']['undone'] = '未完成';
$lang->project->featureBar['browse']['wait'] = '未开始';
$lang->project->featureBar['browse']['doing'] = '进行中';
$lang->project->featureBar['browse']['suspended'] = '已挂起';
$lang->project->featureBar['browse']['closed'] = '已关闭';
$lang->project->featureBar['build']['all'] = '所有版本';
$lang->project->aclList['private'] = "私有 (只有项目负责人、团队成员和干系人可访问)";
$lang->project->aclList['open'] = "公开 (有项目视图权限即可访问)";
+7 -64
View File
@@ -259,7 +259,7 @@ class projectModel extends model
{
if($project->parent == 0) return '';
$parentName = $this->dao->select('id,name')->from(TABLE_PROGRAM)->where('id')->in(trim($project->path, ','))->andWhere('grade')->lt($project->grade)->fetchPairs();
$parentName = $this->dao->select('id,name')->from(TABLE_PROGRAM)->where('id')->in(trim($project->path, ','))->andWhere('grade')->lt($project->grade)->orderBy('grade asc')->fetchPairs();
$parentProgram = '';
foreach($parentName as $name) $parentProgram .= $name . '/';
@@ -1107,29 +1107,11 @@ class projectModel extends model
if($project->parent)
{
$program = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($project->parent)->fetch();
if($program)
{
/* Child project begin cannot less than parent. */
if(!empty($project->name) and $project->begin < $program->begin) dao::$errors['begin'] = sprintf($this->lang->project->beginGreateChild, $program->begin);
/* When parent set end then child project end cannot greater than parent. */
if(!empty($project->name) and $program->end != '0000-00-00' and $project->end > $program->end) dao::$errors['end'] = sprintf($this->lang->project->endLetterChild, $program->end);
if(dao::isError()) return false;
}
/* The budget of a child project cannot beyond the remaining budget of the parent program. */
$project->budgetUnit = $program->budgetUnit;
if(isset($project->budget) and $program->budget != 0)
{
$availableBudget = $this->loadModel('program')->getBudgetLeft($program);
if($availableBudget > 0 and $project->budget > $availableBudget) dao::$errors['budget'] = $this->lang->program->beyondParentBudget;
}
/* Judge products not empty. */
if(empty($linkedProductsCount) and !isset($_POST['newProduct']))
{
dao::$errors[] = $this->lang->project->productNotEmpty;
dao::$errors['products0'] = $this->lang->project->productNotEmpty;
return false;
}
}
@@ -1369,30 +1351,6 @@ class projectModel extends model
->remove('products,branch,plans,delta,future,contactListMenu,teamMembers')
->get();
if($project->parent)
{
$program = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($project->parent)->fetch();
if($program)
{
/* Child project begin cannot less than parent. */
if(!empty($project->name) and $project->begin < $program->begin) dao::$errors['begin'] = sprintf($this->lang->project->beginGreateChild, $program->begin);
/* When parent set end then child project end cannot greater than parent. */
if(!empty($project->name) and $program->end != '0000-00-00' and $project->end > $program->end) dao::$errors['end'] = sprintf($this->lang->project->endLetterChild, $program->end);
if(dao::isError()) return false;
}
/* The budget of a child project cannot beyond the remaining budget of the parent project. */
$project->budgetUnit = $program->budgetUnit;
if($project->budget != 0 and $program->budget != 0)
{
$availableBudget = $this->loadModel('program')->getBudgetLeft($program);
if($project->budget > $availableBudget + $oldProject->budget) dao::$errors['budget'] = $this->lang->program->beyondParentBudget;
}
}
$executionsCount = $this->dao->select('COUNT(*) as count')->from(TABLE_PROJECT)
->where('project')->eq($project->id)
->andWhere('deleted')->eq('0')
@@ -1553,25 +1511,6 @@ class projectModel extends model
$projects[$projectID]->lastEditedDate = helper::now();
if(isset($data->codes)) $projects[$projectID]->code = $projectCode;
if($projects[$projectID]->parent)
{
$parentProject = $this->dao->select('*')->from(TABLE_PROGRAM)->where('id')->eq($projects[$projectID]->parent)->fetch();
if($parentProject)
{
/* Child project begin cannot less than parent. */
if(!empty($projects[$projectID]->name) and $projects[$projectID]->begin < $parentProject->begin)
{
dao::$errors[] = "ID {$projects[$projectID]->id}" . sprintf($this->lang->project->beginGreateChild, $parentProject->begin) . "\n";
}
/* When parent set end then child project end cannot greater than parent. */
if(!empty($projects[$projectID]->name) and $parentProject->end != '0000-00-00' and $projects[$projectID]->end > $parentProject->end)
{
dao::$errors[] = "ID {$projects[$projectID]->id}" . sprintf($this->lang->project->endLetterChild, $parentProject->end) . "\n";
}
}
}
foreach($extendFields as $extendField)
{
@@ -2387,7 +2326,11 @@ class projectModel extends model
->beginIF($projectID == 0 and $this->config->vision)->andWhere('t1.vision')->eq($this->config->vision)->fi()
->beginIF(!empty($myExecutionIDList))->andWhere('t1.id')->in(array_keys($myExecutionIDList))->fi()
->beginIF($status == 'undone')->andWhere('t1.status')->notIN('done,closed')->fi()
->beginIF($status != 'all' and $status != 'undone' and $status != 'involved')->andWhere('t1.status')->eq($status)->fi()
->beginIF(!in_array($status, array('all', 'undone', 'involved', 'review'), true))->andWhere('t1.status')->eq($status)->fi()
->beginIF($status == 'review')
->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")
->andWhere('t1.reviewStatus')->eq('doing')
->fi()
->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->sprints)->fi()
->andWhere('t1.vision')->eq($this->config->vision)
->andWhere('t1.deleted')->eq('0')
+2 -1
View File
@@ -59,7 +59,8 @@
<div class="btn-toolBar pull-left">
<?php $excludedEmptyPrograms = array_filter($programs);?>
<div class="input-control w-150px" id='programBox'><?php echo html::select('programID', $programs, $programID, "onchange=changeProgram(this.value) class='form-control chosen' data-placeholder='{$lang->project->selectProgram}' data-drop_width='" . (empty($excludedEmptyPrograms) ? 170 : 450) . "' data-max_drop_width='0'");?></div>
<?php foreach($lang->project->featureBar as $key => $label):?>
<?php common::sortFeatureMenu();?>
<?php foreach($lang->project->featureBar['browse'] as $key => $label):?>
<?php $active = $browseType == $key ? 'btn-active-text' : '';?>
<?php $label = "<span class='text'>$label</span>";?>
<?php if($browseType == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
+2 -1
View File
@@ -33,7 +33,8 @@
</div>
<?php endif;?>
<div class="btn-toolBar pull-left">
<?php foreach($lang->project->featureBar as $key => $label):?>
<?php common::sortFeatureMenu();?>
<?php foreach($lang->project->featureBar['browse'] as $key => $label):?>
<?php $active = $browseType == $key ? 'btn-active-text' : '';?>
<?php $label = "<span class='text'>$label</span>";?>
<?php if($browseType == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
+6 -6
View File
@@ -20,14 +20,14 @@
<div id="mainMenu" class="clearfix table-row">
<div class="btn-toolbar pull-left">
<?php
$label = "<span class='text'>{$lang->execution->build}</span>";
$active = '';
if($type == 'all')
common::sortFeatureMenu();
foreach($lang->project->featureBar['build'] as $featureType => $label)
{
$active = 'btn-active-text';
$label .= " <span class='label label-light label-badge'>{$buildsTotal}</span>";
$activeClass = $type == $featureType ? 'btn-active-text' : '';
$label = "<span class='text'>$label</span>";
if($type == $featureType) $label .= " <span class='label label-light label-badge'>{$buildsTotal}</span>";
echo html::a(inlink('build', "projectID=$projectID&type=$featureType"), $label, '',"class='btn btn-link $activeClass' data-app={$app->tab} id=" . $featureType .'Tab');
}
echo html::a(inlink('build', "projectID=$projectID&type=all"), $label, '', "class='btn btn-link $active' id='all'")
?>
<div class="input-control space w-150px"><?php echo html::select('product', $products, $product, "onchange='changeProduct(this.value)' class='form-control chosen' data-placeholder='{$lang->productCommon}'");?></div>
<a class="btn btn-link querybox-toggle" id="bysearchTab"><i class="icon icon-search muted"></i> <?php echo $lang->execution->byQuery;?></a>
+5 -5
View File
@@ -68,9 +68,9 @@
<tr>
<th><?php echo $lang->project->budget;?></th>
<td>
<div class='input-group'>
<?php $placeholder = ($parentProgram and $parentProgram->budget != 0) ? 'placeholder=' . $lang->program->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $availableBudget : '';?>
<?php echo html::input('budget', '', "class='form-control' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . $placeholder);?>
<div id='budgetBox' class='input-group'>
<?php $placeholder = ($parentProgram and $parentProgram->budget != 0) ? 'placeholder="' . $lang->program->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $availableBudget . '"' : '';?>
<?php echo html::input('budget', '', "class='form-control' onchange='budgetOverrunTips()' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . $placeholder);?>
<?php if($parentProgram):?>
<span class='input-group-addon'><?php echo zget($budgetUnitList, $parentProgram->budgetUnit);?></span>
<?php else:?>
@@ -79,7 +79,7 @@
<?php endif;?>
</div>
</td>
<td>
<td class='futureBox'>
<div class="checkbox-primary c-future <?php echo strpos($requiredFields, 'budget') !== false ? 'hidden' : '';?>">
<input type='checkbox' id='future' name='future' value='1' />
<label for='future'><?php echo $lang->project->future;?></label>
@@ -145,7 +145,7 @@
</td>
</tr>
<tr>
<th><?php echo $lang->execution->linkPlan;?></th>
<th id='linkPlan'><?php echo $lang->execution->linkPlan;?></th>
<td colspan="3" id="plansBox">
<div class='row'>
<?php if($copyProjectID):?>
+5 -5
View File
@@ -74,9 +74,9 @@
<tr>
<th><?php echo $lang->project->budget;?></th>
<td>
<div class='input-group'>
<?php $placeholder = ($parentProgram and $parentProgram->budget != 0) ? 'placeholder=' . $lang->project->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $availableBudget : '';?>
<?php echo html::input('budget', $project->budget != 0 ? $project->budget : '', "class='form-control' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . ($project->budget == 0 ? 'disabled ' : '') . $placeholder);?>
<div id='budgetBox' class='input-group'>
<?php $placeholder = ($parentProgram and $parentProgram->budget != 0) ? 'placeholder="' . $lang->project->parentBudget . zget($lang->project->currencySymbol, $parentProgram->budgetUnit) . $availableBudget . '"' : '';?>
<?php echo html::input('budget', $project->budget != 0 ? $project->budget : '', "class='form-control' onchange='budgetOverrunTips($project->id)' maxlength='10' " . (strpos($requiredFields, 'budget') !== false ? 'required ' : '') . ($project->budget == 0 ? 'disabled ' : '') . $placeholder);?>
<?php if($parentProgram):?>
<span class='input-group-addon'><?php echo zget($budgetUnitList, $project->budgetUnit);?></span>
<?php else:?>
@@ -85,7 +85,7 @@
<?php endif;?>
</div>
</td>
<td>
<td class='futureBox'>
<div class='checkbox-primary'>
<input type='checkbox' id='future' name='future' value='1' <?php if($project->budget == 0) echo 'checked';?> />
<label for='future'><?php echo $lang->project->future;?></label>
@@ -153,7 +153,7 @@
</td>
</tr>
<tr>
<th><?php echo $lang->execution->linkPlan;?></th>
<th id='linkPlan'><?php echo $lang->execution->linkPlan;?></th>
<td id="plansBox" colspan="3">
<div class='row'>
<?php $i = 0;?>
+1
View File
@@ -22,6 +22,7 @@
?>
</ul>
</div>
<?php common::sortFeatureMenu('execution', 'all');?>
<?php foreach($lang->execution->featureBar['all'] as $key => $label):?>
<?php $label = "<span class='text'>$label</span>";?>
<?php if($status == $key) $label .= " <span class='label label-light label-badge'>{$pager->recTotal}</span>";?>
+1 -1
View File
@@ -16,7 +16,7 @@
<div class='clearfix' id='mainMenu'>
<div class='btn-toolbar pull-left'>
<?php
foreach($lang->project->featureBar as $label => $labelName)
foreach($lang->project->featureBar['browse'] as $label => $labelName)
{
$active = $browseType == $label ? 'btn-active-text' : '';
echo html::a($this->createLink('project', 'index', "projectID=$project->id&browseType=" . $label), '<span class="text">' . $labelName . '</span> ' . ($browseType == $label ? "<span class='label label-light label-badge'>" . (int)count($kanbanList) . '</span>' : ''), '', "class='btn btn-link $active'");
+4
View File
@@ -27,3 +27,7 @@ $lang->projectrelease->unlinkBug = 'Unlink Bug';
$lang->projectrelease->export = 'Export as HTML';
$lang->projectrelease->browseAction = "Release List";
$lang->projectrelease->notify = 'notify';
$lang->projectrelease->featureBar['browse']['all'] = 'All';
$lang->projectrelease->featureBar['browse']['normal'] = 'Active';
$lang->projectrelease->featureBar['browse']['terminate'] = 'Terminated';
+4
View File
@@ -27,3 +27,7 @@ $lang->projectrelease->unlinkBug = 'Unlink Bug';
$lang->projectrelease->export = 'Export as HTML';
$lang->projectrelease->browseAction = "Release List";
$lang->projectrelease->notify = 'notify';
$lang->projectrelease->featureBar['browse']['all'] = 'All';
$lang->projectrelease->featureBar['browse']['normal'] = 'Active';
$lang->projectrelease->featureBar['browse']['terminate'] = 'Terminated';
+4
View File
@@ -27,3 +27,7 @@ $lang->projectrelease->unlinkBug = 'Unlink Bug';
$lang->projectrelease->export = 'Export HTML';
$lang->projectrelease->browseAction = "Release List";
$lang->projectrelease->notify = 'notify';
$lang->projectrelease->featureBar['browse']['all'] = 'All';
$lang->projectrelease->featureBar['browse']['normal'] = 'Active';
$lang->projectrelease->featureBar['browse']['terminate'] = 'Terminated';
+4
View File
@@ -27,3 +27,7 @@ $lang->projectrelease->unlinkBug = 'Unlink Bug';
$lang->projectrelease->export = 'Xuất ra HTML';
$lang->projectrelease->browseAction = "Release List";
$lang->projectrelease->notify = 'notify';
$lang->projectrelease->featureBar['browse']['all'] = 'All';
$lang->projectrelease->featureBar['browse']['normal'] = 'Active';
$lang->projectrelease->featureBar['browse']['terminate'] = 'Terminated';
+4
View File
@@ -27,3 +27,7 @@ $lang->projectrelease->unlinkBug = '移除Bug';
$lang->projectrelease->export = '导出HTML';
$lang->projectrelease->browseAction = "发布列表";
$lang->projectrelease->notify = "通知";
$lang->projectrelease->featureBar['browse']['all'] = '全部';
$lang->projectrelease->featureBar['browse']['normal'] = '正常';
$lang->projectrelease->featureBar['browse']['terminate'] = '停止维护';
+2 -1
View File
@@ -57,7 +57,8 @@ class projectreleaseModel extends model
->leftJoin(TABLE_BUILD)->alias('t3')->on('t1.build = t3.id')
->leftJoin(TABLE_EXECUTION)->alias('t4')->on('t3.execution = t4.id')
->where('t1.project')->eq((int)$projectID)
->beginIF($type != 'all')->andWhere('t1.status')->eq($type)->fi()
->beginIF($type != 'all' && $type != 'review')->andWhere('t1.status')->eq($type)->fi()
->beginIF($type == 'review')->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")->fi()
->andWhere('t1.deleted')->eq(0)
->orderBy($orderBy)
->fetchAll();
+8 -3
View File
@@ -16,9 +16,14 @@
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<?php
echo html::a(inlink('browse', "projectID=$projectID&executionID=$executionID&type=all"), "<span class='text'>{$lang->release->all}</span>" . ($type == 'all' ? ' <span class="label label-light label-badge">' . count($releases) . '</span>' : ''), '', "id='allTab' class='btn btn-link" . ('all' == $type ? ' btn-active-text' : '') . "' data-app='$from'");
echo html::a(inlink('browse', "projectID=$projectID&executionID=$executionID&type=normal"), "<span class='text'>{$lang->release->statusList['normal']}</span>" . ($type == 'normal' ? ' <span class="label label-light label-badge">' . count($releases) . '</span>' : ''), '', "id='normalTab' class='btn btn-link" . ('normal' == $type ? ' btn-active-text' : '') . "' data-app='$from'");
echo html::a(inlink('browse', "projectID=$projectID&executionID=$executionID&type=terminate"), "<span class='text'>{$lang->release->statusList['terminate']}</span>" . ($type == 'terminate' ? ' <span class="label label-light label-badge">' . count($releases) . '</span>' : ''), '', "id='terminateTab' class='btn btn-link" . ('terminate' == $type ? ' btn-active-text' : '') . "' data-app='$from'");
common::sortFeatureMenu();
foreach($lang->projectrelease->featureBar['browse'] as $featureType => $label)
{
$active = $type == $featureType ? 'btn-active-text' : '';
$label = "<span class='text'>$label</span>";
if($type == $featureType) $label .= " <span class='label label-light label-badge'>" . count($releases) . "</span>";
echo html::a(inlink('browse', "projectID={$projectID}&executionID=$executionID&type=$featureType"), $label, '', "id='{$featureType}Tab' data-app='$from' class='btn btn-link $active'");
}
?>
</div>
<div class="btn-toolbar pull-right">

Some files were not shown because too many files have changed in this diff Show More