Merge branch 'sprint/272' of https://gitlab.zcorp.cc/easycorp/zentaopms into sprint/272_tianshujie

This commit is contained in:
田淑杰
2022-12-16 08:40:13 +08:00
40 changed files with 193 additions and 156 deletions
+1 -1
View File
@@ -87,7 +87,7 @@ class taskEntry extends entry
$task->preAndNext['pre'] = $preAndNext->pre ? $preAndNext->pre->id : '';
$task->preAndNext['next'] = $preAndNext->next ? $preAndNext->next->id : '';
$execution = $this->loadModel('project')->getByID($task->execution, 'execution');
$execution = $this->loadModel('project')->getByID($task->execution, 'execution,sprint');
$task->executionStatus = $execution->status;
return $this->send(200, $this->format($task, 'deadline:date,openedBy:user,openedDate:time,assignedTo:user,assignedDate:time,realStarted:time,finishedBy:user,finishedDate:time,closedBy:user,closedDate:time,canceledBy:user,canceledDate:time,lastEditedBy:user,lastEditedDate:time,deleted:bool,mailto:userList'));
+1 -3
View File
@@ -36,9 +36,7 @@ class taskRecordEstimateEntry extends entry
if(!$data) return $this->error('error');
if(isset($data->status) and $data->status == 'fail') return $this->sendError(zget($data, 'code', 400), $data->message);
$effort = new stdclass();
if($issetEffort and $data->data->efforts) $effort = $data->data->efforts;
if(!$issetEffort and $data->data->estimates) $effort = $data->data->estimates;
$effort = $data->data->efforts ? $data->data->efforts : new stdclass();
return $this->send(200, array('effort' => $effort));
}
+19 -15
View File
@@ -183,7 +183,8 @@ class build extends control
$builds = $this->build->getBuildPairs($build->product, 'all', 'noempty,notrunk,singled,separate', $build->project, 'project', $build->builds, false);
}
$executions = $this->product->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project, 'stagefilter');
$executions = $this->product->getExecutionPairsByProduct($build->product, $build->branch, 'id_desc', $this->session->project, 'stagefilter');
$executionType = $build->execution ? $this->execution->getByID($build->execution) : '';
if($build->execution and !isset($executions[$build->execution])) $executions[$build->execution] = $this->loadModel('execution')->getById($build->execution)->name;
/* Get stories and bugs. */
@@ -218,6 +219,7 @@ class build extends control
$this->view->orderBy = $orderBy;
$this->view->oldBranch = $oldBranch;
$this->view->executions = $executions;
$this->view->executionType = (!empty($executionType) and $executionType->type == 'stage') ? 1 : 0;
$this->view->productGroups = $productGroups;
$this->view->products = $products;
$this->view->users = $this->loadModel('user')->getPairs('noletter', $build->builder);
@@ -302,7 +304,8 @@ class build extends control
$objectID = $build->execution;
}
$executions = $this->loadModel('execution')->getPairs($this->session->project, 'all', 'empty');
$executions = $this->loadModel('execution')->getPairs($this->session->project, 'all', 'empty');
$executionType = $build->execution ? $this->execution->getByID($build->execution) : '';
$this->commonActions($build->project);
@@ -329,19 +332,20 @@ class build extends control
/* Assign. */
$this->view->canBeChanged = common::canBeChanged('build', $build); // Determines whether an object is editable.
$this->view->users = $this->loadModel('user')->getPairs('noletter');
$this->view->build = $build;
$this->view->buildPairs = $this->build->getBuildPairs(0, 'all', 'noempty,notrunk', $objectID, $objectType);
$this->view->builds = $this->build->getByList(array_keys($this->view->buildPairs));
$this->view->executions = $executions;
$this->view->actions = $this->loadModel('action')->getList('build', $buildID);
$this->view->link = $link;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->view->bugs = $bugs;
$this->view->type = $type;
$this->view->bugPager = $bugPager;
$this->view->branchName = empty($branchName) ? $this->lang->branch->main : $branchName;
$this->view->childBuilds = empty($build->builds) ? array() : $this->dao->select('id,name,bugs,stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
$this->view->build = $build;
$this->view->buildPairs = $this->build->getBuildPairs(0, 'all', 'noempty,notrunk', $objectID, $objectType);
$this->view->builds = $this->build->getByList(array_keys($this->view->buildPairs));
$this->view->executions = $executions;
$this->view->actions = $this->loadModel('action')->getList('build', $buildID);
$this->view->link = $link;
$this->view->param = $param;
$this->view->orderBy = $orderBy;
$this->view->bugs = $bugs;
$this->view->type = $type;
$this->view->bugPager = $bugPager;
$this->view->branchName = empty($branchName) ? $this->lang->branch->main : $branchName;
$this->view->childBuilds = empty($build->builds) ? array() : $this->dao->select('id,name,bugs,stories')->from(TABLE_BUILD)->where('id')->in($build->builds)->fetchAll();
$this->view->executionType = (!empty($executionType) and $executionType->type == 'stage') ? 1 : 0;
if($this->app->getViewType() == 'json')
{
+1 -2
View File
@@ -20,8 +20,7 @@ function loadBranches(productID)
oldBranch = productGroups[productID]['branches'];
}
projectID = currentTab == 'execution' ? executionID : projectID;
$.get(createLink('branch', 'ajaxGetBranches', 'productID=' + productID + '&oldBranch=0&param=active&projectID=' + projectID + '&withMainBranch=true&isSiblings=no&fieldID=0&multiple=multiple'), function(data)
$.get(createLink('branch', 'ajaxGetBranches', 'productID=' + productID + '&oldBranch=0&param=active&projectID=' + $('#execution').val() + '&withMainBranch=true&isSiblings=no&fieldID=0&multiple=multiple'), function(data)
{
if(data)
{
+1
View File
@@ -34,6 +34,7 @@ $lang->build->branch = 'Platform/Branch';
$lang->build->branchAll = 'All associated %s';
$lang->build->branchName = '%s';
$lang->build->execution = $lang->executionCommon;
$lang->build->executionAB = 'execution';
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
+1
View File
@@ -34,6 +34,7 @@ $lang->build->branch = 'Platform/Branch';
$lang->build->branchAll = 'All associated %s';
$lang->build->branchName = '%s';
$lang->build->execution = $lang->executionCommon;
$lang->build->executionAB = 'execution';
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
+1
View File
@@ -34,6 +34,7 @@ $lang->build->branch = 'Plateforme/Branche';
$lang->build->branchAll = 'All associated %s';
$lang->build->branchName = '%s';
$lang->build->execution = $lang->executionCommon;
$lang->build->executionAB = 'execution';
$lang->build->integrated = 'Integrated';
$lang->build->singled = 'Singled';
$lang->build->builds = 'Included Builds';
+1
View File
@@ -34,6 +34,7 @@ $lang->build->branch = '平台/分支';
$lang->build->branchAll = '所有关联%s';
$lang->build->branchName = '所属%s';
$lang->build->execution = '所属' . $lang->executionCommon;
$lang->build->executionAB = '所属执行';
$lang->build->integrated = '集成版本';
$lang->build->singled = '单一版本';
$lang->build->builds = '包含版本';
+25 -2
View File
@@ -256,10 +256,11 @@ class buildModel extends model
->beginIF(strpos($params, 'hasdeleted') === false)->andWhere('deleted')->eq(0)->fi()
->fetchPairs();
}
$branchPairs = $this->dao->select('id,name')->from(TABLE_BRANCH)->fetchPairs();
$shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where('product')->in($products)->fetchPairs('shadow', 'shadow');
$branchs = strpos($params, 'separate') === false ? "0,$branch" : $branch;
$allBuilds = $this->dao->select('t1.id, t1.name, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t4.name as branchName, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
$allBuilds = $this->dao->select('t1.id, t1.name, t1.branch, t1.execution, t1.date, t1.deleted, t2.status as objectStatus, t3.id as releaseID, t3.status as releaseStatus, t5.type as productType')->from(TABLE_BUILD)->alias('t1')
->beginIF($objectType === 'execution')->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution = t2.id')->fi()
->beginIF($objectType === 'project')->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')->fi()
->leftJoin(TABLE_RELEASE)->alias('t3')->on("FIND_IN_SET(t1.id,t3.build)")
@@ -289,7 +290,29 @@ class buildModel extends model
if((strpos($params, 'withexecution') !== false) and $build->execution and isset($executions[$build->execution])) continue;
if($build->deleted == 1) $build->name .= ' (' . $this->lang->build->deleted . ')';
$branchName = $build->branchName ? $build->branchName : $this->lang->branch->main;
if(!empty($build->branch))
{
$branchName = '';
foreach(explode(',', $build->branch) as $buildBranch)
{
if(empty($buildBranch))
{
$branchName .= $this->lang->branch->main;
}
else
{
$branchName .= isset($branchPairs[$buildBranch]) ? $branchPairs[$buildBranch] : '';
}
$branchName .= ',';
}
$branchName = trim($branchName, ',');
}
else
{
$branchName = $this->lang->branch->main;
}
$buildName = $build->name;
if(strpos($params, 'withbranch') !== false and $build->productType != 'normal') $buildName = $branchName . '/' . $buildName;
+1 -1
View File
@@ -64,7 +64,7 @@
</td>
</tr>
<?php elseif(!empty($multipleProject)):?>
<th class='w-120px'><?php echo $lang->build->execution;?></th>
<th class='w-120px'><?php echo $executionType ? $lang->build->executionAB : $lang->build->execution;?></th>
<td id='executionsBox'><?php echo html::select('execution', $executions, $build->execution, "class='form-control chosen' required $disabled");?></td>
<td><?php if($disabled) echo $lang->build->notice->changeExecution;?></td>
<?php endif;?>
+1 -1
View File
@@ -384,7 +384,7 @@ tbody tr td:first-child input {display: none;}
</tr>
<?php if($build->execution):?>
<tr>
<th><?php echo empty($multipleProject) ? $lang->build->project : $lang->build->execution;?></th>
<th><?php echo empty($multipleProject) ? $lang->build->project :($executionType ? $lang->build->executionAB : $lang->build->execution);?></th>
<td><?php echo zget($executions, $build->execution);?></td>
</tr>
<?php else:?>
+3 -1
View File
@@ -3132,6 +3132,7 @@ class execution extends control
$unmodifiableProducts = array();
$unmodifiableBranches = array();
$linkedStoryIDList = array();
$linkedBranchIdList = array();
foreach($linkedProducts as $productID => $linkedProduct)
{
$linkedBranches[$productID] = array();
@@ -3139,6 +3140,7 @@ class execution extends control
foreach($branches[$productID] as $branchID => $branch)
{
$linkedBranches[$productID][$branchID] = $branchID;
$linkedBranchIdList[$branchID] = $branchID;
if(!empty($executionStories[$productID][$branchID]))
{
array_push($unmodifiableProducts, $productID);
@@ -3158,7 +3160,7 @@ class execution extends control
$this->view->unmodifiableBranches = $unmodifiableBranches;
$this->view->linkedBranches = $linkedBranches;
$this->view->linkedStoryIDList = $linkedStoryIDList;
$this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($allProducts), $execution->project, 'ignoreNormal|noclosed');
$this->view->branchGroups = $this->execution->getBranchByProduct(array_keys($allProducts), $execution->project, 'ignoreNormal|noclosed', $linkedBranchIdList);
$this->view->allBranches = $this->execution->getBranchByProduct(array_keys($allProducts), $execution->project, 'ignoreNormal');
$this->display();
+1 -1
View File
@@ -80,7 +80,7 @@ class productplan extends control
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $planID));
if(isonlybody()) return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'closeModal' => true, 'callback' => 'parent.refreshPlan()'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink($this->app->rawModule, 'browse', "productID=$productID&branch=$branchID&browseType=all")));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->createLink($this->app->rawModule, 'browse', "productID=$productID")));
}
$this->commonAction($productID, $branchID);
+3 -1
View File
@@ -2236,6 +2236,7 @@ class project extends control
}
$linkedBranches = array();
$linkedBranchIdList = array();
$branches = $this->project->getBranchesByProject($projectID);
$linkedProductIdList = empty($branches) ? '' : array_keys($branches);
$allProducts = $this->program->getProductPairs($project->parent, 'all', 'noclosed', $linkedProductIdList);
@@ -2253,6 +2254,7 @@ class project extends control
foreach($branches[$productID] as $branchID => $branch)
{
$linkedBranches[$productID][$branchID] = $branchID;
$linkedBranchIdList[$branchID] = $branchID;
if(!empty($projectStories[$productID][$branchID]) or !empty($projectBranches[$productID][$branchID]))
{
@@ -2263,7 +2265,7 @@ class project extends control
}
}
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed');
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed', $linkedBranchIdList);
if($this->config->systemMode == 'ALM')
{
$topProgramID = $project->parent ? $this->program->getTopByPath($project->path) : 0;
+2
View File
@@ -6,3 +6,5 @@
.c-days {width: 100px;}
.c-hours {width: 90px;}
.c-limited {width: 110px;}
.picker-drop-menu[id^="pickerDropMenu-pk_"] .picker-option-list > .picker-user-option,
.picker-drop-menu[id*=" pickerDropMenu-pk_"] .picker-option-list > .picker-user-option {display: flex; align-items: center;}
+13 -9
View File
@@ -753,11 +753,14 @@ class projectModel extends model
public function getStatData($projectID)
{
$executions = $this->loadModel('execution')->getPairs($projectID);
$storyCount = $this->dao->select('count(t2.story) as storyCount')->from(TABLE_STORY)->alias('t1')
$storyTypeCount = $this->dao->select('count(t2.story) as storyCount,t1.type')->from(TABLE_STORY)->alias('t1')
->leftJoin(TABLE_PROJECTSTORY)->alias('t2')->on('t1.id = t2.story')
->where('t2.project')->eq($projectID)
->andWhere('t1.deleted')->eq(0)
->fetch('storyCount');
->groupBy('t1.type')
->fetchPairs('type', 'storyCount');
$storyCount = isset($storyTypeCount['story']) ? $storyTypeCount['story'] : 0;
$requirementCount = isset($storyTypeCount['requirement']) ? $storyTypeCount['requirement'] : 0;
$taskCount = $this->dao->select('count(id) as taskCount')->from(TABLE_TASK)->where('execution')->in(array_keys($executions))->andWhere('deleted')->eq(0)->fetch('taskCount');
$bugCount = $this->dao->select('count(id) as bugCount')->from(TABLE_BUG)->where('project')->in($projectID)->andWhere('deleted')->eq(0)->fetch('bugCount');
@@ -773,13 +776,14 @@ class projectModel extends model
->fetch('count');
$statData = new stdclass();
$statData->storyCount = $storyCount;
$statData->taskCount = $taskCount;
$statData->bugCount = $bugCount;
$statData->waitCount = zget($statusPairs, 'wait', 0);
$statData->doingCount = zget($statusPairs, 'doing', 0);
$statData->finishedCount = $finishedCount;
$statData->delayedCount = $delayedCount;
$statData->storyCount = $storyCount;
$statData->requirementCount = $requirementCount;
$statData->taskCount = $taskCount;
$statData->bugCount = $bugCount;
$statData->waitCount = zget($statusPairs, 'wait', 0);
$statData->doingCount = zget($statusPairs, 'doing', 0);
$statData->finishedCount = $finishedCount;
$statData->delayedCount = $delayedCount;
return $statData;
}
+19
View File
@@ -242,6 +242,24 @@
<div class="detail-content">
<table class="table table-data data-basic">
<tbody>
<?php if(empty($project->hasProduct) and !empty($config->URAndSR) and $project->model !== 'kanban' and isset($lang->project->menu->storyGroup)):?>
<tr>
<th><?php echo $lang->story->common;?></th>
<td title="<?php echo $statData->storyCount;?>"><?php echo $statData->storyCount;?></td>
<th><?php echo $lang->requirement->common;?></th>
<td title="<?php echo $statData->requirementCount;?>"><?php echo $statData->requirementCount;?></td>
</tr>
<tr>
<th><?php echo $lang->task->common;?></th>
<td title="<?php echo $statData->taskCount;?>"><?php echo $statData->taskCount;?></td>
<th><?php echo $lang->bug->common;?></th>
<td title="<?php echo $statData->bugCount;?>"><?php echo $statData->bugCount;?></td>
</tr>
<tr>
<th><?php echo $lang->project->budget;?></th>
<td title="<?php echo $project->budget;?>"><?php echo $project->budget;?></td>
</tr>
<?php else:?>
<tr>
<th><?php echo $lang->story->common;?></th>
<td title="<?php echo $statData->storyCount;?>"><?php echo $statData->storyCount;?></td>
@@ -254,6 +272,7 @@
<th><?php echo $lang->project->budget;?></th>
<td title="<?php echo $project->budget;?>"><?php echo $project->budget;?></td>
</tr>
<?php endif;?>
</tbody>
</table>
</div>
+2 -2
View File
@@ -78,9 +78,9 @@ class projectreleaseModel extends model
$branchName = '';
if($release->branch != 'normal')
{
foreach(explode(',', $release->branch) as $releaseBranch)
foreach(explode(',', trim($release->branch)) as $releaseBranch)
{
$branchName .= $this->loadModel('branch')->getById($releaseBranch);
$branchName .= $this->loadModel('branch')->getById($releaseBranch, $release->product);
$branchName .= ',';
}
$branchName = trim($branchName, ',');
+3 -3
View File
@@ -46,7 +46,7 @@ section.active {border: 1px solid rgb(0, 166, 255);}
#infoList > li.dropdown .dropdown-menu > li {line-height: 1; height: 20px;}
#infoList > li.dropdown .dropdown-menu > li .todoStatus {display: inline-block; width: 80px;}
#actionData {width: 525px; height: 330px; margin: 0px 20px;}
#actionData {width: 525px; height: 330px; margin: 0px 15px;}
#actionData > div {margin-top: 13px;}
#actionData > div > ul > li {margin-bottom: 3px; cursor: default;}
#actionData > div > ul > li .dropdown-menu {background-color: #000; padding: 5px; border: 1px solid #999;}
@@ -67,7 +67,7 @@ section.active {border: 1px solid rgb(0, 166, 255);}
#executionData table, #productData table {margin-bottom: 0px;}
#executionData table tr>th, #productData table tr>th {color: #fff !important;}
#executionData .c-story, #executionData .c-task, #executionData .c-bug {text-align: center; width: 105px;}
#productData {margin-left: 20px;}
#productData {margin-left: 12px;}
#productData .c-plan, #productData .c-requirement, #productData .c-story, #productData .c-closed {text-align: center; width: 105px;}
#productData .c-story {width: 115px;}
#productData .c-requirement {width: 140px;}
@@ -81,4 +81,4 @@ section.active {border: 1px solid rgb(0, 166, 255);}
.dataYearStat > div {margin-top: 5px;}
.dataYearStat .canvas {float: left; height: 305px; padding-left: 30px;}
.dataYearStat .canvas.left {width: 450px;}
.dataYearStat .canvas.right {width: 810px; float: right;}
.dataYearStat .canvas.right {width: 810px; float: right;}
+7 -3
View File
@@ -1906,12 +1906,11 @@ class story extends control
$productStoryList = array();
$productList = array();
$ignoreTwins = array();
$twinsCount = 0;
$twinsCount = array();
foreach($stories as $story)
{
if(!empty($ignoreTwins) and isset($ignoreTwins[$story->id]))
{
$twinsCount ++;
unset($stories[$story->id]);
continue;
}
@@ -1933,7 +1932,12 @@ class story extends control
if(!empty($story->twins))
{
foreach(explode(',', trim($story->twins, ',')) as $twinID) $ignoreTwins[$twinID] = $twinID;
$twinsCount[$story->id] = 0;
foreach(explode(',', trim($story->twins, ',')) as $twinID)
{
$twinsCount[$story->id] ++;
$ignoreTwins[$twinID] = $twinID;
}
}
}
+1 -35
View File
@@ -866,6 +866,7 @@ class storyModel extends model
{
$this->dbh->exec("UPDATE " . TABLE_STORY . " SET twins = REPLACE(twins, ',$storyID,', ',') WHERE `product` = $oldStory->product");
$this->dao->update(TABLE_STORY)->set('twins')->eq('')->where('id')->eq($storyID)->orWhere('twins')->eq(',')->exec();
if(!dao::isError()) $this->loadModel('action')->create('story', $storyID, 'relieved');
}
elseif(!empty($oldStory->twins))
{
@@ -2228,41 +2229,6 @@ class storyModel extends model
if(empty($oldPlanID)) $story->plan = $planID;
if($oldStory->branch) $story->plan = $planID;
/* Append the plan id to plan field if product is multi and story is all branch. */
if($this->session->currentProductType != 'normal' and empty($story->branch))
{
$branchPlanPairs = $this->dao->select('branch, id as plan')->from(TABLE_PRODUCTPLAN)
->where('product')->eq($oldStory->product)
->andWhere('id')->in($oldStory->plan)
->fetchPairs();
foreach($branchPlanPairs as $branches => $planParis)
{
foreach(explode(',', $branches) as $branch)
{
$branchPlanPairs[$branch] = $planParis;
}
unset($branchPlanPairs[$branches]);
}
if($planID == 0 and !empty($oldStory->plan) and isset($branchPlanPairs[0]) and $branchPlanPairs[0] != $planID) $unlinkPlans[$branchPlanPairs[0]] = empty($unlinkPlans[$branchPlanPairs[0]]) ? $storyID : "{$unlinkPlans[$branchPlanPairs[0]]},$storyID";
if($planID != 0)
{
if(!empty($oldStory->plan))
{
foreach(explode(',', $plan->branch) as $planBranch)
{
if(isset($branchPlanPairs[$planBranch]) and $branchPlanPairs[$planBranch] != $planID)
{
$unlinkPlans[$branchPlanPairs[$planBranch]] = empty($unlinkPlans[$branchPlanPairs[$planBranch]]) ? $storyID : "{$unlinkPlans[$branchPlanPairs[$planBranch]]},$storyID";
}
}
}
foreach(explode(',', $plan->branch) as $planBranch) if(isset($branchPlanPairs[$planBranch])) $branchPlanPairs[$planBranch] = $planID;
$story->plan = $oldStory->plan ? implode(',', array_unique($branchPlanPairs)) : $planID;
$story->plan = trim($story->plan, ',');
if($story->plan != $oldStory->plan and !empty($planID)) $link2Plans[$planID] = empty($link2Plans[$planID]) ? $storyID : "{$link2Plans[$planID]},$storyID";
}
}
/* Change stage. */
if($planID)
{
+1 -1
View File
@@ -11,7 +11,7 @@ if(isset($twins))
<li class='active'><a data-toggle='tab' href='#affectedProjects'><?php echo $lang->story->affectedProjects;?> <?php $count = count($story->executions); if($count > 0) echo "<span class='label label-danger label-badge label-circle'>" . $count . "</span>" ?></a></li>
<li><a data-toggle='tab' href='#affectedBugs'><?php echo $lang->story->affectedBugs;?> <?php $count = count($story->bugs); if($count > 0) echo "<span class='label label-danger label-badge label-circle'>" . $count . "</span>" ?></a></li>
<li><a data-toggle='tab' href='#affectedCases'><?php echo $lang->story->affectedCases;?> <?php $count = count($story->cases); if($count > 0) echo "<span class='label label-danger label-badge label-circle'>" . $count . "</span>" ?></a></li>
<li><a data-toggle='tab' href='#affectedTwins'><?php if(count($twins) > 0) echo $lang->story->affectedTwins;?> <?php if(count($twins) > 0) echo "<span class='label label-danger label-badge label-circle'>" . count($twins) . "</span>" ?></a></li>
<li><a data-toggle='tab' href='#affectedTwins'><?php if(isset($twins) and count($twins) > 0) echo $lang->story->affectedTwins;?> <?php if(isset($twins) and count($twins) > 0) echo "<span class='label label-danger label-badge label-circle'>" . count($twins) . "</span>" ?></a></li>
</ul>
<div class='tab-content'>
<div class='tab-pane active' id='affectedProjects'>
+1 -1
View File
@@ -37,7 +37,7 @@
<td title='<?php echo $story->title;?>' class='text-left'>
<?php echo $story->title;?>
<?php if(!empty($story->twins)):?>
<span class='label label-outline label-badge'><?php echo "{$lang->story->twins}:"?> <span class='text-blue'><?php echo $twinsCount?></span></span>
<span class='label label-outline label-badge'><?php echo "{$lang->story->twins}:"?> <span class='text-blue'><?php echo $twinsCount[$story->id]?></span></span>
<?php endif;?>
</td>
<td class='story-<?php echo $story->status;?>'><?php echo $this->processStatus('story', $story);?></td>
+1 -1
View File
@@ -34,7 +34,7 @@
<?php echo $lang->story->relievedTwinsRelation;?>
</label>
</div>
<div style="display: inline-block"><icon class='icon icon-help' data-toggle='popover' data-trigger='focus hover' data-placement='right' data-tip-class='text-muted popover-sm' data-content="<?php echo $lang->story->relievedTwinsRelationTips;?>"></icon></div>
<div class="<?php echo !empty($story->twins) ? '' : 'hidden';?>" style="display: inline-block"><icon class='icon icon-help' data-toggle='popover' data-trigger='focus hover' data-placement='right' data-tip-class='text-muted popover-sm' data-content="<?php echo $lang->story->relievedTwinsRelationTips;?>"></icon></div>
</td>
</tr>
<tr id='duplicateStoryBox' style='display:none'>
+6 -2
View File
@@ -68,7 +68,9 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
<td class='w-60px <?php if((!$branches and $type == 'story') or $type == 'requirement') echo "hidden"; ?> switchBranch'></td>
<td colspan="2" class='<?php if($branches and $type == 'story') echo "hidden"; ?> switchBranch'>
<div class='input-group' id='moduleIdBox'>
<?php if(!$hiddenProduct):?>
<div class="input-group-addon"><?php echo $lang->story->module;?></div>
<?php endif;?>
<?php
echo html::select('module', $moduleOptionMenu, $moduleID, "class='form-control chosen'");
if(count($moduleOptionMenu) == 1)
@@ -122,6 +124,7 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
</td>
</tr>
<tr class='<?php if($branches) echo "hidden"; ?> switchBranch'>
<?php if(!$hiddenPlan):?>
<th class='planTh'><?php echo $lang->story->planAB;?></th>
<td colspan="2">
<div class='input-group' id='planIdBox'>
@@ -139,11 +142,12 @@ foreach(explode(',', $config->story->create->requiredFields) as $field)
?>
</div>
</td>
<?php else:?>
<th class='planTh'><?php echo $lang->story->assignedTo;?></th>
<?php endif;?>
<td colspan='<?php echo $type == 'story' ? 2 : 1;?>' id='assignedToBox'>
<div class='input-group'>
<?php if(!$hiddenPlan):?>
<div class="input-group-addon assignedTo"><?php echo $lang->story->assignedTo;?></div>
<?php endif;?>
<?php echo html::select('assignedTo', $hiddenProduct ? $teamUsers : $users, '', "class='form-control picker-select'");?>
</div>
</td>
+2 -1
View File
@@ -1,6 +1,7 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<?php js::set('rawMethod', $this->app->rawMethod);?>
<?php js::set('hiddenProduct', isset($hiddenProduct) ? $hiddenProduct : false);?>
<script>
/**
* Load product.
@@ -194,7 +195,7 @@ function loadProductModules(productID, branch)
$moduleIDBox.load(moduleLink, function()
{
$moduleIDBox.find('#module').chosen();
if(typeof(storyModule) == 'string' && config.currentMethod != 'edit') $moduleIDBox.prepend("<span class='input-group-addon'>" + storyModule + "</span>");
if(typeof(storyModule) == 'string' && config.currentMethod != 'edit' && !hiddenProduct) $moduleIDBox.prepend("<span class='input-group-addon'>" + storyModule + "</span>");
$moduleIDBox.fixInputGroup();
});
}
+4 -4
View File
@@ -23,15 +23,15 @@ $(function()
}
$('.team-group').removeClass('hidden');
$('#estimate').attr('disabled', 'disabled')
$('#left').attr('disabled', 'disabled')
$('#estimate').attr('readonly', 'readonly');
$('#left').attr('readonly', 'readonly');
}
else
{
$('#assignedTo').removeAttr('disabled').trigger('chosen:updated')
$('.team-group').addClass('hidden');
$('#estimate').attr('disabled', false)
$('#left').attr('disabled', false)
$('#estimate').removeAttr('readonly');
$('#left').removeAttr('readonly');
}
})
})
+5 -3
View File
@@ -945,9 +945,10 @@ class taskModel extends model
/* Insert or update team. */
if($mode == 'multi' and isset($teams[$account]))
{
$this->dao->update(TABLE_TASKTEAM)->set("estimate= estimate + {$member->estimate}")
->set("`left` = `left` + {$member->left}")
->set("`consumed` = `consumed` + {$member->consumed}")
$this->dao->update(TABLE_TASKTEAM)
->beginIF($member->estimate)->set("estimate= estimate + {$member->estimate}")->fi()
->beginIF($member->left)->set("`left` = `left` + {$member->left}")->fi()
->beginIF($member->consumed)->set("`consumed` = `consumed` + {$member->consumed}")->fi()
->where('task')->eq($member->task)
->andWhere('account')->eq($member->account)
->exec();
@@ -1071,6 +1072,7 @@ class taskModel extends model
/* If a multiple task is assigned to a team member who is not the task, assign to the team member instead. */
if(!$this->post->assignedTo and !empty($oldTask->team) and !empty($_POST['team'])) $_POST['assignedTo'] = $this->getAssignedTo4Multi($_POST['team'], $oldTask);
if(!$oldTask->mode and !$this->post->assignedTo and !empty($_POST['team'])) $_POST['assignedTo'] = $_POST['team'][0];
/* When the selected parent task is a common task and has consumption, select other parent tasks. */
if($this->post->parent > 0)
+2 -2
View File
@@ -78,8 +78,8 @@ foreach(explode(',', $config->task->create->requiredFields) as $field)
<span class="input-group-btn team-group hidden"><a class="btn br-0" href="#modalTeam" data-toggle="modal"><?php echo $lang->task->team;?></a></span>
</div>
</td>
<td>
<div class="checkbox-primary c-multipleTask affair" style='display: inline-block'>
<td colspan='2'>
<div class="checkbox-primary c-multipleTask affair" style='display: inline-block; margin-right: <?php echo common::checkNotCN() ? '-10px' : '-30px'?>'>
<input type="checkbox" name="multiple" value="1" id="multipleBox" /><label for="multipleBox" class="no-margin"><?php echo $lang->task->multiple;?></label>
</div>
<div class='hidden modeBox' style='display: inline-block'><?php echo html::radio('mode', $lang->task->modeList, !empty($task->mode) ? $task->mode: 'linear');?></div>
+4 -6
View File
@@ -144,19 +144,17 @@ $(document).ready(function()
showTeamMenu();
<?php endif;?>
<?php if(isset($task->mode) and $task->mode == 'multi'):?>
$('tr.teamTemplate').closest('tbody.sortable').sortable('destroy');
<?php if(empty($task->mode) or $task->mode != 'multi'):?>
var canSort = false;
<?php else:?>
var options = {
trigger: '.icon-move',
selector: 'tr.teamTemplate',
selector: '.icon-move',
dragCssClass: 'drag-row',
reverse: true,
finish: setLineNumber
}
$('#taskTeamEditor > .sortable').sortable(options);
$('#taskTeamEditor tbody.sortable').sortable(options);
<?php endif;?>
/* Init task team manage dialog */
+1 -3
View File
@@ -528,8 +528,6 @@ class testcase extends control
$currentModuleID = $moduleID ? (int)$moduleID : (int)$this->cookie->lastCaseModule;
/* Get the status of stories are not closed. */
$storyStatus = $this->lang->story->statusList;
unset($storyStatus['closed']);
$modules = array();
if($currentModuleID)
{
@@ -539,7 +537,7 @@ class testcase extends control
$modules = $this->tree->getAllChildID($modules);
}
$stories = $this->story->getProductStoryPairs($productID, $branch, $modules, array_keys($storyStatus), 'id_desc', 50, 'null', 'story', false);
$stories = $this->story->getProductStoryPairs($productID, $branch, $modules, 'active', 'id_desc', 50, 'null', 'story', false);
if($this->app->tab != 'qa' and $this->app->tab != 'product')
{
$projectID = $this->app->tab == 'project' ? $this->session->project : $this->session->execution;
+5 -2
View File
@@ -92,11 +92,14 @@ class treeModel extends model
->beginIF($type == 'task')->andWhere('type')->eq('task')->fi()
->beginIF($type != 'task')->andWhere('type')->in("story,$type")->fi()
->beginIF($startModulePath)->andWhere('path')->like($startModulePath)->fi()
->beginIF($branch !== 'all' and $branch !== '' and $branch !== false)
->beginIF($branch !== 'all' and $branch !== '' and $branch !== false and strpos($param, 'noMainBranch') === false)
->andWhere("(branch")->eq(0)
->orWhere('branch')->eq($branch)
->markRight(1)
->fi()
->beginIF($branch !== 'all' and $branch !== '' and $branch !== false and strpos($param, 'noMainBranch') !== false)
->andWhere('branch')->eq($branch)
->fi()
->beginIF(strpos($param, 'nodeleted') !== false)->andWhere('deleted')->eq(0)->fi()
->orderBy('grade desc, `order`, type desc')
->get();
@@ -178,7 +181,7 @@ class treeModel extends model
$treeMenu = array();
foreach($branches as $branchID => $branch)
{
{
$stmt = $this->dbh->query($this->buildMenuQuery($rootID, $type, $startModule, $branchID, $param));
$modules = array();
while($module = $stmt->fetch())
+1 -1
View File
@@ -189,7 +189,7 @@ function loadModules(branch)
if(typeof(branchID) == 'undefined') branchID = 0;
if(typeof(moduleID) == 'undefined') moduleID = 0;
link = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=story&branch=' + branchID + '&rootModuleID=0&returnType=html&fieldID=&needManage=true&extra=excludeModuleID=' + <?php echo $module->id;?> + ',noMainBranch&currentModuleID=' + moduleID);
link = createLink('tree', 'ajaxGetOptionMenu', 'productID=' + productID + '&viewtype=' + type + '&branch=' + branchID + '&rootModuleID=0&returnType=html&fieldID=&needManage=true&extra=excludeModuleID=' + <?php echo $module->id;?> + ',noMainBranch&currentModuleID=' + moduleID);
$(moduleBox).load(link, function()
{
$(this).children('select').attr('id', 'parent').attr('name', 'parent');
+22 -22
View File
@@ -277,10 +277,10 @@
border-radius: 2px;
}
.ke-container.focus {
border-color: #0c64eb;
border-color: #2e7fff;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(12, 100, 235, .6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(12, 100, 235, .6);
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(46, 127, 255, .6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(46, 127, 255, .6);
}
.ke-container.ke-loading > .ke-toolbar,
.ke-container.ke-loading > .ke-edit,
@@ -327,7 +327,7 @@
.ke-toolbar .ke-on,
.ke-toolbar .ke-selected {
filter: alpha(opacity=100);
border-color: #cbd0db;
border-color: #c4c4c4;
opacity: 1;
}
.ke-toolbar .ke-selected {
@@ -347,7 +347,7 @@
line-height: 0;
border-top: 0;
border-bottom: 0;
border-left: 1px dotted #cbd0db;
border-left: 1px dotted #c4c4c4;
}
.ke-toolbar .ke-hr {
height: 1px;
@@ -369,7 +369,7 @@
overflow: auto;
font-family: Monaco, Menlo, Consolas, "Courier New", monospace;
font-size: 12px;
color: #3c4353;
color: #313c52;
resize: none;
background-color: #fff;
}
@@ -431,7 +431,7 @@
font-size: 12px;
text-align: left;
background-color: #fff;
border: 1px solid #b6bdcc;
border: 1px solid #b2b2b2;
border: 1px solid rgba(0, 0, 0, .15);
border-radius: 4px;
}
@@ -443,7 +443,7 @@
.ke-menu-item-on {
color: #fff;
text-decoration: none;
background-color: #0c64eb;
background-color: #2e7fff;
outline: 0;
}
.ke-menu-item-left {
@@ -482,7 +482,7 @@
/* colorpicker */
.ke-colorpicker {
background-color: #fff;
border: 1px solid #b6bdcc;
border: 1px solid #b2b2b2;
border: 1px solid rgba(0, 0, 0, .15);
border-radius: 4px;
}
@@ -516,13 +516,13 @@
}
.ke-colorpicker-cell-on {
color: #fff;
background-color: #0c64eb;
background-color: #2e7fff;
}
.ke-colorpicker-cell-on .ke-colorpicker-cell-color {
border: 2px solid #3c4353;
border: 2px solid #313c52;
}
.ke-colorpicker-cell-selected .ke-colorpicker-cell-color {
border: 2px solid #3c4353;
border: 2px solid #313c52;
}
/* dialog */
.ke-dialog {
@@ -719,11 +719,11 @@
padding: 0 12px;
margin: 0;
font-size: 12px;
color: #3c4353;
color: #313c52;
text-decoration: none;
background-color: #fff;
border: 1px solid #d6dae3;
border-color: #d6dae3;
border: 1px solid #d8dbde;
border-color: #d8dbde;
border-radius: 4px;
}
.ke-button:hover,
@@ -731,9 +731,9 @@
.ke-button:active,
.ke-button.active,
.open .dropdown-toggle.ke-button {
color: #3c4353;
color: #313c52;
background-color: #ebebeb;
border-color: #b2b9ca;
border-color: #b7bcc2;
-webkit-box-shadow: 0 2px 1px rgba(0, 0, 0, .1);
box-shadow: 0 2px 1px rgba(0, 0, 0, .1);
}
@@ -742,7 +742,7 @@
.open .dropdown-toggle.ke-button {
background-color: #d9d9d9;
background-image: none;
border-color: #b8bfce;
border-color: #bcc2c7;
-webkit-box-shadow: inset 0 4px 6px rgba(0, 0, 0, .15);
box-shadow: inset 0 4px 6px rgba(0, 0, 0, .15);
}
@@ -762,7 +762,7 @@ fieldset[disabled] .ke-button:active,
.ke-button[disabled].active,
fieldset[disabled] .ke-button.active {
background-color: #fff;
border-color: #d6dae3;
border-color: #d8dbde;
}
/* inputbox */
.ke-input-text {
@@ -790,10 +790,10 @@ fieldset[disabled] .ke-button.active {
}
.ke-input-text:focus,
.ke-input-text.focus {
border-color: #0c64eb;
border-color: #2e7fff;
outline: 0;
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(12, 100, 235, .6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(12, 100, 235, .6);
-webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(46, 127, 255, .6);
box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 8px rgba(46, 127, 255, .6);
}
.ke-input-text[disabled] {
background: #eee;
+7 -11
View File
@@ -1,10 +1,3 @@
/*!
* ZUI: Zentao Kindeditor - v1.10.0 - 2022-04-19
* http://openzui.com
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2022 cnezsoft.com; Licensed MIT
*/
/******************************************************************************
* KindEditor - WYSIWYG HTML Editor for Internet
* Copyright (C) 2006-2013 kindsoft.net
@@ -304,7 +297,7 @@
],
fontSizeTable: ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'],
htmlTags: {
font: ['id', 'class', 'color', 'size', 'face', '.background-color'],
font: ['id', 'class', 'color', 'size', 'face', '.background-color', '.color', '.font-size', '.font-family'],
span: [
'id', 'class', '.color', '.background-color', '.font-size', '.font-family', '.background',
'.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.line-height'
@@ -10359,14 +10352,17 @@ KindEditor.plugin('pasteimage', function(K) {
var original = ev.originalEvent;
var clipboardItems = original.clipboardData && original.clipboardData.items;
var clipboardItem = null;
if(clipboardItems) {
if(clipboardItems)
{
var IMAGE_MIME_REGEX = /^image\/(p?jpeg|gif|png)$/i;
for (var i = 0; i < clipboardItems.length; i++)
{
if (IMAGE_MIME_REGEX.test(clipboardItems[i].type))
var dataType = clipboardItems[i].type;
if(options.pasteTextFirst && dataType.indexOf('text/') === 0) return;
if (IMAGE_MIME_REGEX.test(dataType))
{
clipboardItem = clipboardItems[i];
break;
if(!options.pasteTextFirst) break;
}
}
}
File diff suppressed because one or more lines are too long
+6 -12
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1 +1 @@
6d5d77c11978c707cb8204353f640a3ecca6e046
7ca69ef051899efdcd25a1aa997b0de62d3cccba
@@ -35,6 +35,20 @@ $(function()
window.parent.appHeaderStyleUpdated = true;
window.open('xxc://setAppHeaderStyle/zentao-integrated/' + encodeURIComponent(JSON.stringify(clientHeaderStyle)), '_blank');
});
setTimeout(function() // Override confirm, prompt and alert methods.
{
window.confirm = function() {
console.warn('\"window.confirm\" is disabled in webview.');
return true;
};
window.prompt = function() {
console.warn('\"window.prompt\" is disabled in webview.');
};
window.alert = function(msg) {
const win = window.parent ? window.parent : window;
win.open(`xxc://webview/alert/${encodeURIComponent(msg)}`, '_blank');
};
});
</script>
<?php if($this->app->moduleName =='user' && $this->app->methodName == 'deny'): ?>
<script>
@@ -353,8 +353,8 @@ class zentaoBot extends xuanBot
if(empty($args))
{
$keys['assignTo'] = is_object($user) ? $user->account : false;
$keys['status'] = 'wait,doing,done,pause,cancel';
$args['assignTo'] = is_object($user) ? $user->account : false;
$args['status'] = 'wait,doing,done,pause,cancel';
}
$conds = $this->parseArguments($args, $keys);