Merge remote-tracking branch 'origin/master'
This commit is contained in:
+3
-1
@@ -1,4 +1,4 @@
|
||||
FROM hub.qucheng.com/ci/zentao-ztf:php8-2023050806
|
||||
FROM hub.qucheng.com/ci/zentao-ztf:php8-2023050810
|
||||
|
||||
# Install zentao
|
||||
ARG VERSION
|
||||
@@ -13,3 +13,5 @@ ENV MYSQL_PASSWORD=${MYSQL_PASSWORD}
|
||||
SHELL ["/bin/bash", "-c"]
|
||||
# Copy ZenTao
|
||||
COPY --chown=33:33 . /apps/zentao/
|
||||
|
||||
RUN INIT_PHPINI_ONLY=true /etc/s6/s6-init/run
|
||||
|
||||
Vendored
+2
-2
@@ -96,7 +96,7 @@ pipeline {
|
||||
|
||||
steps {
|
||||
container('zentao') {
|
||||
sh 'cat /usr/bin/initdb.php; initdb.php ; /apps/zentao/test/ztest init'
|
||||
sh '/etc/s6/s6-init/run ; php --ini ; cat /usr/bin/initdb.php; initdb.php ; /apps/zentao/test/ztest init'
|
||||
}
|
||||
}
|
||||
post {
|
||||
@@ -138,7 +138,7 @@ pipeline {
|
||||
stage('Run') {
|
||||
steps {
|
||||
container('zentao') {
|
||||
sh 'initdb.php config'
|
||||
sh '/etc/s6/s6-init/run ; php --ini ; initdb.php config'
|
||||
sh '/apps/zentao/test/ztest extract ; /apps/zentao/test/ztest ${SEQUENCE} | tee /apps/zentao/test/${SEQUENCE}.log'
|
||||
sh 'ls /apps/zentao/www ; cat /apps/zentao/www/coverage.php'
|
||||
sh 'pipeline-unittest.sh /apps/zentao/test/${SEQUENCE}.log'
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.histories {
|
||||
background: #FCFDFE;
|
||||
}
|
||||
|
||||
.histories .btn-mini {
|
||||
@@ -22,7 +28,8 @@
|
||||
|
||||
.histories .btn {
|
||||
background-color: #fff;
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
@@ -69,6 +76,7 @@
|
||||
background: 0 0;
|
||||
box-shadow: none;
|
||||
border-color: transparent;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
@@ -77,7 +85,6 @@
|
||||
}
|
||||
|
||||
.histories-list {
|
||||
padding-left: 15px;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
list-style: decimal;
|
||||
@@ -85,6 +92,24 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.histories-list .timeline {
|
||||
top: 13px;
|
||||
bottom: 13px;
|
||||
left: 10px;
|
||||
background: #EEE;
|
||||
}
|
||||
|
||||
.histories-list .marker {
|
||||
color: #5E626D;
|
||||
border-color: #EEE;
|
||||
border-width: 1px;
|
||||
box-shadow: none;
|
||||
background: #FCFDFE;
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.histories-list.sort-reverse {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
@@ -93,6 +118,7 @@
|
||||
word-break: break-word;
|
||||
word-wrap: break-word;
|
||||
position: relative;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.histories-list > li strong {
|
||||
|
||||
+98
-85
@@ -14,10 +14,24 @@ class history extends wg
|
||||
return file_get_contents(__DIR__ . DS . 'css' . DS . 'v1.css');
|
||||
}
|
||||
|
||||
private function marker(int $num)
|
||||
{
|
||||
return span
|
||||
(
|
||||
setClass('marker', 'text-sm', 'rounded-full', 'aspect-square', 'inline-flex', 'justify-center', 'items-center', 'mr-2'),
|
||||
$num
|
||||
);
|
||||
}
|
||||
|
||||
private function timeline()
|
||||
{
|
||||
return div(setClass('timeline w-px absolute'));
|
||||
}
|
||||
|
||||
private function checkEditCommentPriv($action)
|
||||
{
|
||||
global $app;
|
||||
$methodName = $this->prop('methodName') ?? data('methodName');
|
||||
$methodName = $this->prop('methodName') === null ? $this->prop('methodName') : data('methodName');
|
||||
|
||||
return (!isset($canBeChanged) || !empty($canBeChanged))
|
||||
&& end($actions) == $action
|
||||
@@ -27,10 +41,9 @@ class history extends wg
|
||||
&& common::hasPriv('action', 'editComment');
|
||||
}
|
||||
|
||||
private function createExpandBtn($i)
|
||||
private function expandBtn($i)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return button
|
||||
(
|
||||
setClass('btn btn-mini switch-btn btn-icon btn-expand'),
|
||||
@@ -52,10 +65,9 @@ class history extends wg
|
||||
);
|
||||
}
|
||||
|
||||
private function createEditCommentBtn()
|
||||
private function editCommentBtn()
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return button
|
||||
(
|
||||
setClass('btn btn-link btn-icon btn-sm btn-edit-comment'),
|
||||
@@ -64,10 +76,9 @@ class history extends wg
|
||||
);
|
||||
}
|
||||
|
||||
private function createHistoryChangesView($action, $i)
|
||||
private function historyChanges($action, $i)
|
||||
{
|
||||
global $app;
|
||||
|
||||
return div
|
||||
(
|
||||
setClass('history-changes'),
|
||||
@@ -76,18 +87,19 @@ class history extends wg
|
||||
);
|
||||
}
|
||||
|
||||
private function createActionItemView($action, $i)
|
||||
private function actionItem($action, $i)
|
||||
{
|
||||
global $app;
|
||||
|
||||
return li
|
||||
(
|
||||
setClass('my-3'),
|
||||
set::value($i),
|
||||
$this->marker($i),
|
||||
html($app->loadTarget('action')->renderAction($action))
|
||||
);
|
||||
}
|
||||
|
||||
private function generateComment($action)
|
||||
private function getComment($action)
|
||||
{
|
||||
if(str_contains($action->comment, '<pre class="prettyprint lang-html">'))
|
||||
{
|
||||
@@ -102,10 +114,9 @@ class history extends wg
|
||||
: $action->comment;
|
||||
}
|
||||
|
||||
private function createCommentView($action)
|
||||
private function comment($action)
|
||||
{
|
||||
$comment = $this->generateComment($action);
|
||||
|
||||
$comment = $this->getComment($action);
|
||||
return div
|
||||
(
|
||||
setClass('article-content comment'),
|
||||
@@ -117,10 +128,9 @@ class history extends wg
|
||||
);
|
||||
}
|
||||
|
||||
private function createCommentEditForm($action)
|
||||
private function commentEditForm($action)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return form
|
||||
(
|
||||
setClass('comment-edit-form'),
|
||||
@@ -156,51 +166,38 @@ class history extends wg
|
||||
);
|
||||
}
|
||||
|
||||
private function buildHistoriesList()
|
||||
private function historyList()
|
||||
{
|
||||
$actions = $this->prop('actions') ?? data('actions');
|
||||
$users = $this->prop('users') ?? data('users');
|
||||
$historiesListView = h::ol(setClass('histories-list'));
|
||||
$actions = $this->prop('actions') === null ? $this->prop('actions') : data('actions');
|
||||
$users = $this->prop('users') === null ? $this->prop('users') : data('users');
|
||||
$historiesListView = h::ol(setClass('histories-list relative'));
|
||||
$i = 0;
|
||||
|
||||
$historiesListView->add($this->timeline());
|
||||
foreach($actions as $action)
|
||||
{
|
||||
if($action->action === 'assigned' || $action->action === 'toaudit')
|
||||
$action->extra = zget($users, $action->extra);
|
||||
if($action->action === 'assigned' || $action->action === 'toaudit') $action->extra = zget($users, $action->extra);
|
||||
|
||||
$action->actor = zget($users, $action->actor);
|
||||
if(str_contains($action->actor, ':'))
|
||||
$action->actor = substr($action->actor, strpos($action->actor, ':') + 1);
|
||||
if(str_contains($action->actor, ':')) $action->actor = substr($action->actor, strpos($action->actor, ':') + 1);
|
||||
|
||||
$i++;
|
||||
$actionItemView = $this->createActionItemView($action, $i);
|
||||
$actionItemView = $this->actionItem($action, $i);
|
||||
|
||||
if(!empty($action->history))
|
||||
{
|
||||
$allExpandBtn = $this->createExpandBtn($i);
|
||||
$actionItemView->add($allExpandBtn);
|
||||
|
||||
$historyChangesView = $this->createHistoryChangesView($action, $i);
|
||||
$actionItemView->add($historyChangesView);
|
||||
$actionItemView->add($this->expandBtn($i));
|
||||
$actionItemView->add($this->historyChanges($action, $i));
|
||||
}
|
||||
if(strlen(trim(($action->comment))) !== 0)
|
||||
{
|
||||
$canEditComment = $this->checkEditCommentPriv($action);
|
||||
|
||||
if($canEditComment)
|
||||
{
|
||||
$editCommentBtn = $this->createEditCommentBtn();
|
||||
$actionItemView->add($editCommentBtn);
|
||||
}
|
||||
if($canEditComment) $actionItemView->add($this->editCommentBtn());
|
||||
|
||||
$commentView = $this->createCommentView($action);
|
||||
$actionItemView->add($commentView);
|
||||
$actionItemView->add($this->comment($action));
|
||||
|
||||
if($canEditComment)
|
||||
{
|
||||
$commentEditForm = $this->createCommentEditForm($action);
|
||||
$actionItemView->add($commentEditForm);
|
||||
}
|
||||
if($canEditComment) $actionItemView->add($this->commentEditForm($action));
|
||||
}
|
||||
$historiesListView->add($actionItemView);
|
||||
}
|
||||
@@ -208,6 +205,62 @@ class history extends wg
|
||||
return $historiesListView;
|
||||
}
|
||||
|
||||
private function reverseBtn()
|
||||
{
|
||||
global $lang;
|
||||
return btn
|
||||
(
|
||||
setClass('btn-mini btn-icon btn-reverse mr-2'),
|
||||
set::title($lang->reverse),
|
||||
set::icon('arrow-up'),
|
||||
on::click(<<<REVERSE
|
||||
document.querySelector('.histories-list').classList.toggle('sort-reverse');
|
||||
var icon = e.target.querySelector('.icon');
|
||||
icon.classList.toggle('icon-arrow-up');
|
||||
icon.classList.toggle('icon-arrow-down');
|
||||
REVERSE)
|
||||
);
|
||||
}
|
||||
|
||||
private function expandAllBtn()
|
||||
{
|
||||
global $lang;
|
||||
return btn
|
||||
(
|
||||
setClass('btn-mini btn-icon btn-expand-all'),
|
||||
set::title($lang->switchDisplay),
|
||||
set::icon('plus'),
|
||||
on::click(<<<EXPANDALL
|
||||
var icon = e.target.querySelector('.icon');
|
||||
var isExpand = icon.classList.contains('icon-plus');
|
||||
var changeBoxs = document.querySelectorAll('[id^="changeBox"]');
|
||||
if(isExpand) {
|
||||
changeBoxs.forEach(function(box) {
|
||||
box.classList.add('show');
|
||||
});
|
||||
} else {
|
||||
changeBoxs.forEach(function(box) {
|
||||
box.classList.remove('show');
|
||||
});
|
||||
}
|
||||
icon.classList.toggle('icon-plus');
|
||||
icon.classList.toggle('icon-minus');
|
||||
EXPANDALL)
|
||||
);
|
||||
}
|
||||
|
||||
private function commentBtn()
|
||||
{
|
||||
global $lang;
|
||||
return btn
|
||||
(
|
||||
setClass('btn-comment btn-link ml-4'),
|
||||
set::icon('chat-line'),
|
||||
set::iconClass('text-primary'),
|
||||
$lang->action->create
|
||||
);
|
||||
}
|
||||
|
||||
protected function build()
|
||||
{
|
||||
global $lang;
|
||||
@@ -221,51 +274,11 @@ class history extends wg
|
||||
(
|
||||
setClass('detail-title'),
|
||||
span($lang->history),
|
||||
button
|
||||
(
|
||||
setClass('btn btn-mini btn-icon btn-reverse'),
|
||||
setStyle('margin-right', '4px'),
|
||||
set::type('button'),
|
||||
set::title($lang->reverse),
|
||||
h::i(setClass('icon icon-arrow-up icon-sm')),
|
||||
on::click(<<<REVERSE
|
||||
document.querySelector('.histories-list').classList.toggle('sort-reverse');
|
||||
var icon = e.target.querySelector('.icon');
|
||||
icon.classList.toggle('icon-arrow-up');
|
||||
icon.classList.toggle('icon-arrow-down');
|
||||
REVERSE),
|
||||
),
|
||||
button
|
||||
(
|
||||
setClass('btn btn-mini btn-icon btn-expand-all'),
|
||||
set::type('button'),
|
||||
set::title($lang->switchDisplay),
|
||||
h::i(setClass('icon icon-plus icon-sm')),
|
||||
on::click(<<<EXPANDALL
|
||||
var icon = e.target.querySelector('.icon');
|
||||
var isExpand = icon.classList.contains('icon-plus');
|
||||
var changeBoxs = document.querySelectorAll('[id^="changeBox"]');
|
||||
if(isExpand) {
|
||||
changeBoxs.forEach(function(box) {
|
||||
box.classList.add('show');
|
||||
});
|
||||
} else {
|
||||
changeBoxs.forEach(function(box) {
|
||||
box.classList.remove('show');
|
||||
});
|
||||
}
|
||||
icon.classList.toggle('icon-plus');
|
||||
icon.classList.toggle('icon-minus');
|
||||
EXPANDALL),
|
||||
),
|
||||
button
|
||||
(
|
||||
setClass('btn btn-link pull-right btn-comment'),
|
||||
set::type('button'),
|
||||
h::i(setClass('icon icon-chat-line'), ' ' . $lang->action->create)
|
||||
),
|
||||
$this->reverseBtn(),
|
||||
$this->expandAllBtn(),
|
||||
$this->commentBtn(),
|
||||
),
|
||||
div(setClass('detail-content'), $this->buildHistoriesList())
|
||||
div(setClass('detail-content'), $this->historyList())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
.productstatistic-block {background: #FCFDFE;}
|
||||
.productstatistic-block .tab-content {width: 100%;}
|
||||
.productstatistic-block .bg-secondary-pale {background: #F3F6FA;}
|
||||
.productstatistic-block .nav-tabs .nav-item:hover {border-left: 2px solid #2E7FFF; background-color: #FCFDFE;}
|
||||
.productstatistic-block .nav-tabs .nav-item.active {border-left: 2px solid #2E7FFF; background-color: #FCFDFE;}
|
||||
.productstatistic-block .nav-tabs .nav-item:hover > a.link {display: flex!important;}
|
||||
.productstatistic-block .nav-tabs .nav-item > a:before {background: transparent;}
|
||||
+1
-44
@@ -370,49 +370,6 @@ class blockModel extends model
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a block.
|
||||
*
|
||||
* @param int $blockID
|
||||
* @param string $type
|
||||
* @param string $module
|
||||
* @access public
|
||||
* @return int|false
|
||||
*/
|
||||
public function save(int $blockID, string $type, string $module = 'my'): bool|int
|
||||
{
|
||||
$block = $blockID ? $this->getByID($blockID) : null;
|
||||
$data = fixer::input('post')
|
||||
->setIF($blockID, 'id', $blockID)
|
||||
->add('account', $this->app->user->account)
|
||||
->add('module', $module)
|
||||
->add('order', $block ? $block->order : ($this->getMaxOrderByModule($module) + 1))
|
||||
->add('hidden', 0)
|
||||
->setDefault('vision', $this->config->vision)
|
||||
->setDefault('grid', '4')
|
||||
->setDefault('params', array())
|
||||
->stripTags('html', $this->config->allowedTags)
|
||||
->remove('uid,actionLink,modules,moduleBlock')
|
||||
->get();
|
||||
|
||||
$data->source = $this->post->moduleBlock ? $this->post->modules : '';
|
||||
$data->block = $this->post->moduleBlock ? $this->post->moduleBlock : $this->post->modules;
|
||||
|
||||
if($block) $data->height = $block->height;
|
||||
if($type == 'html')
|
||||
{
|
||||
$uid = $this->post->uid;
|
||||
$data = $this->loadModel('file')->processImgURL($data, 'html', $uid);
|
||||
$data->params['html'] = $data->html;
|
||||
unset($data->html);
|
||||
unset($_SESSION['album'][$uid]);
|
||||
}
|
||||
|
||||
$data->params = helper::jsonEncode($data->params);
|
||||
|
||||
$this->dao->replace(TABLE_BLOCK)->data($data)->exec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init block when account use first.
|
||||
* 用户首次加载时初始化区块数据.
|
||||
@@ -459,7 +416,7 @@ class blockModel extends model
|
||||
*/
|
||||
public function isLongBlock(object $block): bool
|
||||
{
|
||||
return (!empty($block) and $block->grid >= 6) ? true : false;
|
||||
return (!empty($block->grid) and $block->grid >= 6) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->appendCountParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试新增count param >> count:{name:数量,default:20,control:input};
|
||||
测试新增count param 和 param test >> test:test;count:{name:数量,default:20,control:input};
|
||||
测试新增count param 和 param par >> par:par;count:{name:数量,default:20,control:input};
|
||||
测试新增count param 和 param append >> append:append;count:{name:数量,default:20,control:input};
|
||||
测试新增count param 和 param 空 >> count:{name:数量,default:20,control:input};
|
||||
|
||||
*/
|
||||
$param1 = new stdclass();
|
||||
$param1->test = 'test';
|
||||
|
||||
$param2 = new stdclass();
|
||||
$param2->par = 'par';
|
||||
|
||||
$param3 = new stdclass();
|
||||
$param3->append = 'append';
|
||||
|
||||
$param4 = new stdclass();
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->appendCountParamsTest()) && p() && e('count:{name:数量,default:20,control:input};'); // 测试新增count param
|
||||
r($block->appendCountParamsTest($param1)) && p() && e('test:test;count:{name:数量,default:20,control:input};'); // 测试新增count param 和 param test
|
||||
r($block->appendCountParamsTest($param2)) && p() && e('par:par;count:{name:数量,default:20,control:input};'); // 测试新增count param 和 param par
|
||||
r($block->appendCountParamsTest($param3)) && p() && e('append:append;count:{name:数量,default:20,control:input};'); // 测试新增count param 和 param append
|
||||
r($block->appendCountParamsTest($param4)) && p() && e('count:{name:数量,default:20,control:input};'); // 测试新增count param 和 param 空
|
||||
@@ -19,14 +19,17 @@ function initData()
|
||||
/**
|
||||
|
||||
title=测试 blockModel->checkAPI();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试空哈希值 >> 0
|
||||
测试正确的哈希值 >> 1
|
||||
测试错误的哈希值 >> 0
|
||||
sed: can't read /home/liuruogu/git/zentaopms/test/config/my.php: No such file or directory
|
||||
- 测试空哈希值 @0
|
||||
|
||||
*/
|
||||
- 测试正确的哈希值 @1
|
||||
|
||||
- 测试错误的哈希值 @0
|
||||
|
||||
*/
|
||||
|
||||
initData();
|
||||
|
||||
@@ -34,4 +37,4 @@ $block = new blockTest();
|
||||
|
||||
r($block->checkAPITest('')) && p('') && e('0'); // 测试空哈希值
|
||||
r($block->checkAPITest('858640a724c2c981983935eb2bbc4ad8')) && p('') && e('1'); // 测试正确的哈希值
|
||||
r($block->checkAPITest('858640a724c2c98198')) && p('') && e('0'); // 测试错误的哈希值
|
||||
r($block->checkAPITest('858640a724c2c98198')) && p('') && e('0'); // 测试错误的哈希值
|
||||
@@ -5,61 +5,66 @@ include dirname(__FILE__, 2) . '/block.class.php';
|
||||
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2');
|
||||
$block->account->range('test');
|
||||
$block->vision->range('rnd');
|
||||
$block->module->range('test');
|
||||
$block->title->prefix('区块')->range('2');
|
||||
$block->order->range('5');
|
||||
|
||||
$block->gen(1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 block 模块 model下的 create 方法
|
||||
timeout=0
|
||||
cid=39
|
||||
|
||||
- 执行block模块的getByID方法,参数是$newBlockID
|
||||
- 测试获取正常的block的内容
|
||||
- 属性account @admin
|
||||
- 属性vision @rnd
|
||||
- 属性dashboard @my
|
||||
- 属性title @区块123
|
||||
- 属性source @my
|
||||
- 属性block @bug
|
||||
- 属性order @5
|
||||
- 属性module @project
|
||||
- 属性code @statistic
|
||||
- 属性title @项目统计区块
|
||||
- 属性order @1
|
||||
|
||||
- 执行blockTest模块的create方法,参数是$accoutTooLangBlock,属性account @『所属用户』长度应当不超过『30』,且大于『0』。
|
||||
- 测试所属模块为空 @『所属模块』不能为空。
|
||||
|
||||
- 测试所属区块为空 @『区块』不能为空。
|
||||
|
||||
- 测试区块名称为空 @『区块名称』不能为空。
|
||||
|
||||
- 测试account 字段字符超出长度 @『所属用户』长度应当不超过『30』,且大于『0』。
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
$block = new stdclass();
|
||||
$block->account = 'admin';
|
||||
$block->vision = 'rnd';
|
||||
$block->dashboard = 'my';
|
||||
$block->title = '区块123';
|
||||
$block->order = '5';
|
||||
$block->module = 'project';
|
||||
$block->code = 'statistic';
|
||||
$block->title = '项目统计区块';
|
||||
$block->order = '1';
|
||||
|
||||
$accoutTooLangBlock = new stdclass();
|
||||
$accoutTooLangBlock->account = 'adminadminadminadminadminadminadminadmin1';
|
||||
$accoutTooLangBlock->vision = 'rnd';
|
||||
$accoutTooLangBlock->dashboard = 'my';
|
||||
$accoutTooLangBlock->title = 'long account';
|
||||
$accoutTooLangBlock->order = '5';
|
||||
$accountTooLangBlock = new stdclass();
|
||||
$accountTooLangBlock->account = 'adminadminadminadminadminadminadminadmin1';
|
||||
$accountTooLangBlock->vision = 'rnd';
|
||||
$accountTooLangBlock->dashboard = 'my';
|
||||
$accountTooLangBlock->module = 'project';
|
||||
$accountTooLangBlock->code = 'statistic';
|
||||
$accountTooLangBlock->title = '项目统计区块2';
|
||||
$accountTooLangBlock->order = '2';
|
||||
|
||||
$emptyModuleBlock = new stdclass();
|
||||
$emptyModuleBlock->module = '';
|
||||
|
||||
$emptyCodeBlock = new stdclass();
|
||||
$emptyCodeBlock->code = '';
|
||||
|
||||
$emptyTitleBlock = new stdclass();
|
||||
$emptyTitleBlock->title = '';
|
||||
|
||||
$blockTest = new blockTest();
|
||||
$newBlockID = $blockTest->createTest($block);
|
||||
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,dashboard,title,order') && e('admin,rnd,my,区块123,5'); // 测试获取正常的block的内容
|
||||
r($blockTest->createTest($accoutTooLangBlock)) && p('account:0') && e('『所属用户』长度应当不超过『30』,且大于『0』。'); // 测试account 字段字符超出长度
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,dashboard,module,code,title,order') && e('admin,rnd,my,project,statistic,项目统计区块,1'); // 测试获取正常的block的内容
|
||||
r($blockTest->createTest($emptyModuleBlock)) && p('module:0') && e('『所属模块』不能为空。'); // 测试所属模块为空
|
||||
r($blockTest->createTest($emptyCodeBlock)) && p('code:0') && e('『区块』不能为空。'); // 测试所属区块为空
|
||||
r($blockTest->createTest($emptyTitleBlock)) && p('title:0') && e('『区块名称』不能为空。'); // 测试区块名称为空
|
||||
r($blockTest->createTest($accountTooLangBlock)) && p('account:0') && e('『所属用户』长度应当不超过『30』,且大于『0』。'); // 测试account 字段字符超出长度
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getAssignToMeParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取当前登陆用户待办的默认参数 >> 待办数,20,input
|
||||
获取当前登陆用户任务的默认参数 >> 任务数,20,input
|
||||
获取当前登陆用户Bug的默认参数 >> Bug数,20,input
|
||||
获取当前登陆用户需求的默认参数 >> 需求数,20,input
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data = $block->getAssignToMeParamsTest();
|
||||
|
||||
r($data) && p('todoCount:name,default,control') && e('待办数,20,input'); // 获取当前登陆用户待办的默认参数
|
||||
r($data) && p('taskCount:name,default,control') && e('任务数,20,input'); // 获取当前登陆用户任务的默认参数
|
||||
r($data) && p('bugCount:name,default,control') && e('Bug数,20,input'); // 获取当前登陆用户Bug的默认参数
|
||||
r($data) && p('storyCount:name,default,control') && e('需求数,20,input'); // 获取当前登陆用户需求的默认参数
|
||||
@@ -9,9 +9,6 @@ title=测试 blockModel->getAvailableBlocks();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
通过获取项目的可用区块 >> 项目计划,最新动态
|
||||
通过获取测试的可用区块 >> 测试统计,Bug列表,用例列表,版本列表
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getBlock();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取block的所属模块 >> my
|
||||
测试获取block的名称 >> 项目统计
|
||||
测试获取block的来源 >> project
|
||||
测试获取block的区块 >> statistic
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data = $block->getBlockTest(99);
|
||||
|
||||
r($data) && p('module') && e('my'); // 测试获取block的所属模块
|
||||
r($data) && p('title') && e('项目统计'); // 测试获取block的名称
|
||||
r($data) && p('source') && e('project'); // 测试获取block的来源
|
||||
r($data) && p('block') && e('statistic'); // 测试获取block的区块
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getBlockList();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
>> 测试统计;指派给我的Bug;指派给我的用例;待测版本列表
|
||||
>> 项目计划;最新计划
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getBlockListTest('qa')) && p('107:title;108:title;109:title;110:title') && e('测试统计;指派给我的Bug;指派给我的用例;待测版本列表');
|
||||
r($block->getBlockListTest('project', 'waterfall')) && p('105:title;106:title') && e('项目计划;最新计划');
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getBugParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试通过模块获取Bug区块的参数 >> 数量;类型;排序
|
||||
测试通过模块获取Bug区块的参数 >> 数量;类型;排序
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data[0] = $block->getBugParamsTest('qa');
|
||||
$data[1] = $block->getBugParamsTest('my');
|
||||
|
||||
r($data[0]) && p('count:name;type:name;orderBy:name') && e('数量;类型;排序'); //测试通过模块获取Bug区块的参数
|
||||
r($data[1]) && p('count:name;type:name;orderBy:name') && e('数量;类型;排序'); //测试通过模块获取Bug区块的参数
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getBuildParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取版本区块参数 >> 数量,20,input
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data = $block->getBuildParamsTest();
|
||||
|
||||
r($data) && p('count:name,default,control') && e('数量,20,input'); //测试获取版本区块参数
|
||||
@@ -7,11 +7,13 @@ function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2-5');
|
||||
$block->account->range('admin,test1,test2');
|
||||
$block->account->range('admin');
|
||||
$block->vision->range('rnd,lite');
|
||||
$block->module->range('my,qa,project');
|
||||
$block->title->prefix('区块')->range('2-5');
|
||||
$block->order->range('5-2');
|
||||
$block->dashboard->range('my');
|
||||
$block->module->range('project');
|
||||
$block->code->range('list,statistic');
|
||||
$block->title->prefix('区块名称')->range('2-5');
|
||||
$block->order->range('1-4');
|
||||
|
||||
$block->gen(4);
|
||||
}
|
||||
@@ -22,18 +24,18 @@ title=测试 blockModel->getByID();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 执行block模块的getByID方法,参数是2
|
||||
- 测试获取正常的block的内容
|
||||
- 属性account @admin
|
||||
- 属性vision @rnd
|
||||
- 属性module @my
|
||||
- 属性title @区块2
|
||||
- 属性source @my
|
||||
- 属性block @bug
|
||||
- 属性order @5
|
||||
- 属性dashboard @my
|
||||
- 属性module @project
|
||||
- 属性code @list
|
||||
- 属性title @区块名称2
|
||||
- 属性order @1
|
||||
|
||||
- 执行block模块的getByID方法,参数是4,属性order @3
|
||||
- 执行block模块的getByID方法,参数是6 @0
|
||||
- 测试获取正常的block的内容属性order @3
|
||||
|
||||
- 测试获取不存在的block的内容 @0
|
||||
|
||||
*/
|
||||
|
||||
@@ -42,6 +44,6 @@ $tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->block->getByID(2)) && p('account,vision,module,title,order') && e('admin,rnd,my,区块2,5'); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID(2)) && p('account,vision,dashboard,module,code,title,order') && e('admin,rnd,my,project,list,区块名称2,1'); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID(4)) && p('order') && e('3'); // 测试获取正常的block的内容
|
||||
r($tester->block->getByID(6)) && p('') && e('0'); // 测试获取不存在的block的内容
|
||||
r($tester->block->getByID(6)) && p('') && e('0'); // 测试获取不存在的block的内容
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getCaseParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试通过模块获取用例区块的参数 >> 数量;类型;排序
|
||||
测试通过模块获取用例区块的参数 >> 数量;类型;排序
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data[0] = $block->getCaseParamsTest('qa');
|
||||
$data[1] = $block->getCaseParamsTest('my');
|
||||
|
||||
r($data[0]) && p('count:name;type:name;orderBy:name') && e('数量;类型;排序'); //测试通过模块获取用例区块的参数
|
||||
r($data[1]) && p('count:name;type:name;orderBy:name') && e('数量;类型;排序'); //测试通过模块获取用例区块的参数
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getExecutionParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取执行区块的参数 >> 数量;类型
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data = $block->getExecutionParamsTest();
|
||||
|
||||
r($data) && p('count:name;type:name') && e('数量;类型'); //测试获取执行区块的参数
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getExecutionStatisticParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取执行区块的参数 >> 数量;类型
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data = $block->getExecutionStatisticParamsTest();
|
||||
|
||||
r($data) && p('count:name;type:name') && e('数量;类型'); //测试获取执行区块的参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getHiddenBlocks();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取隐藏的区块 >> 未获取到隐藏的区块
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getHiddenBlocksTest('my')) && p('message') && e('未获取到隐藏的区块'); //测试获取隐藏的区块
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getLastKey();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试通过qa模块获取区块的key >> 4
|
||||
测试通过my模块获取区块的key >> 10
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data[0] = $block->getLastKeyTest('qa');
|
||||
$data[1] = $block->getLastKeyTest('my');
|
||||
|
||||
r($data[0]) && p('qa') && e('4'); //测试通过qa模块获取区块的key
|
||||
r($data[1]) && p('my') && e('10'); //测试通过my模块获取区块的key
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getListParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试通过模块获取区块的参数 >> 数量
|
||||
测试通过模块获取区块的参数 >> 数量
|
||||
测试通过模块获取区块的参数 >> 数量;类型;排序
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
$data[0] = $block->getListParamsTest('my');
|
||||
$data[1] = $block->getListParamsTest('qa');
|
||||
$data[2] = $block->getListParamsTest('project');
|
||||
|
||||
r($data[0]) && p('count:name') && e('数量'); //测试通过模块获取区块的参数
|
||||
r($data[1]) && p('count:name') && e('数量'); //测试通过模块获取区块的参数
|
||||
r($data[2]) && p('count:name;type:name;orderBy:name') && e('数量;类型;排序'); //测试通过模块获取区块的参数
|
||||
@@ -2,20 +2,19 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
|
||||
$userModel = new userModel();
|
||||
$user = $userModel->identify('admin', 'Asd123456');
|
||||
$userModel->login($user);
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2-5');
|
||||
$block->account->range('admin,test1,test2');
|
||||
$block->account->range('admin');
|
||||
$block->vision->range('rnd,lite');
|
||||
$block->module->range('my,qa,project');
|
||||
$block->title->prefix('区块')->range('2-5');
|
||||
$block->dashboard->range('my,qa');
|
||||
$block->order->range('5-2');
|
||||
$block->dashboard->range('my');
|
||||
$block->module->range('project');
|
||||
$block->code->range('list,statistic');
|
||||
$block->title->prefix('区块名称')->range('2-5');
|
||||
$block->order->range('1-4');
|
||||
|
||||
$block->gen(4);
|
||||
}
|
||||
@@ -26,16 +25,6 @@ title=测试 blockModel->getMaxOrderByDashboard();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 执行block模块的getByID方法,参数是2
|
||||
- 属性account @admin
|
||||
- 属性vision @rnd
|
||||
- 属性module @my
|
||||
- 属性title @区块2
|
||||
- 属性source @my
|
||||
- 属性block @bug
|
||||
- 属性order @5
|
||||
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
@@ -43,6 +32,6 @@ $tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->block->getMaxOrderByDashboard('my')) && p('') && e('5'); // 测试 my 模块下最大order 为 5
|
||||
r($tester->block->getMaxOrderByDashboard('my')) && p('') && e('5'); // 测试 my 模块下最大order 为 5
|
||||
r($tester->block->getMaxOrderByDashboard('my')) && p('') && e('4'); // 测试 my 模块下最大order 为 4
|
||||
r($tester->block->getMaxOrderByDashboard('my')) && p('') && e('4'); // 测试 my 模块下最大order 为 4
|
||||
r($tester->block->getMaxOrderByDashboard('bug')) && p('') && e('0'); // 测试数据库中不存在 模块的最大排序 为 0
|
||||
|
||||
@@ -3,25 +3,19 @@
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
|
||||
#su('admin');
|
||||
|
||||
$userModel = new userModel();
|
||||
$user = $userModel->identify('admin', 'Asd123456');
|
||||
$userModel->login($user);
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2-3');
|
||||
$block->id->range('2-5');
|
||||
$block->account->range('admin');
|
||||
$block->vision->range('rnd');
|
||||
$block->module->range('test,my');
|
||||
$block->title->prefix('区块')->range('3,2');
|
||||
$block->hidden->range('0-1');
|
||||
$block->order->range('3-2');
|
||||
$block->dashboard->range('test,my');
|
||||
$block->vision->range('rnd,lite');
|
||||
$block->dashboard->range('my,qa,project');
|
||||
$block->title->prefix('区块')->range('2-5');
|
||||
$block->order->range('5-2');
|
||||
|
||||
$block->gen(2);
|
||||
$block->gen(4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,7 +30,8 @@ $tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->block->getMyDashboard('test')) && p('2:account,title') && e('admin,区块3'); // 测试我的 test 模块的面板
|
||||
r($tester->block->getMyHiddenBlocks('my')) && p('3:account,title') && e('admin,区块2');// 测试我的 my 模块隐藏的面板
|
||||
r($tester->block->getMyDashboard('noneModule')) && p('') && e('0');// 测试我的 不存在的 模块的面板
|
||||
r($tester->block->getMyDashboard('')) && p('') && e('0');// 测试我的 空 模块的面板
|
||||
r(count($tester->block->getMyDashboard('my'))) && p('') && e('1'); // 查询admin用户在我的地盘仪表盘的区块列表数量
|
||||
r($tester->block->getMyDashboard('my')) && p('2:title') && e('区块2'); // 查询admin用户在我的地盘仪表盘的区块标题第2条的title属性
|
||||
r(count($tester->block->getMyDashboard('my', 1))) && p('') && e('0'); // 查询admin用户在我的地盘仪表盘的隐藏区块列表数量
|
||||
r(count($tester->block->getMyDashboard('asdas?'))) && p('') && e('0'); // 查询admin用户在不存在仪表盘的区块列表数量
|
||||
r($tester->block->getMyDashboard('my')) && p('2:vision') && e('rnd'); // 查询admin用户在我的地盘仪表盘区块的vision第2条的vision属性
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getPlanParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取计划参数 >> {"count":{"name":"\u6570\u91cf","default":20,"control":"input"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getPlanParamsTest()) && p() && e('{"count":{"name":"\u6570\u91cf","default":20,"control":"input"}}'); // 获取计划参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getProductParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取产品区块的参数 >> type:{name:类型,noclosed=>未关闭,closed=>已关闭,all=>全部,involved=>我参与,control:select};count:{name:数量,default:20,control:input};
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getProductParamsTest()) && p() && e('type:{name:类型,noclosed=>未关闭,closed=>已关闭,all=>全部,involved=>我参与,control:select};count:{name:数量,default:20,control:input};'); // 获取产品区块的参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getProductStatisticParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取产品统计区块的参数 >> count:{name:数量,default:20,control:input};type:{name:类型,noclosed=>未关闭,closed=>已关闭,all=>全部,involved=>我参与,control:select};
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getProductStatisticParamsTest()) && p() && e('count:{name:数量,default:20,control:input};type:{name:类型,noclosed=>未关闭,closed=>已关闭,all=>全部,involved=>我参与,control:select};'); // 获取产品统计区块的参数
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getProjectDynamicParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取项目动态区块参数 >> count:{name:数量,default:20,control:input};
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getProjectDynamicParamsTest()) && p() && e('count:{name:数量,default:20,control:input};'); // 获取项目动态区块参数
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getProjectParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取计划参数 >> {"type":{"name":"\u7c7b\u578b","options":{"all":"\u6240\u6709","undone":"\u672a\u5b8c\u6210","wait":"\u672a\u5f00\u59cb","doing":"\u8fdb\u884c\u4e2d","suspended":"\u5df2\u6302\u8d77","closed":"\u5df2\u5173\u95ed"},"control":"select"},"orderBy":{"name":"\u6392\u5e8f","options":{"id_asc":"ID \u9012\u589e","id_desc":"ID \u9012\u51cf","status_asc":"\u72b6\u6001\u6b63\u5e8f","status_desc":"\u72b6\u6001\u5012\u5e8f"},"control":"select"},"count":{"name":"\u6570\u91cf","default":20,"control":"input"}}
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getProjectParamsTest()) && p() && e('{"type":{"name":"\u7c7b\u578b","options":{"all":"\u6240\u6709","undone":"\u672a\u5b8c\u6210","wait":"\u672a\u5f00\u59cb","doing":"\u8fdb\u884c\u4e2d","suspended":"\u5df2\u6302\u8d77","closed":"\u5df2\u5173\u95ed"},"control":"select"},"orderBy":{"name":"\u6392\u5e8f","options":{"id_asc":"ID \u9012\u589e","id_desc":"ID \u9012\u51cf","status_asc":"\u72b6\u6001\u6b63\u5e8f","status_desc":"\u72b6\u6001\u5012\u5e8f"},"control":"select"},"count":{"name":"\u6570\u91cf","default":20,"control":"input"}}'); //获取计划参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getProjectStatisticParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取project静态param >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"undone":"未完成","doing":"进行中","all":"全部","involved":"我参与的"},"control":"select"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getProjectStatisticParamsTest()) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"undone":"未完成","doing":"进行中","all":"全部","involved":"我参与的"},"control":"select"}}'); // 获取project静态param
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getProjectTeamParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取项目团队 >> type:{name:类型,all=>所有,undone=>未完成,wait=>未开始,doing=>进行中,suspended=>已挂起,closed=>已关闭,control:select};orderBy:{name:排序,id_asc=>ID 递增,id_desc=>ID 递减,status_asc=>状态正序,status_desc=>状态倒序,control:select};count:{name:数量,default:20,control:input};
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getProjectTeamParamsTest()) && p() && e('type:{name:类型,all=>所有,undone=>未完成,wait=>未开始,doing=>进行中,suspended=>已挂起,closed=>已关闭,control:select};orderBy:{name:排序,id_asc=>ID 递增,id_desc=>ID 递减,status_asc=>状态正序,status_desc=>状态倒序,control:select};count:{name:数量,default:20,control:input};'); // 测试获取项目团队
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getQaStatisticParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试name >> 类型
|
||||
测试control >> select
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getQaStatisticParamsTest()) && p('type:name') && e('类型'); //测试name
|
||||
r($block->getQaStatisticParamsTest()) && p('type:control') && e('select');//测试control
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getReleaseParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试name >> 数量,20,input
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getReleaseParamsTest()) && p('name,default,control') && e('数量,20,input'); //测试name
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getScrumListParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试name和select >> 类型,select
|
||||
测试options >> 未完成
|
||||
测试options >> 进行中
|
||||
测试options >> 全部
|
||||
测试options >> 我参与
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getScrumListParamsTest()) && p('name,control') && e('类型,select'); //测试name和select
|
||||
r($block->getScrumListParamsTest()) && p('options:undone') && e('未完成'); //测试options
|
||||
r($block->getScrumListParamsTest()) && p('options:doing') && e('进行中'); //测试options
|
||||
r($block->getScrumListParamsTest()) && p('options:all') && e('全部'); //测试options
|
||||
r($block->getScrumListParamsTest()) && p('options:involved') && e('我参与'); //测试options
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getScrumProductParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取产品区块的参数 >> 数量;20;input
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getScrumProductParamsTest()) && p('count:name;count:default;count:control') && e('数量;20;input'); // 测试获取产品区块的参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getScrumRoadMapParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取产品路线图区块的参数 >> 0
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getScrumRoadMapParamsTest()) && p() && e('0'); // 测试获取产品路线图区块的参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getScrumTestParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取测试单区块的参数 >> 数量;类型
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getScrumTestParamsTest()) && p('count:name;type:name') && e('数量;类型'); // 测试获取测试单区块的参数
|
||||
@@ -1,34 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getStatisticParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取空区块的参数 >> {"count":{"name":"数量","default":20,"control":"input"}}
|
||||
获取产品区块的参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"noclosed":"未关闭","closed":"已关闭","all":"全部","involved":"我参与"},"control":"select"}}
|
||||
获取项目区块的参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"undone":"未完成","doing":"进行中","all":"全部","involved":"我参与的"},"control":"select"}}
|
||||
获取执行区块的参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"undone":"未完成","doing":"进行中","all":"所有","involved":"我参与"},"control":"select"}}
|
||||
获取测试区块的参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"noclosed":"未关闭","closed":"已关闭","all":"全部","involved":"我参与"},"control":"select"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
$data = array();
|
||||
$data[0] = $block->getStatisticParamsTest('');
|
||||
$data[1] = $block->getStatisticParamsTest('product');
|
||||
$data[2] = $block->getStatisticParamsTest('project');
|
||||
$data[3] = $block->getStatisticParamsTest('execution');
|
||||
$data[4] = $block->getStatisticParamsTest('qa');
|
||||
|
||||
r($data[0]) && p() && e('{"count":{"name":"数量","default":20,"control":"input"}}'); // 获取空区块的参数
|
||||
r($data[1]) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"noclosed":"未关闭","closed":"已关闭","all":"全部","involved":"我参与"},"control":"select"}}'); // 获取产品区块的参数
|
||||
r($data[2]) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"undone":"未完成","doing":"进行中","all":"全部","involved":"我参与的"},"control":"select"}}'); // 获取项目区块的参数
|
||||
r($data[3]) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"undone":"未完成","doing":"进行中","all":"所有","involved":"我参与"},"control":"select"}}'); // 获取执行区块的参数
|
||||
r($data[4]) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"noclosed":"未关闭","closed":"已关闭","all":"全部","involved":"我参与"},"control":"select"}}'); // 获取测试区块的参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getStoryParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取需求的参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"assignedTo":"指派给我","openedBy":"由我创建","reviewedBy":"由我评审","closedBy":"由我关闭"},"control":"select"},"orderBy":{"name":"排序","default":"id_desc","options":{"id_asc":"ID 递增","id_desc":"ID 递减","pri_asc":"优先级递增","pri_desc":"优先级递减","status_asc":"状态正序","status_desc":"状态倒序","stage_asc":"阶段正序","stage_desc":"阶段倒序"},"control":"select"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getStoryParamsTest()) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"assignedTo":"指派给我","openedBy":"由我创建","reviewedBy":"由我评审","closedBy":"由我关闭"},"control":"select"},"orderBy":{"name":"排序","default":"id_desc","options":{"id_asc":"ID 递增","id_desc":"ID 递减","pri_asc":"优先级递增","pri_desc":"优先级递减","status_asc":"状态正序","status_desc":"状态倒序","stage_asc":"阶段正序","stage_desc":"阶段倒序"},"control":"select"}}'); // 获取需求的参数
|
||||
@@ -1,29 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getStorysEstimateHours();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取需求 1 的预计工时 >> 1
|
||||
获取需求 2 的预计工时 >> 1
|
||||
获取需求 3 的预计工时 >> 1
|
||||
获取需求 4 的预计工时 >> 1
|
||||
获取需求 5 的预计工时 >> 1
|
||||
|
||||
*/
|
||||
|
||||
$storyID = array(1, 2, 3, 4, 5);
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getStorysEstimateHoursTest($storyID[0])) && p('estimate') && e('1'); // 获取需求 1 的预计工时
|
||||
r($block->getStorysEstimateHoursTest($storyID[1])) && p('estimate') && e('1'); // 获取需求 2 的预计工时
|
||||
r($block->getStorysEstimateHoursTest($storyID[2])) && p('estimate') && e('1'); // 获取需求 3 的预计工时
|
||||
r($block->getStorysEstimateHoursTest($storyID[3])) && p('estimate') && e('1'); // 获取需求 4 的预计工时
|
||||
r($block->getStorysEstimateHoursTest($storyID[4])) && p('estimate') && e('1'); // 获取需求 5 的预计工时
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getTaskParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取task的参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"assignedTo":"指派给我","openedBy":"由我创建","finishedBy":"由我完成","closedBy":"由我关闭","canceledBy":"由我取消"},"control":"select"},"orderBy":{"name":"排序","default":"id_desc","options":{"id_asc":"ID 递增","id_desc":"ID 递减","pri_asc":"优先级递增","pri_desc":"优先级递减","estimate_asc":"预计时间递增","estimate_desc":"预计时间递减","status_asc":"状态正序","status_desc":"状态倒序","deadline_asc":"截止日期递增","deadline_desc":"截止日期递减"},"control":"select"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getTaskParamsTest()) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"assignedTo":"指派给我","openedBy":"由我创建","finishedBy":"由我完成","closedBy":"由我关闭","canceledBy":"由我取消"},"control":"select"},"orderBy":{"name":"排序","default":"id_desc","options":{"id_asc":"ID 递增","id_desc":"ID 递减","pri_asc":"优先级递增","pri_desc":"优先级递减","estimate_asc":"预计时间递增","estimate_desc":"预计时间递减","status_asc":"状态正序","status_desc":"状态倒序","deadline_asc":"截止日期递增","deadline_desc":"截止日期递减"},"control":"select"}}'); // 获取task的参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getTesttaskParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取testtask参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"wait":"待测版本","doing":"测试中版本","blocked":"阻塞版本","done":"已测版本","all":"全部"},"control":"select"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getTesttaskParamsTest()) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":{"wait":"待测版本","doing":"测试中版本","blocked":"阻塞版本","done":"已测版本","all":"全部"},"control":"select"}}'); // 获取testtask参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getTodoParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取todo参数 >> {"count":{"name":"数量","default":20,"control":"input"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getTodoParamsTest()) && p() && e('{"count":{"name":"数量","default":20,"control":"input"}}'); // 获取todo参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getWaterfallIssueParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取waterfall issue的参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":null,"control":"select"},"orderBy":{"name":"排序","options":{"id_asc":"ID 递增","id_desc":"ID 递减","status_asc":"状态正序","status_desc":"状态倒序"},"control":"select"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getWaterfallIssueParamsTest()) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":null,"control":"select"},"orderBy":{"name":"排序","options":{"id_asc":"ID 递增","id_desc":"ID 递减","status_asc":"状态正序","status_desc":"状态倒序"},"control":"select"}}'); // 获取waterfall issue的参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getWaterfallRiskParams();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取waterfall risk 参数 >> {"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":null,"control":"select"},"orderBy":{"name":"排序","options":{"id_asc":"ID 递增","id_desc":"ID 递减","status_asc":"状态正序","status_desc":"状态倒序"},"control":"select"}}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getWaterfallRiskParamsTest()) && p() && e('{"count":{"name":"数量","default":20,"control":"input"},"type":{"name":"类型","options":null,"control":"select"},"orderBy":{"name":"排序","options":{"id_asc":"ID 递增","id_desc":"ID 递减","status_asc":"状态正序","status_desc":"状态倒序"},"control":"select"}}'); // 获取waterfall risk 参数
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->getWelcomeBlockData();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取欢迎区块的数据 >> {"tasks":"0","doneTasks":"0","bugs":85,"stories":0,"executions":739,"products":80,"delayTask":0,"delayBug":74,"delayProject":0}
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->getWelcomeBlockDataTest()) && p() && e('{"tasks":"0","doneTasks":"0","bugs":85,"stories":0,"executions":739,"products":80,"delayTask":0,"delayBug":74,"delayProject":0}'); // 获取欢迎区块的数据
|
||||
@@ -7,54 +7,31 @@ su('admin');
|
||||
/**
|
||||
|
||||
title=测试 blockModel->initBlock();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取敏捷项目的区块版本 >> 1;2
|
||||
获取敏捷项目的区块数据 >> project;scrum
|
||||
获取瀑布项目的区块版本 >> 1;2
|
||||
获取瀑布项目的区块数据 >> project;waterfall
|
||||
获取看板项目的区块版本 >> 1;2
|
||||
获取看板项目的区块数据 >> project;kanban
|
||||
获取产品的区块版本 >> 1;2
|
||||
获取产品的区块数据 >> product;
|
||||
获取执行的区块版本 >> 1;2
|
||||
获取执行的区块数据 >> execution;
|
||||
获取地盘的区块版本 >> 1;2
|
||||
获取地盘的区块数据 >> my;
|
||||
获取测试的区块版本 >> 1;2
|
||||
获取测试的区块数据 >> qa;
|
||||
获取空区块版本 >> 1;2
|
||||
获取空区块数据 >> 0
|
||||
- 测试获取正常的block的内容
|
||||
- 属性account @admin
|
||||
- 属性dashboard @my
|
||||
- 属性module @welcome
|
||||
- 属性code @welcome
|
||||
- 属性title @欢迎
|
||||
|
||||
- 测试获取正常的block的内容
|
||||
- 属性account @admin
|
||||
- 属性dashboard @my
|
||||
- 属性module @project
|
||||
- 属性code @project
|
||||
- 属性title @项目列表
|
||||
|
||||
*/
|
||||
|
||||
$block = new blockTest();
|
||||
global $tester, $app;
|
||||
$tester->loadModel('block');
|
||||
$tester->block->reset('my');
|
||||
|
||||
$dataList = array();
|
||||
$dataList[0] = $block->initBlockTest('project', 'scrum');
|
||||
$dataList[1] = $block->initBlockTest('project', 'waterfall');
|
||||
$dataList[2] = $block->initBlockTest('project', 'kanban');
|
||||
$dataList[3] = $block->initBlockTest('product');
|
||||
$dataList[4] = $block->initBlockTest('execution');
|
||||
$dataList[5] = $block->initBlockTest('my');
|
||||
$dataList[6] = $block->initBlockTest('qa');
|
||||
$dataList[7] = $block->initBlockTest('');
|
||||
|
||||
r($dataList[0]) && p("blockInited;blockversion") && e('1;2'); // 获取敏捷项目的区块版本
|
||||
r($dataList[0]) && p("blockData:module;blockData:type") && e('project;scrum'); // 获取敏捷项目的区块数据
|
||||
r($dataList[1]) && p("blockInited;blockversion") && e('1;2'); // 获取瀑布项目的区块版本
|
||||
r($dataList[1]) && p("blockData:module;blockData:type") && e('project;waterfall'); // 获取瀑布项目的区块数据
|
||||
r($dataList[2]) && p("blockInited;blockversion") && e('1;2'); // 获取看板项目的区块版本
|
||||
r($dataList[2]) && p("blockData:module;blockData:type") && e('project;kanban'); // 获取看板项目的区块数据
|
||||
r($dataList[3]) && p("blockInited;blockversion") && e('1;2'); // 获取产品的区块版本
|
||||
r($dataList[3]) && p("blockData:module;blockData:type") && e('product;'); // 获取产品的区块数据
|
||||
r($dataList[4]) && p("blockInited;blockversion") && e('1;2'); // 获取执行的区块版本
|
||||
r($dataList[4]) && p("blockData:module;blockData:type") && e('execution;'); // 获取执行的区块数据
|
||||
r($dataList[5]) && p("blockInited;blockversion") && e('1;2'); // 获取地盘的区块版本
|
||||
r($dataList[5]) && p("blockData:module;blockData:type") && e('my;'); // 获取地盘的区块数据
|
||||
r($dataList[6]) && p("blockInited;blockversion") && e('1;2'); // 获取测试的区块版本
|
||||
r($dataList[6]) && p("blockData:module;blockData:type") && e('qa;'); // 获取测试的区块数据
|
||||
r($dataList[7]) && p("blockInited;blockversion") && e('1;2'); // 获取空区块版本
|
||||
r($dataList[7]) && p("blockData") && e('0'); // 获取空区块数据
|
||||
$tester->block->initBlock('my');
|
||||
$newBlcoks = $tester->block->getMyDashboard('my');
|
||||
|
||||
r(reset($newBlcoks)) && p('account,dashboard,module,code,title') && e('admin,my,welcome,welcome,欢迎'); // 测试获取正常的block的内容
|
||||
r(end($newBlcoks)) && p('account,dashboard,module,code,title') && e('admin,my,project,project,项目列表'); // 测试获取正常的block的内容
|
||||
|
||||
@@ -2,35 +2,46 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2-5');
|
||||
$block->account->range('admin');
|
||||
$block->vision->range('rnd,lite');
|
||||
$block->dashboard->range('my');
|
||||
$block->module->range('project');
|
||||
$block->code->range('list,statistic');
|
||||
$block->title->prefix('区块名称')->range('2-5');
|
||||
$block->grid->range('4,8');
|
||||
$block->order->range('1-4');
|
||||
|
||||
$block->gen(4);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->isLongBlock();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试 空 对象 检查是否为长区块 >> 2
|
||||
测试 对象grid为 5 的时候 检查是否为长区块 >> 2
|
||||
测试 对象grid为 6 的时候 检查是否为长区块 >> 1
|
||||
测试 对象grid为 7 的时候 检查是否为长区块 >> 1
|
||||
- 测试 空 对象 检查是否为长区块 @0
|
||||
|
||||
- 测试 空 对象 检查是否为长区块 @0
|
||||
|
||||
- 测试 空 对象 检查是否为长区块 @1
|
||||
|
||||
*/
|
||||
|
||||
$block1 = new stdclass();
|
||||
global $tester;
|
||||
$tester->loadModel('block');
|
||||
|
||||
$block2 = new stdclass();
|
||||
$block2->grid = 5;
|
||||
initData();
|
||||
|
||||
$block3 = new stdclass();
|
||||
$block3->grid = 6;
|
||||
$emptyObject = new stdclass();
|
||||
|
||||
$block4 = new stdclass();
|
||||
$block4->grid = 7;
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->isLongBlockTest($block1)) && p() && e('2'); // 测试 空 对象 检查是否为长区块
|
||||
r($block->isLongBlockTest($block2)) && p() && e('2'); // 测试 对象grid为 5 的时候 检查是否为长区块
|
||||
r($block->isLongBlockTest($block3)) && p() && e('1'); // 测试 对象grid为 6 的时候 检查是否为长区块
|
||||
r($block->isLongBlockTest($block4)) && p() && e('1'); // 测试 对象grid为 7 的时候 检查是否为长区块
|
||||
r($tester->block->isLongBlock($emptyObject)) && p() && e('0'); // 测试 空 对象 检查是否为长区块
|
||||
r($tester->block->isLongBlock($tester->block->getByID(2))) && p() && e('0'); // 测试 空 对象 检查是否为长区块
|
||||
r($tester->block->isLongBlock($tester->block->getByID(3))) && p() && e('1'); // 测试 空 对象 检查是否为长区块
|
||||
@@ -1,56 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 blockModel->save();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试修改block 名称 >> 欢迎test,my,8,welcome
|
||||
测试修改block 模块 >> 我的贡献,my,8,dynamic
|
||||
测试修改block 区块 >> 项目统计,projectteam,8,projectteam
|
||||
测试修改block 变量 >> 未关闭的产品,statistic,8,statistic
|
||||
|
||||
*/
|
||||
|
||||
$blockID = array('95', '99', '113');
|
||||
$source = 'product';
|
||||
|
||||
$changeTitle = new stdclass();
|
||||
$changeTitle->modules = 'welcome';
|
||||
$changeTitle->title = '欢迎test';
|
||||
$changeTitle->grid = 8;
|
||||
$changeTitle->actionLink = '/block-set-95-welcome-.html';
|
||||
|
||||
$changeModules = new stdclass();
|
||||
$changeModules->modules = 'dynamic';
|
||||
$changeModules->title = '我的贡献';
|
||||
$changeModules->grid = 8;
|
||||
$changeModules->actionLink = '/block-set-95-welcome-.html';
|
||||
|
||||
$changeBlock = new stdclass();
|
||||
$changeBlock->modules = 'project';
|
||||
$changeBlock->title = '项目统计';
|
||||
$changeBlock->moduleBlock = 'projectteam';
|
||||
$changeBlock->grid = 8;
|
||||
$changeBlock->params = array('type' => 'all', 'orderBy' => 'id_asc', 'count' => 20);
|
||||
$changeBlock->actionLink = '/block-set-95-welcome-.html';
|
||||
|
||||
$changeParams = new stdclass();
|
||||
$changeParams->modules = 'product';
|
||||
$changeParams->title = '未关闭的产品';
|
||||
$changeParams->moduleBlock = 'statistic';
|
||||
$changeParams->grid = 8;
|
||||
$changeParams->params = array('type' => 'noclosed', 'count' => 30);
|
||||
$changeParams->actionLink = '/block-set-95-welcome-.html';
|
||||
|
||||
$block = new blockTest();
|
||||
|
||||
r($block->saveTest($changeTitle, $blockID[0], $source, $changeTitle->modules)) && p('title,module,grid,block') && e('欢迎test,my,8,welcome'); // 测试修改block 名称
|
||||
r($block->saveTest($changeModules, $blockID[0], $source, $changeModules->modules)) && p('title,module,grid,block') && e('我的贡献,my,8,dynamic'); // 测试修改block 模块
|
||||
r($block->saveTest($changeBlock, $blockID[1], $source, $changeBlock->modules, $changeBlock->moduleBlock)) && p('title,module,grid,block') && e('项目统计,projectteam,8,projectteam'); // 测试修改block 区块
|
||||
r($block->saveTest($changeParams, $blockID[2], $source, $changeParams->modules, $changeParams->moduleBlock)) && p('title,module,grid,block') && e('未关闭的产品,statistic,8,statistic'); // 测试修改block 变量
|
||||
@@ -8,14 +8,16 @@ su('admin');
|
||||
function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2');
|
||||
$block->account->range('test');
|
||||
$block->vision->range('rnd');
|
||||
$block->module->range('test');
|
||||
$block->title->prefix('区块')->range('2');
|
||||
$block->order->range('5');
|
||||
$block->id->range('2-5');
|
||||
$block->account->range('admin');
|
||||
$block->vision->range('rnd,lite');
|
||||
$block->dashboard->range('my');
|
||||
$block->module->range('project');
|
||||
$block->code->range('list,statistic');
|
||||
$block->title->prefix('区块名称')->range('2-5');
|
||||
$block->order->range('1-4');
|
||||
|
||||
$block->gen(1);
|
||||
$block->gen(4);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,18 +26,22 @@ title=测试 block 模块的update 方法
|
||||
timeout=0
|
||||
cid=39
|
||||
|
||||
- 执行block模块的getByID方法,参数是$newBlockID
|
||||
- 属性account @admin
|
||||
- 属性vision @rnd
|
||||
- 属性module @my
|
||||
- 属性title @区块123
|
||||
- 属性source @my
|
||||
- 属性block @bug
|
||||
- 属性order @5
|
||||
- 测试获取正常的block的内容
|
||||
- 属性account @admin2
|
||||
- 属性vision @lite
|
||||
- 属性dashboard @scrumproject
|
||||
- 属性module @project
|
||||
- 属性code @statistic
|
||||
- 属性title @项目统计区块
|
||||
- 属性order @1
|
||||
|
||||
- 执行blockTest模块的create方法,参数是$accoutTooLangBlock,属性account @『所属用户』长度应当不超过『30』,且大于『0』。
|
||||
- 测试所属模块为空 @『所属模块』不能为空。
|
||||
|
||||
- 测试所属区块为空 @『区块』不能为空。
|
||||
|
||||
- 测试区块名称为空 @『区块名称』不能为空。
|
||||
|
||||
- 测试account 字段字符超出长度 @『所属用户』长度应当不超过『30』,且大于『0』。
|
||||
|
||||
*/
|
||||
|
||||
@@ -44,25 +50,43 @@ $tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
$newBlock = new stdclass();
|
||||
$newBlock->id = '2';
|
||||
$newBlock->account = 'newadmin';
|
||||
$newBlock->vision = 'lite';
|
||||
$newBlock->module = 'newmy';
|
||||
$newBlock->title = 'new区块';
|
||||
$newBlock->params = '';
|
||||
$newBlock->order = '5';
|
||||
$block = new stdclass();
|
||||
$block->id = '2';
|
||||
$block->account = 'admin2';
|
||||
$block->vision = 'lite';
|
||||
$block->dashboard = 'scrumproject';
|
||||
$block->module = 'project';
|
||||
$block->code = 'statistic';
|
||||
$block->title = '项目统计区块';
|
||||
$block->order = '1';
|
||||
|
||||
$accoutTooLangBlock = new stdclass();
|
||||
$accoutTooLangBlock->id = '2';
|
||||
$accoutTooLangBlock->account = 'adminadminadminadminadminadminadminadmin1';
|
||||
$accoutTooLangBlock->vision = 'rnd';
|
||||
$accoutTooLangBlock->module = 'my';
|
||||
$accoutTooLangBlock->title = 'long account';
|
||||
$accoutTooLangBlock->order = '5';
|
||||
$accountTooLangBlock = new stdclass();
|
||||
$accountTooLangBlock->id = '3';
|
||||
$accountTooLangBlock->account = 'adminadminadminadminadminadminadminadmin1';
|
||||
$accountTooLangBlock->vision = 'rnd';
|
||||
$accountTooLangBlock->dashboard = 'my';
|
||||
$accountTooLangBlock->module = 'project';
|
||||
$accountTooLangBlock->code = 'statistic';
|
||||
$accountTooLangBlock->title = '项目统计区块2';
|
||||
$accountTooLangBlock->order = '2';
|
||||
|
||||
$emptyModuleBlock = new stdclass();
|
||||
$emptyModuleBlock->id = '4';
|
||||
$emptyModuleBlock->module = '';
|
||||
|
||||
$emptyCodeBlock = new stdclass();
|
||||
$emptyCodeBlock->id = '4';
|
||||
$emptyCodeBlock->code = '';
|
||||
|
||||
$emptyTitleBlock = new stdclass();
|
||||
$emptyTitleBlock->id = '4';
|
||||
$emptyTitleBlock->title = '';
|
||||
|
||||
$blockTest = new blockTest();
|
||||
$newBlockID = $blockTest->updateTest($newBlock);
|
||||
$newBlockID = $blockTest->updateTest($block);
|
||||
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,module,title,order') && e("newadmin,lite,newmy,new区块,5"); // 测试获取正常的block的内容
|
||||
r($blockTest->updateTest($accoutTooLangBlock)) && p('account:0') && e('『所属用户』长度应当不超过『30』,且大于『0』。'); // 测试account 字段字符超出长度
|
||||
r($tester->block->getByID($newBlockID)) && p('account,vision,dashboard,module,code,title,order') && e("admin2,lite,scrumproject,project,statistic,项目统计区块,1"); // 测试获取正常的block的内容
|
||||
r($blockTest->updateTest($emptyModuleBlock)) && p('module:0') && e('『所属模块』不能为空。'); // 测试所属模块为空
|
||||
r($blockTest->updateTest($emptyCodeBlock)) && p('code:0') && e('『区块』不能为空。'); // 测试所属区块为空
|
||||
r($blockTest->updateTest($emptyTitleBlock)) && p('title:0') && e('『区块名称』不能为空。'); // 测试区块名称为空
|
||||
r($blockTest->updateTest($accountTooLangBlock)) && p('account:0') && e('『所属用户』长度应当不超过『30』,且大于『0』。'); // 测试account 字段字符超出长度
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2-5');
|
||||
$block->account->range('admin');
|
||||
$block->vision->range('rnd,lite');
|
||||
$block->dashboard->range('my,qa,project');
|
||||
$block->title->prefix('区块')->range('2-5');
|
||||
$block->order->range('5-2');
|
||||
|
||||
$block->gen(4);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=blockTao->fetchMyBlocks();
|
||||
timeout=0
|
||||
cid=2
|
||||
|
||||
*/
|
||||
$tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
r(count($tester->block->fetchMyBlocks('my'))) && p('') && e('1'); // 查询admin用户在我的地盘仪表盘的区块列表数量
|
||||
r($tester->block->fetchMyBlocks('my')) && p('2:title') && e('区块2'); // 查询admin用户在我的地盘仪表盘的区块标题第2条的title属性
|
||||
r(count($tester->block->fetchMyBlocks('my', 1))) && p('') && e('0'); // 查询admin用户在我的地盘仪表盘的隐藏区块列表数量
|
||||
r(count($tester->block->fetchMyBlocks('asdas?'))) && p('') && e('0'); // 查询admin用户在不存在仪表盘的区块列表数量
|
||||
r($tester->block->fetchMyBlocks('my')) && p('2:vision') && e('rnd'); // 查询admin用户在我的地盘仪表盘区块的vision第2条的vision属性
|
||||
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The product statistic block view file of block module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wangyuting <wangyuting@easycorp.ltd>
|
||||
* @package block
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
/**
|
||||
* 获取区块左侧的产品列表.
|
||||
* Get product tabs on the left side.
|
||||
*
|
||||
* @param array $products
|
||||
* @param string $blockNavCode
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
function getProductTabs($products, $blockNavCode): array
|
||||
{
|
||||
$navTabs = array();
|
||||
$selected = key($products);
|
||||
foreach($products as $product)
|
||||
{
|
||||
$navTabs[] = li
|
||||
(
|
||||
set('class', 'nav-item' . ($product->id == $selected ? ' active' : '')),
|
||||
a
|
||||
(
|
||||
set('class', 'ellipsis'),
|
||||
set('data-toggle', 'tab'),
|
||||
set('href', "#tab3{$blockNavCode}Content{$product->id}"),
|
||||
$product->name
|
||||
|
||||
),
|
||||
a
|
||||
(
|
||||
set('class', 'link flex-1 text-right hidden'),
|
||||
set('href', helper::createLink('product', 'browse', "productID=$product->id")),
|
||||
icon
|
||||
(
|
||||
set('class', 'rotate-90 text-primary'),
|
||||
'export'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return $navTabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取区块右侧显示的项目信息.
|
||||
* Get product statistical information.
|
||||
*
|
||||
* @param object $products
|
||||
* @param string $blockNavID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
function getProductInfo($products, $blockNavID): array
|
||||
{
|
||||
global $lang;
|
||||
|
||||
$selected = key($products);
|
||||
$tabItems = array();
|
||||
foreach($products as $product)
|
||||
{
|
||||
$tabItems[] = div
|
||||
(
|
||||
set('class', 'tab-pane' . ($product->id == $selected ? ' active' : '')),
|
||||
set('id', "tab3{$blockNavID}Content{$product->id}"),
|
||||
div
|
||||
(
|
||||
set('class', 'flex'),
|
||||
cell
|
||||
(
|
||||
set('width', '68%'),
|
||||
div
|
||||
(
|
||||
set('class', 'flex'),
|
||||
cell
|
||||
(
|
||||
set('width', '45%'),
|
||||
set('class', 'px-3 py-2'),
|
||||
div
|
||||
(
|
||||
set('class', 'mx-6 my-4 bg-primary aspect-square text-center align-middle'),
|
||||
span('需求交付率')
|
||||
),
|
||||
div
|
||||
(
|
||||
set('class', 'flex'),
|
||||
cell
|
||||
(
|
||||
set('class', 'flex-1 text-center'),
|
||||
div(span('8073')),
|
||||
div(span('BUG总数'))
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('class', 'flex-1 text-center'),
|
||||
div(span('6549')),
|
||||
div(span('已关闭'))
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('class', 'flex-1 text-center'),
|
||||
div(span('1542')),
|
||||
div(span('未关闭'))
|
||||
)
|
||||
)
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('width', '55%'),
|
||||
set('class', 'py-2'),
|
||||
div
|
||||
(
|
||||
set('class', 'py-2'),
|
||||
span('BUG统计')
|
||||
),
|
||||
div
|
||||
(
|
||||
set('class', 'flex border-r py-1'),
|
||||
cell
|
||||
(
|
||||
div(set('class', 'py-1'), span('昨日新增'), span(set('class', 'ml-1'), '12')),
|
||||
div(set('class', 'py-1'), span('今日新增'), span(set('class', 'ml-1'), '6')),
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('class', 'flex-1 px-3'),
|
||||
div
|
||||
(
|
||||
set('class', 'py-1'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress-bar'),
|
||||
set('role', 'progressbar'),
|
||||
setStyle(['width' => '36%']),
|
||||
)
|
||||
)
|
||||
),
|
||||
div
|
||||
(
|
||||
set('class', 'py-1'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress-bar'),
|
||||
set('role', 'progressbar'),
|
||||
setStyle(['width' => '18%']),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
div
|
||||
(
|
||||
set('class', 'flex border-r py-1'),
|
||||
cell
|
||||
(
|
||||
div(set('class', 'py-1'), span('昨日解决'), span(set('class', 'ml-1'), '36')),
|
||||
div(set('class', 'py-1'), span('今日解决'), span(set('class', 'ml-1'), '12')),
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('class', 'flex-1 px-3'),
|
||||
div
|
||||
(
|
||||
set('class', 'py-1'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress-bar'),
|
||||
set('role', 'progressbar'),
|
||||
setStyle(['width' => '84%']),
|
||||
)
|
||||
)
|
||||
),
|
||||
div
|
||||
(
|
||||
set('class', 'py-1'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress-bar'),
|
||||
set('role', 'progressbar'),
|
||||
setStyle(['width' => '28%']),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
div
|
||||
(
|
||||
set('class', 'flex border-r py-1'),
|
||||
cell
|
||||
(
|
||||
div(set('class', 'py-1'), span('昨日关闭'), span(set('class', 'ml-1'), '24')),
|
||||
div(set('class', 'py-1'), span('今日关闭'), span(set('class', 'ml-1'), '12')),
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('class', 'flex-1 px-3'),
|
||||
div
|
||||
(
|
||||
set('class', 'py-1'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress-bar'),
|
||||
set('role', 'progressbar'),
|
||||
setStyle(['width' => '60%']),
|
||||
)
|
||||
)
|
||||
),
|
||||
div
|
||||
(
|
||||
set('class', 'py-1'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress'),
|
||||
div
|
||||
(
|
||||
set('class', 'progress-bar'),
|
||||
set('role', 'progressbar'),
|
||||
setStyle(['width' => '30%']),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('width', '32%'),
|
||||
123
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
return $tabItems;
|
||||
}
|
||||
|
||||
$blockNavCode = 'nav-' . uniqid();
|
||||
div
|
||||
(
|
||||
set('class', 'productstatistic-block'),
|
||||
div
|
||||
(
|
||||
set('class', 'flex'),
|
||||
cell
|
||||
(
|
||||
set('width', '25%'),
|
||||
set('class', 'of-hidden bg-secondary-pale'),
|
||||
ul
|
||||
(
|
||||
set('class', 'nav nav-tabs nav-stacked'),
|
||||
getProductTabs($products, $blockNavCode)
|
||||
),
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('class', 'tab-content'),
|
||||
set('width', '75%'),
|
||||
getProductInfo($products, $blockNavCode)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The project block view file of block module of ZenTaoPMS.
|
||||
* The project statistic block view file of block module of ZenTaoPMS.
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Wangyuting <wangyuting@easycorp.ltd>
|
||||
@@ -14,9 +14,9 @@ namespace zin;
|
||||
/**
|
||||
* 获取区块左侧的项目列表.
|
||||
* Get project tabs on the left side.
|
||||
*
|
||||
* @param array $projects
|
||||
* @param string $blockNavCode
|
||||
*
|
||||
* @param array $projects
|
||||
* @param string $blockNavCode
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -54,10 +54,10 @@ function getProjectTabs($projects, $blockNavCode): array
|
||||
|
||||
/**
|
||||
* 获取区块右侧显示的项目信息.
|
||||
* Get project statistical information.
|
||||
*
|
||||
* @param object $projects
|
||||
* @param string $blockNavID
|
||||
* Get project statistical information.
|
||||
*
|
||||
* @param object $projects
|
||||
* @param string $blockNavID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -80,8 +80,8 @@ function getProjectInfo($projects, $blockNavID): array
|
||||
/**
|
||||
* 获取敏捷类项目的统计信息.
|
||||
* Get scrum project info.
|
||||
*
|
||||
* @param object $project
|
||||
*
|
||||
* @param object $project
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -89,7 +89,7 @@ function getScrumProjectInfo($project)
|
||||
{
|
||||
global $lang;
|
||||
|
||||
$scrumProjectInfo = div
|
||||
return div
|
||||
(
|
||||
/* 区块右侧顶部的项目概况。 */
|
||||
div
|
||||
@@ -158,14 +158,13 @@ function getScrumProjectInfo($project)
|
||||
getProjectStatisticItems($project)
|
||||
)
|
||||
);
|
||||
return $scrumProjectInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取项目的统计项.
|
||||
* get project statistic items.
|
||||
*
|
||||
* @param object $project
|
||||
*
|
||||
* @param object $project
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
@@ -233,7 +232,7 @@ function getWaterfallProjectInfo($project)
|
||||
{
|
||||
global $app, $lang;
|
||||
$isChineseLang = in_array($app->getClientLang(), array('zh-cn','zh-tw'));
|
||||
$waterfallProjectInfo = div
|
||||
return div
|
||||
(
|
||||
/* 瀑布项目展示概况。 */
|
||||
set('class', 'weekly-row'),
|
||||
@@ -343,7 +342,6 @@ function getWaterfallProjectInfo($project)
|
||||
)
|
||||
)
|
||||
);
|
||||
return $waterfallProjectInfo;
|
||||
}
|
||||
|
||||
$blockNavCode = 'nav-' . uniqid();
|
||||
|
||||
@@ -18,7 +18,7 @@ foreach($projects as $projectID => $project)
|
||||
$cards[] = cell
|
||||
(
|
||||
set('width', '33%'),
|
||||
set('class', 'border m-2 p-4'),
|
||||
set('class', 'border m-2 p-4'),
|
||||
div
|
||||
(
|
||||
set('class', 'pb-2'),
|
||||
|
||||
@@ -1118,9 +1118,7 @@ class blockZen extends block
|
||||
$this->loadModel('weekly');
|
||||
$this->app->loadLang('execution');
|
||||
|
||||
$projectID = $this->session->project;
|
||||
$project = $this->loadModel('project')->getByID($projectID);
|
||||
|
||||
$projectID = $this->session->project;
|
||||
$projectWeekly = $this->dao->select('*')->from(TABLE_WEEKLYREPORT)->where('project')->eq($projectID)->orderBy('weekStart_asc')->fetchAll('weekStart');
|
||||
|
||||
$charts['PV'] = '[';
|
||||
|
||||
+8
-9
@@ -225,14 +225,11 @@ class bugTao extends bugModel
|
||||
* @param int $bugID
|
||||
* @param string $linkBug
|
||||
* @param string $oldLinkBug
|
||||
* @access private
|
||||
* @access protected
|
||||
* @return bool
|
||||
*/
|
||||
private function updateLinkBug(int $bugID, string $linkBug, string $oldLinkBug): bool
|
||||
protected function updateLinkBug(int $bugID, string $linkBug, string $oldLinkBug): bool
|
||||
{
|
||||
|
||||
return false;
|
||||
|
||||
$linkBugs = explode(',', $linkBug);
|
||||
$oldLinkBugs = explode(',', $oldLinkBug);
|
||||
$addedLinkBugs = array_diff($linkBugs, $oldLinkBugs);
|
||||
@@ -242,19 +239,21 @@ class bugTao extends bugModel
|
||||
|
||||
foreach($changedLinkBugs as $changedBugID => $linkBugs)
|
||||
{
|
||||
if(in_array($changeBugID, $addedLinkBugs))
|
||||
if(in_array($changedBugID, $addedLinkBugs))
|
||||
{
|
||||
$currentLinkBug = $bugID;
|
||||
if(!empty($linkBugs)) $currentLinkBug = trim($linkBugs, ',') . ',' . $bugID;
|
||||
$linkBugs = explode(',', $linkBugs);
|
||||
if(!empty($linkBugs) && !in_array($bugID, $linkBugs)) $linkBugs[] = $bugID;
|
||||
}
|
||||
else
|
||||
{
|
||||
$linkBugs = explode(',', $linkBugs);
|
||||
unset($linkBugs[array_search($bugID, $linkBugs)]);
|
||||
$currentLinkBug = implode(',', $linkBugs);
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_BUG)->set('linkBug')->eq($linkBug)->where('id')->eq($changeBugID)->exec();
|
||||
$currentLinkBug = implode(',', array_filter($linkBugs));
|
||||
|
||||
$this->dao->update(TABLE_BUG)->set('linkBug')->eq($currentLinkBug)->where('id')->eq($changedBugID)->exec();
|
||||
}
|
||||
|
||||
return !dao::isError();
|
||||
|
||||
@@ -2135,4 +2135,30 @@ class bugTest
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The test for updatelinkbug function.
|
||||
*
|
||||
* @param string $bugID
|
||||
* @param string $linkBug
|
||||
* @param string $oldLinkBug
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function updateLinkBugTest($bugID, $linkBug, $oldLinkBug)
|
||||
{
|
||||
$this->objectModel->updateLinkBug($bugID, $linkBug, $oldLinkBug);
|
||||
|
||||
$linkBugs = explode(',', $linkBug);
|
||||
$oldLinkBugs = explode(',', $oldLinkBug);
|
||||
$addedLinkBugs = array_diff($linkBugs, $oldLinkBugs);
|
||||
$removedLinkBugs = array_diff($oldLinkBugs, $linkBugs);
|
||||
$allRelatedLinkBugs = array_merge($addedLinkBugs, $removedLinkBugs, array($bugID));
|
||||
|
||||
global $tester;
|
||||
$linkBugPairs = $tester->dao->select('id,linkBug')->from(TABLE_BUG)->where('id')->in(array_filter($allRelatedLinkBugs))->andWhere('deleted')->eq('0')->fetchPairs();
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
return $linkBugPairs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,18 @@ cid=1
|
||||
|
||||
- 测试不更改bug类型 @没有数据更新
|
||||
|
||||
- 测试不输入Bug标题 @『Bug标题』不能为空。
|
||||
|
||||
- 测试通知邮件不合法 @『通知邮箱』应当为合法的EMAIL。
|
||||
|
||||
- 测试解决者不为空时,不输入解决方案 @『解决方案』不能为空。
|
||||
|
||||
- 测试由谁关闭不为空时,不输入解决方案 @『解决方案』不能为空。
|
||||
|
||||
- 测试解决方案为重复Bug时,不输入重复Bug值 @『重复Bug』不能为空。
|
||||
|
||||
- 测试解决方案为已修复时,不输入解决版本 @『解决版本』不能为空。
|
||||
|
||||
|
||||
|
||||
*/
|
||||
@@ -50,13 +62,25 @@ initData();
|
||||
|
||||
$bugIdList = array('1', '2');
|
||||
|
||||
$t_uptitle = array('title' => 'john');
|
||||
$t_uptype = array('type' => 'config');
|
||||
$t_untitle = array('title' => 'john');
|
||||
$t_untype = array('type' => 'config');
|
||||
$t_uptitle = array('title' => 'john');
|
||||
$t_uptype = array('type' => 'config');
|
||||
$t_untitle = array('title' => 'john');
|
||||
$t_untype = array('type' => 'config');
|
||||
$t_titleRequire = array('title' => '');
|
||||
$t_unnotifyEmail = array('notifyEmail' => '123');
|
||||
$t_resolution1 = array('resolvedBy' => 'john', 'resolution' => '');
|
||||
$t_resolution2 = array('closedBy' => 'john', 'resolution' => '');
|
||||
$t_unduplicateBug = array('resolution' => 'duplicate', 'duplicateBug' => '');
|
||||
$t_unresolvedBuild = array('resolution' => 'fixed', 'resolvedBuild' => '');
|
||||
|
||||
$bug = new bugTest();
|
||||
r($bug->updateObject($bugIdList[0], $t_uptitle)) && p('0:field,old,new') && e('title,BUG1,john'); // 测试更新bug名称
|
||||
r($bug->updateObject($bugIdList[0], $t_uptype)) && p('0:field,old,new') && e('type,codeerror,config'); // 测试更新bug类型
|
||||
r($bug->updateObject($bugIdList[0], $t_untitle)) && p() && e('没有数据更新'); // 测试不更改bug名称
|
||||
r($bug->updateObject($bugIdList[0], $t_untype)) && p() && e('没有数据更新'); // 测试不更改bug类型
|
||||
r($bug->updateObject($bugIdList[0], $t_uptitle)) && p('0:field,old,new') && e('title,BUG1,john'); // 测试更新bug名称
|
||||
r($bug->updateObject($bugIdList[0], $t_uptype)) && p('0:field,old,new') && e('type,codeerror,config'); // 测试更新bug类型
|
||||
r($bug->updateObject($bugIdList[0], $t_untitle)) && p() && e('没有数据更新'); // 测试不更改bug名称
|
||||
r($bug->updateObject($bugIdList[0], $t_untype)) && p() && e('没有数据更新'); // 测试不更改bug类型
|
||||
r($bug->updateObject($bugIdList[0], $t_titleRequire)) && p('title:0') && e('『Bug标题』不能为空。'); // 测试不输入Bug标题
|
||||
r($bug->updateObject($bugIdList[0], $t_unnotifyEmail)) && p('notifyEmail:0') && e('『通知邮箱』应当为合法的EMAIL。'); // 测试通知邮件不合法
|
||||
r($bug->updateObject($bugIdList[0], $t_resolution1)) && p('resolution:0') && e('『解决方案』不能为空。'); // 测试解决者不为空时,不输入解决方案
|
||||
r($bug->updateObject($bugIdList[0], $t_resolution2)) && p('resolution:0') && e('『解决方案』不能为空。'); // 测试由谁关闭不为空时,不输入解决方案
|
||||
r($bug->updateObject($bugIdList[0], $t_unduplicateBug)) && p('duplicateBug:0') && e('『重复Bug』不能为空。'); // 测试解决方案为重复Bug时,不输入重复Bug值
|
||||
r($bug->updateObject($bugIdList[0], $t_unresolvedBuild)) && p('resolvedBuild:0') && e('『解决版本』不能为空。'); // 测试解决方案为已修复时,不输入解决版本
|
||||
@@ -0,0 +1,128 @@
|
||||
---
|
||||
fields:
|
||||
- field: id
|
||||
range: 1-5
|
||||
- field: project
|
||||
range: 0-5
|
||||
- field: product
|
||||
range: 1-5
|
||||
- field: branch
|
||||
range: 0-1
|
||||
- field: module
|
||||
range: 1821-1823,1825-1827,1831-1833,0{1000000}
|
||||
- field: execution
|
||||
range: 0-5
|
||||
- field: plan
|
||||
range: 1{3},4{3},7{3},0{1111111}
|
||||
- field: story
|
||||
range: 2-400:4
|
||||
- field: storyVersion
|
||||
range: 1
|
||||
- field: task
|
||||
range: 0
|
||||
- field: toTask
|
||||
range: 0
|
||||
- field: toStory
|
||||
range: 0
|
||||
- field: title
|
||||
range: 1-5
|
||||
prefix: BUG
|
||||
- field: keywords
|
||||
range: '[]'
|
||||
- field: severity
|
||||
range: '[3]'
|
||||
- field: pri
|
||||
range: '[3]'
|
||||
- field: type
|
||||
range: '[codeerror]'
|
||||
- field: os
|
||||
range: '[]{2},[win10,windows,android,ios]'
|
||||
- field: browser
|
||||
range: '[]'
|
||||
- field: hardware
|
||||
range: '[]'
|
||||
- field: found
|
||||
range: '[]'
|
||||
- field: steps
|
||||
range: '[<p>【步骤】</p><br/><p>【结果】</p><br/><p>【期望】</p><br/>,【步骤】进入成果展示<br/>【结果】乱码<br/>【期望】正常显示<br/>]'
|
||||
- field: status
|
||||
range: '[active]'
|
||||
- field: subStatus
|
||||
range: '[]'
|
||||
- field: color
|
||||
range: '[#3da7f5,#75c941,#2dbdb2,#797ec9,#ffaf38,#ff4e3e]'
|
||||
- field: confirmed
|
||||
range: 0,1
|
||||
- field: activatedCount
|
||||
range: 0
|
||||
- field: mailto
|
||||
range: admin{100},[]{200}
|
||||
- field: openedBy
|
||||
range: admin
|
||||
- field: openedDate
|
||||
range: (-1M)-(+1w):-1D
|
||||
type: timestamp
|
||||
format: YYYY-MM-DD hh:mm:ss
|
||||
- field: openedBuild
|
||||
range: 1-5
|
||||
- field: assignedTo
|
||||
range: '[admin,dev1,test1]{30},[]{20},[admin,dev1,test1]{20},[]{10},closed{20}'
|
||||
- field: assignedDate
|
||||
range: (-1M)-(+1w):-1D
|
||||
type: timestamp
|
||||
format: YYYY-MM-DD
|
||||
- field: deadline
|
||||
range: (-1M)-(+1w):-1D
|
||||
type: timestamp
|
||||
prefix: ""
|
||||
postfix: ""
|
||||
loop: 0
|
||||
format: YYYY-MM-DD
|
||||
- field: resolvedBy
|
||||
range: '[]{50},$assignedTo{30},admin{20}'
|
||||
- field: resolution
|
||||
range: '[]{50},bydesign{5},duplicate{5},external{5},fixed{5},notrepro{2},postponed{3},willnotfix{5},fixed{10},bydesign,external,notrepro,postponed,willnotfix,duplicate{5}'
|
||||
- field: resolvedBuild
|
||||
range: '[]{55},trunk{15},[]{25},trunk{5}'
|
||||
- field: resolvedDate
|
||||
range: (+1w)-(-2w):-1D
|
||||
type: timestamp
|
||||
prefix: ""
|
||||
postfix: ""
|
||||
loop: 0
|
||||
format: YYYY-MM-DD
|
||||
- field: closedBy
|
||||
range: '[]{50},admin{30}'
|
||||
- field: closedDate
|
||||
range: ~
|
||||
- field: duplicateBug
|
||||
range: 0{55},1-5,0{40},10-15
|
||||
- field: linkBug
|
||||
range: ~
|
||||
- field: case
|
||||
range: 0
|
||||
- field: caseVersion
|
||||
range: 0
|
||||
- field: result
|
||||
range: 0
|
||||
- field: repo
|
||||
range: 0
|
||||
- field: entry
|
||||
range: ~
|
||||
- field: lines
|
||||
range: ~
|
||||
- field: v1
|
||||
range: ~
|
||||
- field: v2
|
||||
range: ~
|
||||
- field: repoType
|
||||
range: ~
|
||||
- field: testtask
|
||||
range: 0
|
||||
- field: lastEditedBy
|
||||
range: ~
|
||||
- field: lastEditedDate
|
||||
range: ~
|
||||
- field: deleted
|
||||
range: 0{40},1{10},0{50}
|
||||
...
|
||||
@@ -0,0 +1,120 @@
|
||||
-- MySQL dump 10.13 Distrib 8.0.32, for Linux (x86_64)
|
||||
--
|
||||
-- Host: 127.0.0.1 Database: zentaopms184
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 8.0.32-0ubuntu0.22.04.2
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!50503 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `zt_bug`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `zt_bug`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `zt_bug` (
|
||||
`id` mediumint NOT NULL AUTO_INCREMENT,
|
||||
`project` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`product` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`injection` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`identify` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`branch` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`module` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`execution` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`plan` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`story` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`storyVersion` smallint NOT NULL DEFAULT '1',
|
||||
`task` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`toTask` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`toStory` mediumint NOT NULL DEFAULT '0',
|
||||
`title` varchar(255) NOT NULL DEFAULT '',
|
||||
`keywords` varchar(255) NOT NULL DEFAULT '',
|
||||
`severity` tinyint NOT NULL DEFAULT '0',
|
||||
`pri` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`type` varchar(30) NOT NULL DEFAULT '',
|
||||
`os` varchar(255) NOT NULL DEFAULT '',
|
||||
`browser` varchar(255) NOT NULL DEFAULT '',
|
||||
`hardware` varchar(30) NOT NULL DEFAULT '',
|
||||
`found` varchar(30) NOT NULL DEFAULT '',
|
||||
`steps` mediumtext,
|
||||
`status` enum('active','resolved','closed') NOT NULL DEFAULT 'active',
|
||||
`subStatus` varchar(30) NOT NULL DEFAULT '',
|
||||
`color` char(7) NOT NULL DEFAULT '',
|
||||
`confirmed` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`activatedCount` smallint NOT NULL DEFAULT '0',
|
||||
`activatedDate` datetime DEFAULT NULL,
|
||||
`feedbackBy` varchar(100) NOT NULL DEFAULT '',
|
||||
`notifyEmail` varchar(100) NOT NULL DEFAULT '',
|
||||
`mailto` text,
|
||||
`openedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`openedDate` datetime DEFAULT NULL,
|
||||
`openedBuild` varchar(255) NOT NULL DEFAULT '',
|
||||
`assignedTo` varchar(30) NOT NULL DEFAULT '',
|
||||
`assignedDate` datetime DEFAULT NULL,
|
||||
`deadline` date DEFAULT NULL,
|
||||
`resolvedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`resolution` varchar(30) NOT NULL DEFAULT '',
|
||||
`resolvedBuild` varchar(30) NOT NULL DEFAULT '',
|
||||
`resolvedDate` datetime DEFAULT NULL,
|
||||
`closedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`closedDate` datetime DEFAULT NULL,
|
||||
`duplicateBug` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`linkBug` varchar(255) NOT NULL DEFAULT '',
|
||||
`case` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`caseVersion` smallint NOT NULL DEFAULT '1',
|
||||
`feedback` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`result` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`repo` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`mr` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`entry` text,
|
||||
`lines` varchar(10) NOT NULL DEFAULT '',
|
||||
`v1` varchar(40) NOT NULL DEFAULT '',
|
||||
`v2` varchar(40) NOT NULL DEFAULT '',
|
||||
`repoType` varchar(30) NOT NULL DEFAULT '',
|
||||
`issueKey` varchar(50) NOT NULL DEFAULT '',
|
||||
`testtask` mediumint unsigned NOT NULL DEFAULT '0',
|
||||
`lastEditedBy` varchar(30) NOT NULL DEFAULT '',
|
||||
`lastEditedDate` datetime DEFAULT NULL,
|
||||
`deleted` enum('0','1') NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `product` (`product`),
|
||||
KEY `execution` (`execution`),
|
||||
KEY `status` (`status`),
|
||||
KEY `plan` (`plan`),
|
||||
KEY `story` (`story`),
|
||||
KEY `case` (`case`),
|
||||
KEY `toStory` (`toStory`),
|
||||
KEY `result` (`result`),
|
||||
KEY `assignedTo` (`assignedTo`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `zt_bug`
|
||||
--
|
||||
|
||||
LOCK TABLES `zt_bug` WRITE;
|
||||
/*!40000 ALTER TABLE `zt_bug` DISABLE KEYS */;
|
||||
/*!40000 ALTER TABLE `zt_bug` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2023-05-08 10:24:51
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
INSERT INTO zt_bug(`id`, `project`, `product`, `branch`, `module`, `execution`, `plan`, `story`, `storyVersion`, `task`, `toTask`, `toStory`, `title`, `keywords`, `severity`, `pri`, `type`, `os`, `browser`, `hardware`, `found`, `steps`, `status`, `subStatus`, `color`, `confirmed`, `activatedCount`, `mailto`, `openedBy`, `openedDate`, `openedBuild`, `assignedTo`, `assignedDate`, `deadline`, `resolvedBy`, `resolution`, `resolvedBuild`, `resolvedDate`, `closedBy`, `closedDate`, `duplicateBug`, `linkBug`, `case`, `caseVersion`, `result`, `repo`, `entry`, `lines`, `v1`, `v2`, `repoType`, `testtask`, `lastEditedBy`, `lastEditedDate`, `deleted`)
|
||||
VALUES ('1', '0', '1', '0', '1821', '0', '1', '2', '1', '0', '0', '0', 'BUG1', '', '3', '3', 'codeerror', '', '', '', '', '<p>【步骤】</p><br/><p>【结果】</p><br/><p>【期望】</p><br/>', 'active', '', '#3da7f5', '0', '0', 'admin', 'admin', '2023-04-08 10:24:51', '1', 'admin', '2023-04-08', '2023-04-08', '', '', '', '2023-05-15', '', '', '0', '', '0', '0', '0', '0', '', '', '', '', '', '0', '', '', '0'),
|
||||
('2', '1', '2', '1', '1822', '1', '1', '6', '1', '0', '0', '0', 'BUG2', '', '3', '3', 'codeerror', '', '', '', '', '【步骤】进入成果展示<br/>【结果】乱码<br/>【期望】正常显示<br/>', 'active', '', '#75c941', '1', '0', 'admin', 'admin', '2023-04-09 10:24:51', '2', 'admin', '2023-04-09', '2023-04-09', '', '', '', '2023-05-14', '', '', '0', '', '0', '0', '0', '0', '', '', '', '', '', '0', '', '', '0'),
|
||||
('3', '2', '3', '0', '1823', '2', '1', '10', '1', '0', '0', '0', 'BUG3', '', '3', '3', 'codeerror', 'win10', '', '', '', '<p>【步骤】</p><br/><p>【结果】</p><br/><p>【期望】</p><br/>', 'active', '', '#2dbdb2', '0', '0', 'admin', 'admin', '2023-04-10 10:24:51', '3', 'admin', '2023-04-10', '2023-04-10', '', '', '', '2023-05-13', '', '', '0', '', '0', '0', '0', '0', '', '', '', '', '', '0', '', '', '0'),
|
||||
('4', '3', '4', '1', '1825', '3', '4', '14', '1', '0', '0', '0', 'BUG4', '', '3', '3', 'codeerror', 'windows', '', '', '', '【步骤】进入成果展示<br/>【结果】乱码<br/>【期望】正常显示<br/>', 'active', '', '#797ec9', '1', '0', 'admin', 'admin', '2023-04-11 10:24:51', '4', 'admin', '2023-04-11', '2023-04-11', '', '', '', '2023-05-12', '', '', '0', '', '0', '0', '0', '0', '', '', '', '', '', '0', '', '', '0'),
|
||||
('5', '4', '5', '0', '1826', '4', '4', '18', '1', '0', '0', '0', 'BUG5', '', '3', '3', 'codeerror', 'android', '', '', '', '<p>【步骤】</p><br/><p>【结果】</p><br/><p>【期望】</p><br/>', 'active', '', '#ffaf38', '0', '0', 'admin', 'admin', '2023-04-12 10:24:51', '5', 'admin', '2023-04-12', '2023-04-12', '', '', '', '2023-05-11', '', '', '0', '', '0', '0', '0', '0', '', '', '', '', '', '0', '', '', '0');
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/bug.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$data = zdTable('bug');
|
||||
$data->id->range('1-5');
|
||||
$data->product->range('1-5');
|
||||
$data->branch->range('0-1');
|
||||
$data->project->range('0-5');
|
||||
$data->execution->range('0-5');
|
||||
$data->title->prefix("BUG")->range('1-5');
|
||||
$data->openedBuild->range('1-5');
|
||||
$data->type->range("[codeerror]");
|
||||
$data->status->range("[active]");
|
||||
$data->pri->range("[3]");
|
||||
$data->severity->range("[3]");
|
||||
|
||||
$data->gen(5);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=bugModel->updateLinkBug();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 测试关联bug2的关联bug同步更新为1属性2 @1
|
||||
|
||||
- 测试关联bug2的关联bug同步更新为空,bug3的关联bug为1
|
||||
- 属性2 @~~
|
||||
- 属性3 @1
|
||||
|
||||
- 测试关联bug2的关联bug同步更新为1属性2 @1
|
||||
|
||||
- 测试关联bug3的关联bug同步更新为1,2属性3 @1,2
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
initData();
|
||||
|
||||
$bugIDList = array(1, 2, 3);
|
||||
|
||||
$bug = new bugTest();
|
||||
r($bug->updateLinkBugTest($bugIDList[0], '2', '')) && p('2', ';') && e('1'); //测试关联bug2的关联bug同步更新为1
|
||||
r($bug->updateLinkBugTest($bugIDList[0], '3', '2')) && p('2;3', ';') && e('~~;1'); //测试关联bug2的关联bug同步更新为空,bug3的关联bug为1
|
||||
r($bug->updateLinkBugTest($bugIDList[0], '2,3', '3')) && p('2') && e('1'); //测试关联bug2的关联bug同步更新为1
|
||||
r($bug->updateLinkBugTest($bugIDList[1], '1,3', '1')) && p('3', ';') && e('1,2'); //测试关联bug3的关联bug同步更新为1,2
|
||||
+4
-2
@@ -829,9 +829,11 @@ class bugZen extends bug
|
||||
|
||||
/* 获取影响版本列表和解决版本列表。*/
|
||||
/* Get the openedBuilds and resolvedBuilds. */
|
||||
$objectType = '';
|
||||
if($bug->project) $objectType = 'project';
|
||||
if($bug->execution) $objectType = 'execution';
|
||||
|
||||
$objectID = $bug->execution ? $bug->execution : $bug->project;
|
||||
$objectType = $bug->project ? 'project' : '';
|
||||
$objectType = $bug->execution ? 'execution' : $objectType;
|
||||
$allBuilds = $this->loadModel('build')->getBuildPairs($bug->product, 'all', 'noempty');
|
||||
$openedBuilds = $this->build->getBuildPairs($bug->product, $bug->branch, $params = 'noempty,noterminate,nodone,withbranch,noreleased', $objectID, $objectType, $bug->openedBuild);
|
||||
$resolvedBuilds = $openedBuilds;
|
||||
|
||||
@@ -380,7 +380,7 @@ class doc extends control
|
||||
$libID = $this->post->lib;
|
||||
$moduleID = $this->post->module;
|
||||
if(empty($libID) and strpos($this->post->module, '_') !== false) list($libID, $moduleID) = explode('_', $this->post->module);
|
||||
setcookie('lastDocModule', $moduleID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, false);
|
||||
setcookie('lastDocModule', $moduleID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
$docResult = $this->doc->create();
|
||||
if(!$docResult or dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
@@ -1043,7 +1043,7 @@ class doc extends control
|
||||
{
|
||||
$this->loadModel('file');
|
||||
if(empty($viewType)) $viewType = !empty($_COOKIE['docFilesViewType']) ? $this->cookie->docFilesViewType : 'list';
|
||||
setcookie('docFilesViewType', $viewType, $this->config->cookieLife, $this->config->webRoot, '', false, true);
|
||||
setcookie('docFilesViewType', $viewType, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
$objects = $this->doc->getOrderedObjects($type, 'nomerge', $objectID);
|
||||
list($libs, $libID, $object, $objectID, $objectDropdown) = $this->doc->setMenuByType($type, $objectID, 0);
|
||||
@@ -1271,7 +1271,7 @@ class doc extends control
|
||||
$docSpaceParam->moduleID = $moduleID;
|
||||
$docSpaceParam->browseType = $browseType;
|
||||
$docSpaceParam->param = $param;
|
||||
setCookie("docSpaceParam", json_encode($docSpaceParam), $this->config->cookieLife, $this->config->webRoot, '', false, true);
|
||||
setCookie("docSpaceParam", json_encode($docSpaceParam), $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
|
||||
if($moduleID) $libID = $this->tree->getById($moduleID)->root;
|
||||
$isFirstLoad = $libID == 0 ? true : false;
|
||||
|
||||
@@ -255,7 +255,7 @@ class docModel extends model
|
||||
->remove('uid,contactListMenu,libType')
|
||||
->get();
|
||||
|
||||
if(defined('IN_UPGRADE') and (($this->config->edition == 'open' and version_compare($this->config->version, '18.4.alpha1', '<')) or ($this->config->edition == 'biz' and version_compare($this->config->version, 'biz8.4.alpha1', '<')) or ($this->config->edition == 'max' and version_compare($this->config->version, 'max4.4.alpha1', '<')))) unset($lib->addedBy, $lib->addedDate);
|
||||
if(defined('IN_UPGRADE') and (($this->config->edition == 'open' and version_compare($this->config->version, '18.4.alpha1', '<')) or ($this->config->edition == 'biz' and version_compare($this->config->version, 'biz8.4.alpha1', '<')) or ($this->config->edition == 'max' and version_compare($this->config->version, 'max4.4.alpha1', '<')))) unset($data->addedBy, $data->addedDate);
|
||||
|
||||
$this->app->loadLang('api');
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ if($config->systemMode == 'ALM') $config->product->custom->batchEditFields .= ',
|
||||
$config->product->list = new stdclass();
|
||||
$config->product->list->exportFields = 'id,program,line,name,manager,draftStories,activeStories,changedStories,reviewingStories,closedStories,storyCompleteRate,bugs,unResolvedBugs,assignToNullBugs,bugFixedRate,plans,releases';
|
||||
|
||||
$config->product->showBranchMethod = 'browse,project';
|
||||
$config->product->showBranchMethod = ',browse,project,track,';
|
||||
|
||||
global $lang, $app;
|
||||
$app->loadLang('story');
|
||||
|
||||
+11
-11
@@ -43,29 +43,28 @@ class product extends control
|
||||
/**
|
||||
* Index page, to browse.
|
||||
*
|
||||
* @param string $locate locate to browse page or not. If not, display all products.
|
||||
* @param int $productID
|
||||
* @param string $orderBy
|
||||
* @param int $recTotal
|
||||
* @param int $recPerPage
|
||||
* @param int $pageID
|
||||
* @param string $locate auto|yes locate to browse page or not. If not, display all products.
|
||||
* @param string $productID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function index($locate = 'auto', $productID = 0, $status = 'noclosed', $orderBy = 'order_desc', $recTotal = 0, $recPerPage = 10, $pageID = 1)
|
||||
public function index(string $locate = 'auto', string $productID = '0')
|
||||
{
|
||||
if($locate == 'yes') $this->locate($this->createLink($this->moduleName, 'browse'));
|
||||
|
||||
if($this->app->getViewType() != 'mhtml') unset($this->lang->product->menu->index);
|
||||
/* Check product id and get product branch. */
|
||||
$productID = (int)$productID;
|
||||
$productID = $this->product->saveVisitState($productID, $this->products);
|
||||
$branch = (int)$this->cookie->preBranch;
|
||||
|
||||
/* Set Menu. */
|
||||
if($this->app->getViewType() != 'mhtml') unset($this->lang->product->menu->index);
|
||||
if($this->app->viewType == 'mhtml') $this->product->setMenu($productID, $branch);
|
||||
|
||||
/* Add create product button for view. */
|
||||
if(common::hasPriv('product', 'create')) $this->lang->TRActions = html::a($this->createLink('product', 'create'), "<i class='icon icon-sm icon-plus'></i> " . $this->lang->product->create, '', "class='btn btn-primary'");
|
||||
|
||||
$this->view->title = $this->lang->product->index;
|
||||
$this->view->position[] = $this->lang->product->index;
|
||||
$this->view->title = $this->lang->product->index;
|
||||
$this->display();
|
||||
}
|
||||
|
||||
@@ -296,6 +295,7 @@ class product extends control
|
||||
|
||||
if($this->post->name)
|
||||
{
|
||||
/* 从POST中获取数据,并预处理数据。 */
|
||||
$formConfig = $this->productZen->appendFlowFields($this->config->product->form->batchEdit, 'batch');
|
||||
$data = form::data($formConfig);
|
||||
$products = $this->productZen->prepareBatchEditExtras($data);
|
||||
@@ -647,7 +647,7 @@ class product extends control
|
||||
$programID = (int)$programID;
|
||||
|
||||
/* Set env data. */
|
||||
$this->productZen->setEnvAll();
|
||||
$this->productZen->setMenu4All();
|
||||
|
||||
/* Generate statistics of products and program. */
|
||||
$this->app->loadClass('pager', true);
|
||||
|
||||
+57
-288
@@ -26,150 +26,28 @@ class productModel extends model
|
||||
const STORY_TYPE_REQ = 'requirement';
|
||||
|
||||
/**
|
||||
* Get product module menu.
|
||||
* 获取移动端1.5级导航。
|
||||
* Get product drop menu in mobile.
|
||||
*
|
||||
* @param array $products
|
||||
* @param int $productID
|
||||
* @param string $extra
|
||||
* @param string $branch
|
||||
* @param string $module
|
||||
* @param string $moduleType
|
||||
* @param array $products
|
||||
* @param int $productID
|
||||
* @param string $extra
|
||||
* @param string|int $branch
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getModuleNav($products, $productID, $extra, $branch, $module = 0, $moduleType = '')
|
||||
public function getMobileDropMenu(array $products, int $productID, string $extra = '', string|int $branch = ''): string
|
||||
{
|
||||
$currentModule = $this->app->getModuleName();
|
||||
$currentMethod = $this->app->getMethodName();
|
||||
list($locateModule, $locateMethod) = $this->productTao->computeLocate4DropMenu();
|
||||
|
||||
/* init currentModule and currentMethod for report and story. */
|
||||
if($currentModule == 'story')
|
||||
{
|
||||
$storyMethods = ",track,create,batchcreate,batchclose,";
|
||||
if(strpos($storyMethods, "," . $currentMethod . ",") === false) $currentModule = 'product';
|
||||
if($currentMethod == 'view' || $currentMethod == 'change' || $currentMethod == 'review') $currentMethod = 'browse';
|
||||
}
|
||||
if($currentMethod == 'report') $currentMethod = 'browse';
|
||||
|
||||
$selectHtml = $this->select($products, $productID, $currentModule, $currentMethod, $extra, $branch, $module, $moduleType);
|
||||
|
||||
$pageNav = '';
|
||||
$isMobile = $this->app->viewType == 'mhtml';
|
||||
if($isMobile)
|
||||
{
|
||||
$pageNav = html::a(helper::createLink('product', 'index'), $this->lang->product->index) . $this->lang->colon;
|
||||
$pageNav .= $selectHtml;
|
||||
}
|
||||
else
|
||||
{
|
||||
$pageNav = $selectHtml;
|
||||
}
|
||||
$selectHtml = $this->productTao->buildSelect4Mobile($products, $productID, $locateModule, $locateMethod, $extra, $branch);
|
||||
$pageNav = html::a(helper::createLink('product', 'index'), $this->lang->product->index) . $this->lang->colon;
|
||||
$pageNav .= $selectHtml;
|
||||
|
||||
return $pageNav;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the select code of products.
|
||||
*
|
||||
* @param array $products
|
||||
* @param int $productID
|
||||
* @param string $currentModule
|
||||
* @param string $currentMethod
|
||||
* @param string $extra
|
||||
* @param int|string $branch
|
||||
* @param int $module
|
||||
* @param string $moduleType
|
||||
* @param bool $withBranch true|false
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function select($products, $productID, $currentModule, $currentMethod, $extra = '', $branch = '', $module = 0, $moduleType = '', $withBranch = true)
|
||||
{
|
||||
$isQaModule = (strpos(',project,execution,', ",{$this->app->tab},") !== false and strpos(',bug,testcase,testtask,ajaxselectstory,', ",{$this->app->rawMethod},") !== false and isset($products[0])) ? true : false;
|
||||
$isFeedbackModel = strpos(',feedback,', ",{$this->app->tab},") !== false ? true : false;
|
||||
if(count($products) <= 2 and isset($products[0]))
|
||||
{
|
||||
unset($products[0]);
|
||||
$productID = key($products);
|
||||
}
|
||||
|
||||
if(empty($products)) return;
|
||||
|
||||
if($this->app->tab == 'project' and strpos(',zeroCase,browseUnits,groupCase,', ",$currentMethod,") !== false) $isQaModule = true;
|
||||
|
||||
$this->app->loadLang('product');
|
||||
if(!$isQaModule and !$productID and !$isFeedbackModel)
|
||||
{
|
||||
unset($this->lang->product->menu->settings['subMenu']->branch);
|
||||
return;
|
||||
}
|
||||
$isMobile = $this->app->viewType == 'mhtml';
|
||||
|
||||
$productID = $productID == 'all' ? 0 : $productID;
|
||||
setcookie("lastProduct", $productID, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
if($productID) $currentProduct = $this->getById($productID);
|
||||
|
||||
if($isQaModule and $this->app->tab == 'project')
|
||||
{
|
||||
if($this->app->tab == 'project') $extra = strpos(',testcase,groupCase,zeroCase,', ",$currentMethod,") !== false ? $extra : $this->session->project;
|
||||
if($this->app->tab == 'execution') $extra = $this->session->execution;
|
||||
}
|
||||
|
||||
if($isQaModule and !$productID)
|
||||
{
|
||||
$currentProduct = new stdclass();
|
||||
$currentProduct->name = $products[$productID];
|
||||
$currentProduct->type = 'normal';
|
||||
}
|
||||
if($isFeedbackModel and !$productID)
|
||||
{
|
||||
$currentProduct = new stdclass();
|
||||
$currentProduct->name = isset($products[$productID]) ? $products[$productID] : current($products);
|
||||
$currentProduct->type = 'normal';
|
||||
}
|
||||
$this->session->set('currentProductType', $currentProduct->type);
|
||||
|
||||
$output = '';
|
||||
if(!empty($products))
|
||||
{
|
||||
$moduleName = 'product';
|
||||
if($isQaModule) $moduleName = 'bug';
|
||||
if($isFeedbackModel) $moduleName = 'feedback';
|
||||
$dropMenuLink = helper::createLink($moduleName, 'ajaxGetDropMenu', "objectID=$productID&module=$currentModule&method=$currentMethod&extra=$extra");
|
||||
$output = "<div class='btn-group angle-btn'><div class='btn-group'><button data-toggle='dropdown' type='button' class='btn btn-limit' id='currentItem' title='{$currentProduct->name}' style='width: 90%'><span class='text'>{$currentProduct->name}</span> <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
|
||||
$output .= "</div></div>";
|
||||
if($isMobile) $output = "<a id='currentItem' href=\"javascript:showSearchMenu('product', '$productID', '$currentModule', '$currentMethod', '$extra')\"><span class='text'>{$currentProduct->name}</span> <span class='icon-caret-down'></span></a><div id='currentItemDropMenu' class='hidden affix enter-from-bottom layer'></div>";
|
||||
|
||||
if($currentProduct->type == 'normal' || !$withBranch) unset($this->lang->product->menu->settings['subMenu']->branch);
|
||||
if($currentProduct->type != 'normal' && $currentModule != 'programplan' && $withBranch)
|
||||
{
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$currentProduct->type]);
|
||||
$this->lang->product->menu->settings['subMenu']->branch = str_replace('@branch@', $this->lang->product->branch, $this->lang->product->menu->settings['subMenu']->branch);
|
||||
|
||||
$branches = $this->loadModel('branch')->getPairs($productID, 'all');
|
||||
$branchName = $branches[$branch];
|
||||
if(!$isMobile)
|
||||
{
|
||||
$dropMenuLink = helper::createLink('branch', 'ajaxGetDropMenu', "objectID=$productID&branch=$branch&module=$currentModule&method=$currentMethod&extra=$extra");
|
||||
$output .= "<div class='btn-group'><button id='currentBranch' data-toggle='dropdown' type='button' class='btn btn-limit' title='{$branchName}' style='width: 90%'>{$branchName} <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
|
||||
$output .= "</div></div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$output .= "<a id='currentBranch' href=\"javascript:showSearchMenu('branch', '$productID', '$currentModule', '$currentMethod', '$extra')\">{$branchName} <span class='icon-caret-down'></span></a><div id='currentBranchDropMenu' class='hidden affix enter-from-bottom layer'></div>";
|
||||
}
|
||||
}
|
||||
|
||||
if(!$isMobile) $output .= '</div>';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check privilege.
|
||||
*
|
||||
@@ -177,7 +55,7 @@ class productModel extends model
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPriv($productID)
|
||||
public function checkPriv(int $productID): bool
|
||||
{
|
||||
if(empty($productID)) return false;
|
||||
|
||||
@@ -525,30 +403,19 @@ class productModel extends model
|
||||
}
|
||||
|
||||
/*
|
||||
* 获取1.5级导航数据。
|
||||
* Get product switcher.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param string $extra
|
||||
* @param int|string $branch
|
||||
* @param string|int $branch
|
||||
* @access public
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function getSwitcher($productID = 0, $extra = '', $branch = '')
|
||||
public function getSwitcher(int $productID = 0, string $extra = '', string|int $branch = ''): string
|
||||
{
|
||||
$currentModule = $this->app->moduleName;
|
||||
$currentMethod = $this->app->methodName;
|
||||
|
||||
/* Init currentModule and currentMethod for report and story. */
|
||||
if($currentModule == 'story')
|
||||
{
|
||||
$storyMethods = ",create,batchcreate,batchclose,";
|
||||
if(strpos($storyMethods, "," . $currentMethod . ",") === false) $currentModule = 'product';
|
||||
if($currentMethod == 'view' or $currentMethod == 'change' or $currentMethod == 'review') $currentMethod = 'browse';
|
||||
}
|
||||
if($currentModule == 'testcase' and strpos(',view,edit,', ",$currentMethod,") !== false) $currentMethod = 'browse';
|
||||
if($currentModule == 'bug' and $currentMethod == 'edit') $currentMethod = 'browse';
|
||||
if($currentMethod == 'report') $currentMethod = 'browse';
|
||||
|
||||
/* 获取产品名称,产品类型。 */
|
||||
$currentProduct = new stdclass();
|
||||
$currentProductName = $this->lang->productCommon;
|
||||
if($productID)
|
||||
{
|
||||
@@ -557,38 +424,21 @@ class productModel extends model
|
||||
$this->session->set('currentProductType', $currentProduct->type);
|
||||
}
|
||||
|
||||
$fromModule = $this->app->tab == 'qa' ? 'qa' : '';
|
||||
$dropMenuLink = helper::createLink($this->app->tab == 'qa' ? 'product' : $this->app->tab, 'ajaxGetDropMenu', "objectID=$productID&module=$currentModule&method=$currentMethod&extra=$extra&from=$fromModule");
|
||||
if($this->app->viewType == 'mhtml') return $this->getMobileDropMenu(array($productID => $currentProductName), $productID, $extra, $branch);
|
||||
|
||||
if($this->app->viewType == 'mhtml' and $productID) return $this->getModuleNav(array($productID => $currentProductName), $productID, $extra, $branch);
|
||||
/* Init locateModule and locateMethod for report and story. */
|
||||
list($locateModule, $locateMethod) = $this->productTao->computeLocate4DropMenu();
|
||||
|
||||
/* 生成异步获取产品下拉菜单的链接。*/
|
||||
$fromModule = $this->app->tab == 'qa' ? 'qa' : '';
|
||||
$dropMenuModule = $this->app->tab == 'qa' ? 'product' : $this->app->tab;
|
||||
$dropMenuLink = helper::createLink($dropMenuModule, 'ajaxGetDropMenu', "objectID=$productID&module=$locateModule&method=$locateMethod&extra=$extra&from=$fromModule");
|
||||
|
||||
/* 构建产品1.5级导航数据。 */
|
||||
$output = "<div class='btn-group header-btn' id='swapper'><button data-toggle='dropdown' type='button' class='btn' id='currentItem' title='{$currentProductName}'><span class='text'>{$currentProductName}</span> <span class='caret' style='margin-bottom: -1px'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
|
||||
$output .= "</div></div>";
|
||||
|
||||
$notNormalProduct = (isset($currentProduct->type) and $currentProduct->type != 'normal');
|
||||
if($notNormalProduct)
|
||||
{
|
||||
$isShowBranch = false;
|
||||
if($currentModule == 'product' and $currentMethod == 'track') $isShowBranch = true;
|
||||
if($currentModule == 'tree' and $currentMethod == 'browse') $isShowBranch = true;
|
||||
if($currentModule == 'product' and strpos($this->config->product->showBranchMethod, $currentMethod) !== false) $isShowBranch = true;
|
||||
if($this->app->tab == 'qa' and strpos(',testsuite,testreport,testtask,', ",$currentModule,") === false) $isShowBranch = true;
|
||||
if($this->app->tab == 'qa' and $currentModule == 'testtask' and strpos(',create,edit,browseunits,importunitresult,unitcases,', ",$currentMethod,") === false) $isShowBranch = true;
|
||||
if($currentModule == 'testcase' and $currentMethod == 'showimport') $isShowBranch = false;
|
||||
if($currentModule == 'release' and strpos(',browse,create,', $currentMethod) !== false) $isShowBranch = true;
|
||||
if($isShowBranch)
|
||||
{
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$currentProduct->type]);
|
||||
$branches = $this->loadModel('branch')->getPairs($productID, 'all');
|
||||
$branchName = isset($branches[$branch]) ? $branches[$branch] : $branches[0];
|
||||
$dropMenuLink = helper::createLink('branch', 'ajaxGetDropMenu', "objectID=$productID&branch=$branch&module=$currentModule&method=$currentMethod&extra=$extra");
|
||||
|
||||
$output .= "<div class='btn-group header-btn'><button id='currentBranch' data-toggle='dropdown' type='button' class='btn'><span class='text'>{$branchName}</span> <span class='caret' style='margin-bottom: -1px'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
|
||||
$output .= "</div></div>";
|
||||
}
|
||||
}
|
||||
$output .= $this->productTao->getBranchSelect4PC($currentProduct, $branch, $locateModule, $locateMethod, $extra);
|
||||
|
||||
return $output;
|
||||
}
|
||||
@@ -1272,7 +1122,7 @@ class productModel extends model
|
||||
|
||||
/**
|
||||
* 获取产品路线图数据。
|
||||
* Get roadmap of a proejct.
|
||||
* Get roadmap of product.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param string $branch all|0|1
|
||||
@@ -1282,85 +1132,8 @@ class productModel extends model
|
||||
*/
|
||||
public function getRoadmap(int $productID, string $branch = '0', int $count = 0): array
|
||||
{
|
||||
$plans = $this->loadModel('productplan')->getList($productID, $branch);
|
||||
$releases = $this->loadModel('release')->getList($productID, $branch);
|
||||
$roadmap = array();
|
||||
$total = 0;
|
||||
|
||||
$parents = array();
|
||||
$orderedPlans = array();
|
||||
foreach($plans as $planID => $plan)
|
||||
{
|
||||
if($plan->parent == '-1')
|
||||
{
|
||||
$parents[$planID] = $plan->title;
|
||||
unset($plans[$planID]);
|
||||
continue;
|
||||
}
|
||||
if((!helper::isZeroDate($plan->end) and $plan->end < date('Y-m-d')) or $plan->end == '2030-01-01') continue;
|
||||
$orderedPlans[$plan->end][] = $plan;
|
||||
}
|
||||
|
||||
krsort($orderedPlans);
|
||||
foreach($orderedPlans as $plans)
|
||||
{
|
||||
krsort($plans);
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
if($plan->parent > 0 and isset($parents[$plan->parent])) $plan->title = $parents[$plan->parent] . ' / ' . $plan->title;
|
||||
|
||||
$year = substr($plan->end, 0, 4);
|
||||
$branchIdList = explode(',', trim($plan->branch, ','));
|
||||
$branchIdList = array_unique($branchIdList);
|
||||
foreach($branchIdList as $branchID)
|
||||
{
|
||||
if($branchID === '') continue;
|
||||
$roadmap[$year][$branchID][] = $plan;
|
||||
}
|
||||
$total++;
|
||||
|
||||
if($count > 0 and $total >= $count) return $this->processRoadmap($roadmap, $branch);
|
||||
}
|
||||
}
|
||||
|
||||
$orderedReleases = array();
|
||||
foreach($releases as $release) $orderedReleases[$release->date][] = $release;
|
||||
|
||||
krsort($orderedReleases);
|
||||
foreach($orderedReleases as $releases)
|
||||
{
|
||||
krsort($releases);
|
||||
foreach($releases as $release)
|
||||
{
|
||||
$year = substr($release->date, 0, 4);
|
||||
$branchIdList = explode(',', trim($release->branch, ','));
|
||||
$branchIdList = array_unique($branchIdList);
|
||||
foreach($branchIdList as $branchID)
|
||||
{
|
||||
if($branchID === '') continue;
|
||||
$roadmap[$year][$branchID][] = $release;
|
||||
}
|
||||
$total++;
|
||||
|
||||
if($count > 0 and $total >= $count) return $this->processRoadmap($roadmap, $branch);
|
||||
}
|
||||
}
|
||||
|
||||
if($count > 0) return $this->processRoadmap($roadmap, $branch);
|
||||
|
||||
$groupRoadmap = array();
|
||||
foreach($roadmap as $year => $branchRoadmaps)
|
||||
{
|
||||
foreach($branchRoadmaps as $branch => $roadmaps)
|
||||
{
|
||||
$totalData = count($roadmaps);
|
||||
$rows = ceil($totalData / 8);
|
||||
$maxPerRow = ceil($totalData / $rows);
|
||||
|
||||
$groupRoadmap[$year][$branch] = array_chunk($roadmaps, $maxPerRow);
|
||||
foreach($groupRoadmap[$year][$branch] as $row => $rowRoadmaps) krsort($groupRoadmap[$year][$branch][$row]);
|
||||
}
|
||||
}
|
||||
/* Get group roadmap data. */
|
||||
$groupRoadmap = $this->productTao->getGroupRoadmapData($productID, $branch, $count);
|
||||
|
||||
/* Get last 5 roadmap. */
|
||||
$lastKeys = array_slice(array_keys($groupRoadmap), 0, 5);
|
||||
@@ -1391,7 +1164,7 @@ class productModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function processRoadmap($roadmapGroups, $branch)
|
||||
public function processRoadmap($roadmapGroups, $branch): array
|
||||
{
|
||||
$newRoadmap = array();
|
||||
foreach($roadmapGroups as $year => $branchRoadmaps)
|
||||
@@ -2243,19 +2016,18 @@ class productModel extends model
|
||||
if(empty($this->session->product)) $productID = (int)key($products);
|
||||
}
|
||||
|
||||
if(isset($products[$productID])) return $productID;
|
||||
|
||||
/* 产品ID已经被删除,不存在于产品列表中。*/
|
||||
/* Product ID does not exsit in products list, it may be deleted. */
|
||||
if(!isset($products[$productID]))
|
||||
/* Confirm if product exist. */
|
||||
$product = $this->product->getById($productID);
|
||||
if(empty($product) or $product->deleted == 1) $productID = (int)key($products);
|
||||
/* If product is invisable for curren user, then response access denied message. */
|
||||
if($productID && !$this->checkPriv($productID))
|
||||
{
|
||||
/* Confirm if product exist. */
|
||||
$product = $this->product->getById($productID);
|
||||
if(empty($product) or $product->deleted == 1) $productID = (int)key($products);
|
||||
/* If product is invisable for curren user, then response access denied message. */
|
||||
if($productID && strpos(",{$this->app->user->view->products},", ",{$productID},") === false)
|
||||
{
|
||||
$productID = (int)key($products);
|
||||
$this->accessDenied($this->lang->product->accessDenied);
|
||||
}
|
||||
$productID = (int)key($products);
|
||||
$this->accessDenied($this->lang->product->accessDenied);
|
||||
}
|
||||
|
||||
return $productID;
|
||||
@@ -2269,7 +2041,7 @@ class productModel extends model
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
public function accessDenied($tips)
|
||||
public function accessDenied(string $tips)
|
||||
{
|
||||
if(defined('TUTORIAL')) return true;
|
||||
|
||||
@@ -2288,40 +2060,37 @@ class productModel extends model
|
||||
* Set menu.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int|string $branch
|
||||
* @param int $module
|
||||
* @param string $moduleType
|
||||
* @param string|int $branch all|''|int
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setMenu($productID = 0, $branch = '', $module = 0, $moduleType = '', $extra = ''): void
|
||||
public function setMenu(int $productID = 0, string|int $branch = '', string $extra = '')
|
||||
{
|
||||
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL'))
|
||||
{
|
||||
$this->accessDenied($this->lang->product->accessDenied);
|
||||
return;
|
||||
}
|
||||
|
||||
$product = $this->getByID($productID);
|
||||
if(!defined('TUTORIAL') and $productID != 0 and !$this->checkPriv($productID)) return $this->accessDenied($this->lang->product->accessDenied);
|
||||
|
||||
/* 用真实数据替换导航配置的占位符,并删除无用配置项。 */
|
||||
$params = array('branch' => $branch);
|
||||
common::setMenuVars('product', $productID, $params);
|
||||
if(strpos($extra, 'requirement') !== false) unset($this->lang->product->moreSelects['willclose']);
|
||||
|
||||
$product = $this->getByID($productID);
|
||||
if(!$product) return;
|
||||
|
||||
/* 设置1.5级导航数据。*/
|
||||
$this->lang->switcherMenu = $this->getSwitcher($productID, $extra, $branch);
|
||||
|
||||
/* 设置导航中分支的显示数据。*/
|
||||
/* 如果产品类型是正常的,隐藏导航中分支的显示。*/
|
||||
if($product->type == 'normal')
|
||||
{
|
||||
unset($this->lang->product->menu->settings['subMenu']->branch);
|
||||
}
|
||||
else
|
||||
{
|
||||
$branchLink = $this->lang->product->menu->settings['subMenu']->branch['link'];
|
||||
$this->lang->product->menu->settings['subMenu']->branch['link'] = str_replace('@branch@', $this->lang->product->branchName[$product->type], $branchLink);
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
return;
|
||||
}
|
||||
|
||||
if(strpos($extra, 'requirement') !== false) unset($this->lang->product->moreSelects['willclose']);
|
||||
/* 如果产品类型是多分支、多平台的,将真实数据替换@branch@匹配符。*/
|
||||
$branchLink = $this->lang->product->menu->settings['subMenu']->branch['link'];
|
||||
$this->lang->product->menu->settings['subMenu']->branch['link'] = str_replace('@branch@', $this->lang->product->branchName[$product->type], $branchLink);
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
}
|
||||
}
|
||||
|
||||
+348
-22
@@ -431,27 +431,6 @@ class productTao extends productModel
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化append参数,保证输出用逗号间隔的id列表。
|
||||
* Format append param.
|
||||
*
|
||||
* @param string|array append
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function formatAppendParam(string|array $append = ''): string
|
||||
{
|
||||
if(empty($append)) return '';
|
||||
|
||||
if(is_string($append)) $append = explode(',', $append);
|
||||
|
||||
$append = array_map(function($item){return (int)$item;}, $append);
|
||||
$append = array_unique(array_filter($append));
|
||||
sort($append);
|
||||
|
||||
return implode(',', $append);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用于数据统计的研发需求和用户需求列表。
|
||||
* Get dev stories and user requirements for statistics.
|
||||
@@ -491,7 +470,121 @@ class productTao extends productModel
|
||||
/* Story type is 'requirement'. */
|
||||
if($storyType == static::STORY_TYPE_REQ) $stories = $requirements;
|
||||
|
||||
return [$stories, $requirements];
|
||||
return array($stories, $requirements);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取PC端分支下拉的HTML
|
||||
* Get branch select for mobile
|
||||
*
|
||||
* @param object $product
|
||||
* @param string|int $branch
|
||||
* @param string $currentModule
|
||||
* @param string $currentMethod
|
||||
* @param string $extra
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
protected function getBranchSelect4PC(object $product, string|int $branch, string $currentModule, string $currentMethod, string $extra = ''): string
|
||||
{
|
||||
if(!isset($product->type) or $product->type == 'normal') return '';
|
||||
|
||||
/* 检测是否要显示分支。 */
|
||||
$showBranch = false;
|
||||
if($currentModule == 'testcase' and $currentMethod == 'showimport') $showBranch = false;
|
||||
if($currentModule == 'tree' and $currentMethod == 'browse') $showBranch = true;
|
||||
if($currentModule == 'product' and strpos($this->config->product->showBranchMethod, ",{$currentMethod},") !== false) $showBranch = true;
|
||||
if($currentModule == 'release' and strpos(',browse,create,', ",{$currentMethod},") !== false) $showBranch = true;
|
||||
if($this->app->tab == 'qa' and strpos(',testsuite,testreport,testtask,', ",$currentModule,") === false) $showBranch = true;
|
||||
if($this->app->tab == 'qa' and $currentModule == 'testtask' and strpos(',create,edit,browseunits,importunitresult,unitcases,', ",$currentMethod,") === false) $showBranch = true;
|
||||
|
||||
if(!$showBranch) return '';
|
||||
|
||||
/* 生成异步请求地址。 */
|
||||
$branches = $this->loadModel('branch')->getPairs($product->id, 'all');
|
||||
$branchName = zget($branches, $branch, reset($branches));
|
||||
$dropMenuLink = helper::createLink('branch', 'ajaxGetDropMenu', "objectID={$product->id}&branch=$branch&module=$currentModule&method=$currentMethod&extra=$extra");
|
||||
|
||||
/* 生成分支HTML代码。*/
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
$output = "<div class='btn-group header-btn'><button id='currentBranch' data-toggle='dropdown' type='button' class='btn'><span class='text'>{$branchName}</span> <span class='caret' style='margin-bottom: -1px'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
|
||||
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
|
||||
$output .= "</div></div>";
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取客户端分支下拉的HTML
|
||||
* Get branch select for mobile
|
||||
*
|
||||
* @param object $product
|
||||
* @param string $currentModule
|
||||
* @param string $currentMethod
|
||||
* @param string $extra
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
protected function getBranchSelect4Mobile(object $product, string|int $branch, string $currentModule, string $currentMethod, string $extra = ''): string
|
||||
{
|
||||
if(!isset($product->type) or $product->type == 'normal') return '';
|
||||
|
||||
/* 修正分支显示语言项。 */
|
||||
$this->lang->product->branch = sprintf($this->lang->product->branch, $this->lang->product->branchName[$product->type]);
|
||||
$this->lang->product->menu->settings['subMenu']->branch['link'] = str_replace('@branch@', $this->lang->product->branch, $this->lang->product->menu->settings['subMenu']->branch['link']);
|
||||
|
||||
/* 生成分支HTML代码。*/
|
||||
$output = '';
|
||||
$branches = $this->loadModel('branch')->getPairs($product->id, 'all');
|
||||
$branchName = zget($branches, $branch, reset($branches));
|
||||
if($branchName) $output .= "<a id='currentBranch' href=\"javascript:showSearchMenu('branch', '{$product->id}', '$currentModule', '$currentMethod', '$extra')\">{$branchName} <span class='icon-caret-down'></span></a><div id='currentBranchDropMenu' class='hidden affix enter-from-bottom layer'></div>";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算在点击1.5级导航下拉选项后,跳转的模块名和方法名。
|
||||
* Compute locate for drop menu in PC.
|
||||
*
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function computeLocate4DropMenu(): array
|
||||
{
|
||||
$currentModule = (string)$this->app->moduleName;
|
||||
$currentMethod = (string)$this->app->methodName;
|
||||
|
||||
/* Init currentModule and currentMethod for report and story. */
|
||||
if($currentModule == 'story')
|
||||
{
|
||||
if(strpos(",track,create,batchcreate,batchclose,", ",{$currentMethod},") === false) $currentModule = 'product';
|
||||
if($currentMethod == 'view' or $currentMethod == 'change' or $currentMethod == 'review') $currentMethod = 'browse';
|
||||
}
|
||||
if($currentModule == 'testcase' and strpos(',view,edit,', ",$currentMethod,") !== false) $currentMethod = 'browse';
|
||||
if($currentModule == 'bug' and $currentMethod == 'edit') $currentMethod = 'browse';
|
||||
if($currentMethod == 'report') $currentMethod = 'browse';
|
||||
|
||||
return array($currentModule, $currentMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化append参数,保证输出用逗号间隔的id列表。
|
||||
* Format append param.
|
||||
*
|
||||
* @param string|array append
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function formatAppendParam(string|array $append = ''): string
|
||||
{
|
||||
if(empty($append)) return '';
|
||||
|
||||
if(is_string($append)) $append = explode(',', $append);
|
||||
|
||||
$append = array_map(function($item){return (int)$item;}, $append);
|
||||
$append = array_unique(array_filter($append));
|
||||
sort($append);
|
||||
|
||||
return implode(',', $append);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -629,4 +722,237 @@ class productTao extends productModel
|
||||
->orderBy($orderBy . 't2.order asc')
|
||||
->fetchAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建移动端的下拉HTML。
|
||||
* Create the select code of products.
|
||||
*
|
||||
* @param array $products
|
||||
* @param int $productID
|
||||
* @param string $currentModule
|
||||
* @param string $currentMethod
|
||||
* @param string $extra
|
||||
* @param int|string $branch
|
||||
* @param bool $withBranch true|false
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function buildSelect4Mobile(array $products, int $productID, string $currentModule, string $currentMethod, string $extra = '', string|int $branch = '', bool $withBranch = true): string
|
||||
{
|
||||
/* 处理数据。*/
|
||||
if(isset($products[0])) unset($products[0]);
|
||||
if(empty($products)) return '';
|
||||
if(!isset($products[$productID])) $productID = (int)key($products);
|
||||
|
||||
/* 检测当前页面是否在项目或执行的测试二级导航中。*/
|
||||
$isQaModule = (strpos(',project,execution,', ",{$this->app->tab},") !== false and stripos(',bug,testcase,testtask,ajaxselectstory,', ",{$this->app->rawMethod},") !== false) ? true : false;
|
||||
if($this->app->tab == 'project' and stripos(',zeroCase,browseUnits,groupCase,', ",$currentMethod,") !== false) $isQaModule = true;
|
||||
if($isQaModule)
|
||||
{
|
||||
if($this->app->tab == 'project') $extra = strpos(',testcase,groupCase,zeroCase,', ",$currentMethod,") !== false ? $extra : $this->session->project;
|
||||
if($this->app->tab == 'execution') $extra = $this->session->execution;
|
||||
}
|
||||
|
||||
/* 查询产品数据。*/
|
||||
$currentProduct = $this->getById($productID);
|
||||
$this->session->set('currentProductType', $currentProduct->type);
|
||||
|
||||
/* 生成异步获取下拉菜单的链接。*/
|
||||
$moduleName = $isQaModule ? 'bug' : 'product';
|
||||
if($this->app->tab == 'feedback') $moduleName = 'feedback';
|
||||
$dropMenuLink = helper::createLink($moduleName, 'ajaxGetDropMenu', "objectID=$productID&module=$currentModule&method=$currentMethod&extra=$extra");
|
||||
|
||||
/* 构建产品1.5级导航代码。 */
|
||||
$output = "<a id='currentItem' href=\"javascript:showSearchMenu('product', '$productID', '$currentModule', '$currentMethod', '$extra')\"><span class='text'>{$currentProduct->name}</span> <span class='icon-caret-down'></span></a><div id='currentItemDropMenu' class='hidden affix enter-from-bottom layer'></div>";
|
||||
|
||||
/* 处理分支。根据条件,判断是否追加分支1.5级导航代码。*/
|
||||
if($currentProduct->type == 'normal' || !$withBranch) unset($this->lang->product->menu->settings['subMenu']->branch);
|
||||
if($currentProduct->type != 'normal' && $withBranch && $currentModule != 'programplan') $output .= $this->getBranchSelect4Mobile($currentProduct, $branch, $currentModule, $currentMethod, $extra);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取产品路线图的分组数据。
|
||||
* Get group roadmap data of product.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param string $branch all|0|1
|
||||
* @param int $count
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
protected function getGroupRoadmapData(int $productID, string $branch, int $count): array
|
||||
{
|
||||
$roadmap = array();
|
||||
$total = 0;
|
||||
|
||||
/* Get product plans. */
|
||||
$plans = $this->loadModel('productplan')->getList($productID, $branch);
|
||||
|
||||
/* Get valid product plans and parent plans. */
|
||||
list($orderedPlans, $parents) = $this->filterValidProductPlans($plans);
|
||||
|
||||
/* Get roadmaps of product plans. */
|
||||
list($roadmap, $total, $return) = $this->getRoadmapsOfPlans($orderedPlans, $parents, $branch, $count);
|
||||
if($return) return $roadmap;
|
||||
|
||||
/* Get roadmpas of product releases. */
|
||||
$releases = $this->loadModel('release')->getList($productID, $branch);
|
||||
list($roadmap, $subTotal, $return) = $this->getRoadmapsOfReleases($roadmap, $releases, $branch, $count);
|
||||
if($return) return $roadmap;
|
||||
$total += $subTotal;
|
||||
|
||||
$groupRoadmap = array();
|
||||
foreach($roadmap as $year => $branchRoadmaps)
|
||||
{
|
||||
foreach($branchRoadmaps as $branch => $roadmaps)
|
||||
{
|
||||
$totalData = count($roadmaps);
|
||||
$rows = ceil($totalData / 8);
|
||||
$maxPerRow = ceil($totalData / $rows);
|
||||
|
||||
$groupRoadmap[$year][$branch] = array_chunk($roadmaps, (int)$maxPerRow);
|
||||
foreach($groupRoadmap[$year][$branch] as $row => $rowRoadmaps) krsort($groupRoadmap[$year][$branch][$row]);
|
||||
}
|
||||
}
|
||||
|
||||
return $groupRoadmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤有效的产品计划, 并返回所有父级计划。
|
||||
* Filter valid product plans.
|
||||
*
|
||||
* @param array $plans
|
||||
* @access private
|
||||
* @return [array, array]
|
||||
*/
|
||||
private function filterValidProductPlans(array $plans): array
|
||||
{
|
||||
$parents = array();
|
||||
$orderedPlans = array();
|
||||
|
||||
foreach($plans as $planID => $plan)
|
||||
{
|
||||
/* Remove parent plan. */
|
||||
if($plan->parent == '-1')
|
||||
{
|
||||
$parents[$planID] = $plan->title;
|
||||
unset($plans[$planID]);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Remove exceeded plan and long-time plan. */
|
||||
if((!helper::isZeroDate($plan->end) and $plan->end < date('Y-m-d')) or $plan->end == '2030-01-01') continue;
|
||||
|
||||
$orderedPlans[$plan->end][] = $plan;
|
||||
}
|
||||
|
||||
krsort($orderedPlans);
|
||||
|
||||
return array($orderedPlans, $parents);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取计划的路线图数据。
|
||||
* Get roadmaps of plans.
|
||||
*
|
||||
* @param array $orderedPlans
|
||||
* @param array $parents
|
||||
* @param string $branch
|
||||
* @param int $count
|
||||
* @access private
|
||||
* @return [array, int, bool]
|
||||
*/
|
||||
private function getRoadmapsOfPlans(array $orderedPlans, array $parents, string $branch, int $count): array
|
||||
{
|
||||
$return = false;
|
||||
$total = 0;
|
||||
$roadmap = array();
|
||||
|
||||
foreach($orderedPlans as $plans)
|
||||
{
|
||||
krsort($plans);
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
/* Attach parent plan. */
|
||||
if($plan->parent > 0 and isset($parents[$plan->parent])) $plan->title = $parents[$plan->parent] . ' / ' . $plan->title;
|
||||
|
||||
$year = substr($plan->end, 0, 4);
|
||||
$branchIdList = explode(',', trim($plan->branch, ','));
|
||||
$branchIdList = array_unique($branchIdList);
|
||||
foreach($branchIdList as $branchID)
|
||||
{
|
||||
if($branchID === '') continue;
|
||||
$roadmap[$year][$branchID][] = $plan;
|
||||
}
|
||||
$total++;
|
||||
|
||||
/* Exceed requested count. */
|
||||
if($count > 0 and $total >= $count)
|
||||
{
|
||||
$roadmap = $this->processRoadmap($roadmap, $branch);
|
||||
$return = true;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return array($roadmap, $total, $return);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取计划的路线图数据。
|
||||
* Get roadmaps of plans.
|
||||
*
|
||||
* @param array $roadmaps
|
||||
* @param array $parents
|
||||
* @param string $branch
|
||||
* @param int $count
|
||||
* @access private
|
||||
* @return [array, int, bool]
|
||||
*/
|
||||
private function getRoadmapsOfReleases(array $roadmaps, array $releases, string $branch, int $count): array
|
||||
{
|
||||
$total = 0;
|
||||
$return = false;
|
||||
$orderedReleases = array();
|
||||
|
||||
/* Collect releases. */
|
||||
foreach($releases as $release) $orderedReleases[$release->date][] = $release;
|
||||
|
||||
krsort($orderedReleases);
|
||||
foreach($orderedReleases as $releases)
|
||||
{
|
||||
krsort($releases);
|
||||
foreach($releases as $release)
|
||||
{
|
||||
$year = substr($release->date, 0, 4);
|
||||
$branchIdList = explode(',', trim($release->branch, ','));
|
||||
$branchIdList = array_unique($branchIdList);
|
||||
foreach($branchIdList as $branchID)
|
||||
{
|
||||
if($branchID === '') continue;
|
||||
$roadmaps[$year][$branchID][] = $release;
|
||||
}
|
||||
$total++;
|
||||
|
||||
/* Exceed required count .*/
|
||||
if($count > 0 and $total >= $count)
|
||||
{
|
||||
$roadmaps = $this->processRoadmap($roadmaps, $branch);
|
||||
$return = true;
|
||||
return array($roadmaps, $total, $return);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($count > 0)
|
||||
{
|
||||
$roadmaps = $this->processRoadmap($roadmaps, $branch);
|
||||
$return = true;
|
||||
}
|
||||
|
||||
return array($roadmaps, $total, $return);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
#su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->checkPriv();
|
||||
@@ -26,21 +24,22 @@ pid=1
|
||||
|
||||
*/
|
||||
|
||||
$productIDList = array('1', '2', '3', '4', '5', '1000001');
|
||||
$productIdList = array(1, 2, 3, 4, 5, 1000001);
|
||||
|
||||
$productTest = new productTest('admin');
|
||||
r($productTest->checkPrivTest($productIDList[0])) && p() && e('1'); // 测试admin能否看到产品1
|
||||
r($productTest->checkPrivTest($productIDList[1])) && p() && e('1'); // 测试admin能否看到产品2
|
||||
r($productTest->checkPrivTest($productIDList[2])) && p() && e('1'); // 测试admin能否看到产品3
|
||||
r($productTest->checkPrivTest($productIDList[3])) && p() && e('1'); // 测试admin能否看到产品4
|
||||
r($productTest->checkPrivTest($productIDList[4])) && p() && e('1'); // 测试admin能否看到产品5
|
||||
r($productTest->checkPrivTest($productIDList[5])) && p() && e('1'); // 测试admin能否看到不存在的产品
|
||||
|
||||
$productTest = new productTest('po1');
|
||||
r($productTest->checkPrivTest($productIDList[0])) && p() && e('1'); // 测试po1能否看到产品1
|
||||
r($productTest->checkPrivTest($productIDList[1])) && p() && e('1'); // 测试po1能否看到产品2
|
||||
r($productTest->checkPrivTest($productIDList[2])) && p() && e('1'); // 测试po1能否看到产品3
|
||||
r($productTest->checkPrivTest($productIDList[3])) && p() && e('1'); // 测试po1能否看到产品4
|
||||
r($productTest->checkPrivTest($productIDList[4])) && p() && e('1'); // 测试po1能否看到产品5
|
||||
r($productTest->checkPrivTest($productIDList[5])) && p() && e('2'); // 测试po1能否看到不存在的产品
|
||||
$productTest->objectModel->app->user->admin = true;
|
||||
r($productTest->checkPrivTest($productIdList[0])) && p() && e('1'); // 测试admin能否看到产品1
|
||||
r($productTest->checkPrivTest($productIdList[1])) && p() && e('1'); // 测试admin能否看到产品2
|
||||
r($productTest->checkPrivTest($productIdList[2])) && p() && e('1'); // 测试admin能否看到产品3
|
||||
r($productTest->checkPrivTest($productIdList[3])) && p() && e('1'); // 测试admin能否看到产品4
|
||||
r($productTest->checkPrivTest($productIdList[4])) && p() && e('1'); // 测试admin能否看到产品5
|
||||
r($productTest->checkPrivTest($productIdList[5])) && p() && e('1'); // 测试admin能否看到不存在的产品
|
||||
|
||||
$productTest->objectModel->app->user->admin = false;
|
||||
$productTest->objectModel->app->user->view->products = '1,2,3,4,5,6,7,8,9,20,21,48,49,50';
|
||||
r($productTest->checkPrivTest($productIdList[0])) && p() && e('1'); // 测试po1能否看到产品1
|
||||
r($productTest->checkPrivTest($productIdList[1])) && p() && e('1'); // 测试po1能否看到产品2
|
||||
r($productTest->checkPrivTest($productIdList[2])) && p() && e('1'); // 测试po1能否看到产品3
|
||||
r($productTest->checkPrivTest($productIdList[3])) && p() && e('1'); // 测试po1能否看到产品4
|
||||
r($productTest->checkPrivTest($productIdList[4])) && p() && e('1'); // 测试po1能否看到产品5
|
||||
r($productTest->checkPrivTest($productIdList[5])) && p() && e('0'); // 测试po1能否看到不存在的产品
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('product')->gen(10);
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->getMobileDropMenu();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试admin能否看到产品1 >> 1
|
||||
测试admin能否看到产品2 >> 1
|
||||
测试admin能否看到产品3 >> 1
|
||||
测试admin能否看到产品4 >> 1
|
||||
测试admin能否看到产品5 >> 1
|
||||
测试admin能否看到不存在的产品 >> 1
|
||||
测试po1能否看到产品1 >> 1
|
||||
测试po1能否看到产品2 >> 1
|
||||
测试po1能否看到产品3 >> 1
|
||||
测试po1能否看到产品4 >> 1
|
||||
测试po1能否看到产品5 >> 1
|
||||
测试po1能否看到不存在的产品 >> 2
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$productTest = $tester->loadModel('product');
|
||||
$products = $productTest->dao->select('*')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchPairs('id', 'name');
|
||||
|
||||
r(strpos($productTest->getMobileDropMenu($products, -1), 'showSearchMenu') !== false) && p() && e('1');
|
||||
r(strpos($productTest->getMobileDropMenu($products, 0), 'showSearchMenu') !== false) && p() && e('1');
|
||||
r(strpos($productTest->getMobileDropMenu($products, 1), 'showSearchMenu') !== false) && p() && e('1');
|
||||
r(strpos($productTest->getMobileDropMenu(array(), -1), 'showSearchMenu') !== false) && p() && e('0');
|
||||
r(strpos($productTest->getMobileDropMenu(array(), 0), 'showSearchMenu') !== false) && p() && e('0');
|
||||
r(strpos($productTest->getMobileDropMenu(array(), 1), 'showSearchMenu') !== false) && p() && e('0');
|
||||
@@ -9,11 +9,11 @@ title=productModel->getRoadmap();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试获取产品1的roadmap数量 >> 5
|
||||
测试获取产品2的roadmap数量 >> 2
|
||||
测试获取产品3的roadmap数量 >> 0
|
||||
测试获取产品4的roadmap数量 >> 0
|
||||
测试获取产品5的roadmap数量 >> 0
|
||||
测试获取产品1的roadmap数量 >> 1
|
||||
测试获取产品2的roadmap数量 >> 1
|
||||
测试获取产品3的roadmap数量 >> 1
|
||||
测试获取产品4的roadmap数量 >> 1
|
||||
测试获取产品5的roadmap数量 >> 1
|
||||
测试获取不存在产品的roadmap数量 >> 0
|
||||
|
||||
*/
|
||||
@@ -22,9 +22,9 @@ $productIDList = array('1', '2', '3', '4', '5', '1000001');
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->getRoadmapTest($productIDList[0])) && p('total') && e('5'); // 测试获取产品1的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[1])) && p('total') && e('2'); // 测试获取产品2的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[2])) && p('total') && e('0'); // 测试获取产品3的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[3])) && p('total') && e('0'); // 测试获取产品4的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[4])) && p('total') && e('0'); // 测试获取产品5的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[0])) && p('total') && e('1'); // 测试获取产品1的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[1])) && p('total') && e('1'); // 测试获取产品2的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[2])) && p('total') && e('1'); // 测试获取产品3的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[3])) && p('total') && e('1'); // 测试获取产品4的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[4])) && p('total') && e('1'); // 测试获取产品5的roadmap数量
|
||||
r($product->getRoadmapTest($productIDList[5])) && p('total') && e('0'); // 测试获取不存在产品的roadmap数量
|
||||
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('product')->gen(50);
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->setMenu();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
$product = new productTest('admin');
|
||||
$product->objectModel->app->moduleName = 'product';
|
||||
$product->objectModel->app->methodName = 'browse';
|
||||
|
||||
r($product->getSwitcherTest(0)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(1)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(0, '', 'all')) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(41,'', 'all')) && p('hasProduct,hasBranch') && e('1,1');
|
||||
r($product->getSwitcherTest(0, '', 0)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(41,'', 0)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
|
||||
$product->objectModel->app->viewType = 'mhtml';
|
||||
r($product->getSwitcherTest(0)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(1)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(0, '', 'all')) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(41,'', 'all')) && p('hasProduct,hasBranch') && e('1,1');
|
||||
r($product->getSwitcherTest(0, '', 0)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($product->getSwitcherTest(41,'', 0)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('product')->gen(50);
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->setMenu();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->setMenuTest(0)) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,0,1,0,0');
|
||||
r($product->setMenuTest(1)) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,0,0,0,1');
|
||||
r($product->setMenuTest(0, '', 'requirement')) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,0,1,1,0');
|
||||
r($product->setMenuTest(1, '', 'requirement')) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,0,0,1,1');
|
||||
r($product->setMenuTest(0, 'all')) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,0,1,0,0');
|
||||
r($product->setMenuTest(41, 'all')) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,1,1,0,1');
|
||||
r($product->setMenuTest(0, 0, 'requirement')) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,0,1,1,0');
|
||||
r($product->setMenuTest(41, 0, 'requirement')) && p('idReplaced,branchReplaced,hasBranch,requirement,hasSwitch') && e('1,1,1,1,1');
|
||||
@@ -5,7 +5,7 @@ class productTest
|
||||
* @var productModel
|
||||
* @access private
|
||||
*/
|
||||
private productModel $objectModel;
|
||||
public productModel $objectModel;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
@@ -372,20 +372,11 @@ class productTest
|
||||
*
|
||||
* @param int $productID
|
||||
* @access public
|
||||
* @return int
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPrivTest($productID)
|
||||
public function checkPrivTest(int $productID): bool
|
||||
{
|
||||
$object = $this->objectModel->checkPriv($productID);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $object ? 1 : 2;
|
||||
}
|
||||
return $this->objectModel->checkPriv($productID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -777,14 +768,9 @@ class productTest
|
||||
{
|
||||
$objects = $this->objectModel->getRoadmap($productID);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $objects;
|
||||
}
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -803,14 +789,9 @@ class productTest
|
||||
|
||||
$objects = $this->objectModel->processRoadmap($roadmapGroups);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $objects;
|
||||
}
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
return $objects;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1106,4 +1087,86 @@ class productTest
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试setMenu方法。
|
||||
* Test setMenu
|
||||
*
|
||||
* @param int $productID
|
||||
* @param string|int $branch
|
||||
* @param string $extra
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function setMenuTest(int $productID, string|int $branch = '', string $extra = ''): array
|
||||
{
|
||||
/* Reset data. */
|
||||
unset($this->objectModel->lang->switcherMenu);
|
||||
$this->objectModel->lang->product->moreSelects['willclose'] = 'willcose';
|
||||
$this->objectModel->lang->product->menu->settings['link'] = "Settings|product|view|productID=%s";
|
||||
$this->objectModel->lang->product->menu->settings['subMenu']->branch = array('link' => "@branch@|branch|manage|product=%s", 'subModule' => 'branch');
|
||||
|
||||
$this->objectModel->setMenu($productID, $branch, $extra);
|
||||
|
||||
$hasBranch = (int) isset($this->objectModel->lang->product->menu->settings['subMenu']->branch);
|
||||
$requirement = (int)!isset($this->objectModel->lang->product->moreSelects['willclose']);
|
||||
$hasSwitch = (int)!empty($this->objectModel->lang->switcherMenu);
|
||||
$idReplaced = (int)(strpos($this->objectModel->lang->product->menu->settings['link'], '%s') === false);
|
||||
$branchReplaced = (int)($hasBranch and strpos($this->objectModel->lang->product->menu->settings['subMenu']->branch['link'], '@branch@') === false);
|
||||
|
||||
return array('idReplaced' => $idReplaced, 'branchReplaced' => $branchReplaced, 'hasBranch' => $hasBranch, 'requirement' => $requirement, 'hasSwitch' => $hasSwitch);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 getSwitcher 方法。
|
||||
* Test getSwitcher.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param string $extra
|
||||
* @param string|int $branch
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getSwitcherTest(int $productID, string $extra = '', string|int $branch = ''): array
|
||||
{
|
||||
$this->objectModel->lang->product->menu->settings['subMenu']->branch = array('link' => "@branch@|branch|manage|product=%s", 'subModule' => 'branch');
|
||||
|
||||
$switcher = $this->objectModel->getSwitcher($productID, $extra, $branch);
|
||||
|
||||
$product = $this->objectModel->dao->select('*')->from(TABLE_PRODUCT)->where('id')->eq($productID)->fetch();
|
||||
$hasProduct = $product ? (int)(strpos($switcher, $product->name) !== false) : (int)(strpos($switcher, '产品') !== false);
|
||||
$hasBranch = (int)(strpos($switcher, 'currentBranch') !== false);
|
||||
|
||||
return array('hasProduct' => $hasProduct, 'hasBranch' => $hasBranch);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试 buildSelect4Mobile 方法。
|
||||
* Test buildSelect4Mobile
|
||||
*
|
||||
* @param array $products
|
||||
* @param int $productID
|
||||
* @param string $currentModule
|
||||
* @param string $currentMethod
|
||||
* @param string $extra
|
||||
* @param string|int $branch
|
||||
* @param bool $withBranch
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function buildSelect4MobileTest(array $products, int $productID, string $currentModule, string $currentMethod, string $extra = '', string|int $branch = '', bool $withBranch = true): array
|
||||
{
|
||||
$this->objectModel->lang->product->menu->settings['subMenu']->branch = array('link' => "@branch@|branch|manage|product=%s", 'subModule' => 'branch');
|
||||
|
||||
$select = $this->objectModel->buildSelect4Mobile($products, $productID, $currentModule, $currentMethod, $extra, $branch, $withBranch);
|
||||
|
||||
$productName = zget($products, $productID, reset($products));
|
||||
$branchName = '所有';
|
||||
if(is_numeric($branch)) $branchName = $this->objectModel->dao->select('*')->from(TABLE_BRANCH)->where('id')->eq($branch)->fetch('name');
|
||||
|
||||
$hasProduct = (int)(strpos($select, 'currentItem') !== false and strpos($select, $productName) !== false);
|
||||
$hasBranch = (int)(strpos($select, 'currentBranch') !== false and strpos($select, $branchName) !== false);
|
||||
|
||||
return array('hasProduct' => $hasProduct, 'hasBranch' => $hasBranch);
|
||||
}
|
||||
}
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('product')->gen(50);
|
||||
$branch = zdTable('branch');
|
||||
$branch->product->range('41');
|
||||
$branch->gen(5);
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->buildSelect4Mobile();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
$productTest = new productTest('admin');
|
||||
$productTest->objectModel->dao->update(TABLE_PRODUCT)->set('deleted')->eq(1)->where('id')->eq(49)->exec();
|
||||
$products = $productTest->objectModel->dao->select('*')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchPairs('id', 'name');
|
||||
|
||||
$moduleName = 'product';
|
||||
$methodName = 'browse';
|
||||
r($productTest->buildSelect4MobileTest(array(), 0, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('0,0');
|
||||
r($productTest->buildSelect4MobileTest($products, 0, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($productTest->buildSelect4MobileTest($products, 1, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($productTest->buildSelect4MobileTest($products, 49, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName, '', 1)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName, '', '', false)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
r($productTest->buildSelect4MobileTest($products, 70, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,0');
|
||||
|
||||
$productTest->objectModel->app->tab = 'project';
|
||||
$moduleName = 'project';
|
||||
$methodName = 'testcase';
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
$moduleName = 'testcase';
|
||||
$methodName = 'groupCase';
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
|
||||
$productTest->objectModel->app->tab = 'execution';
|
||||
$moduleName = 'execution';
|
||||
$methodName = 'bug';
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
$methodName = 'task';
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
|
||||
$productTest->objectModel->app->tab = 'feedback';
|
||||
$moduleName = 'bug';
|
||||
$methodName = 'view';
|
||||
r($productTest->buildSelect4MobileTest($products, 41, $moduleName, $methodName)) && p('hasProduct,hasBranch') && e('1,1');
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->computeLocate4DropMenu();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$product = $tester->loadModel('product');
|
||||
|
||||
$product->app->moduleName = 'product';
|
||||
$product->app->methodName = 'browse';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('product,browse');
|
||||
|
||||
$product->app->moduleName = 'story';
|
||||
$product->app->methodName = 'view';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('product,browse');
|
||||
|
||||
$product->app->moduleName = 'story';
|
||||
$product->app->methodName = 'create';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('story,create');
|
||||
|
||||
$product->app->moduleName = 'story';
|
||||
$product->app->methodName = 'report';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('product,browse');
|
||||
|
||||
$product->app->moduleName = 'product';
|
||||
$product->app->methodName = 'report';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('product,browse');
|
||||
|
||||
$product->app->moduleName = 'bug';
|
||||
$product->app->methodName = 'edit';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('bug,browse');
|
||||
|
||||
$product->app->moduleName = 'bug';
|
||||
$product->app->methodName = 'view';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('bug,view');
|
||||
|
||||
$product->app->moduleName = 'bug';
|
||||
$product->app->methodName = 'report';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('bug,browse');
|
||||
|
||||
$product->app->moduleName = 'testcase';
|
||||
$product->app->methodName = 'edit';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('testcase,browse');
|
||||
|
||||
$product->app->moduleName = 'testcase';
|
||||
$product->app->methodName = 'view';
|
||||
r($product->computeLocate4DropMenu()) && p('0,1') && e('testcase,browse');
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
|
||||
zdTable('product')->gen(50);
|
||||
$branch = zdTable('branch');
|
||||
$branch->product->range('41');
|
||||
$branch->gen(5);
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->getBranchSelect4Mobile();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$productTest = $tester->loadModel('product');
|
||||
$product = $productTest->dao->select('*')->from(TABLE_PRODUCT)->where('id')->eq(1)->fetch();
|
||||
|
||||
$moduleName = 'product';
|
||||
$methodName = 'browse';
|
||||
r($productTest->getBranchSelect4Mobile(new stdclass(), '', $moduleName, $methodName)) && p() && e('0');
|
||||
r($productTest->getBranchSelect4Mobile($product, '', $moduleName, $methodName)) && p() && e('0');
|
||||
|
||||
$product = $productTest->dao->select('*')->from(TABLE_PRODUCT)->where('id')->eq(41)->fetch();
|
||||
$result = $productTest->getBranchSelect4Mobile($product, 'all', $moduleName, $methodName);
|
||||
r((strpos($result, 'currentBranch') !== false and strpos($result, '所有') !== false)) && p() && e('1');
|
||||
|
||||
$result = $productTest->getBranchSelect4Mobile($product, 1, $moduleName, $methodName);
|
||||
r((strpos($result, 'currentBranch') !== false and strpos($result, '分支1') !== false)) && p() && e('1');
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
|
||||
zdTable('product')->gen(50);
|
||||
$branch = zdTable('branch');
|
||||
$branch->product->range('41');
|
||||
$branch->gen(5);
|
||||
|
||||
/**
|
||||
|
||||
title=测试productModel->getBranchSelect4PC();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$productTest = $tester->loadModel('product');
|
||||
$product = $productTest->dao->select('*')->from(TABLE_PRODUCT)->where('id')->eq(1)->fetch();
|
||||
|
||||
$moduleName = 'product';
|
||||
$methodName = 'browse';
|
||||
r($productTest->getBranchSelect4PC(new stdclass(), '', $moduleName, $methodName)) && p() && e('0');
|
||||
r($productTest->getBranchSelect4PC($product, '', $moduleName, $methodName)) && p() && e('0');
|
||||
|
||||
$product = $productTest->dao->select('*')->from(TABLE_PRODUCT)->where('id')->eq(41)->fetch();
|
||||
$result = $productTest->getBranchSelect4PC($product, '', $moduleName, $methodName);
|
||||
r((strpos($result, 'currentBranch') !== false and strpos($result, '所有') !== false)) && p() && e('1');
|
||||
|
||||
$result = $productTest->getBranchSelect4PC($product, 1, $moduleName, $methodName);
|
||||
r((strpos($result, 'currentBranch') !== false and strpos($result, '分支1') !== false)) && p() && e('1');
|
||||
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'testcase', 'showimport'), 'currentBranch') !== false)) && p() && e('0');
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'tree', 'browse'), 'currentBranch') !== false)) && p() && e('1');
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'product', 'view'), 'currentBranch') !== false)) && p() && e('0');
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'release', 'create'), 'currentBranch') !== false)) && p() && e('1');
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'release', 'view'), 'currentBranch') !== false)) && p() && e('0');
|
||||
|
||||
$productTest->app->tab = 'qa';
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'bug', 'view'), 'currentBranch') !== false)) && p() && e('1');
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'testcase', 'view'), 'currentBranch') !== false)) && p() && e('1');
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'testtask', 'view'), 'currentBranch') !== false)) && p() && e('1');
|
||||
r((strpos($productTest->getBranchSelect4PC($product, 1, 'testtask', 'create'), 'currentBranch') !== false)) && p() && e('0');
|
||||
@@ -19,7 +19,7 @@ class productZen extends product
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function setEnvAll()
|
||||
protected function setMenu4All()
|
||||
{
|
||||
/* Set redirect URI. */
|
||||
$this->session->set('productList', $this->app->getURI(true), 'product');
|
||||
@@ -28,7 +28,7 @@ class productZen extends product
|
||||
if($this->app->viewType == 'mhtml')
|
||||
{
|
||||
$productID = $this->saveVisitState(0, $this->products);
|
||||
$this->setMenu($productID);
|
||||
$this->product->setMenu($productID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class productZen extends product
|
||||
setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true);
|
||||
$this->session->set('createProjectLocate', $this->app->getURI(true), 'product');
|
||||
|
||||
$this->setMenu($productID, $branch);
|
||||
$this->product->setMenu($productID, $branch);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +67,7 @@ class productZen extends product
|
||||
if($this->app->getViewType() != 'mhtml') return;
|
||||
|
||||
if($this->app->rawModule == 'projectstory' and $this->app->rawMethod == 'story') return $this->loadModel('project')->setMenu();
|
||||
$this->setMenu();
|
||||
$this->product->setMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +82,7 @@ class productZen extends product
|
||||
protected function setEditMenu(int $productID, int $programID)
|
||||
{
|
||||
if($programID) return $this->loadModel('program')->setMenu($programID);
|
||||
$this->setMenu($productID);
|
||||
$this->product->setMenu($productID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +97,7 @@ class productZen extends product
|
||||
*/
|
||||
protected function setShowErrorNoneMenu(string $moduleName, string $activeMenu, int $objectID)
|
||||
{
|
||||
if($this->app->getViewType() == 'mhtml') return $this->setMenu();
|
||||
if($this->app->getViewType() == 'mhtml') return $this->product->setMenu();
|
||||
|
||||
if($moduleName == 'qa') $this->setShowErrorNoneMenu4QA($activeMenu);
|
||||
if($moduleName == 'project') $this->setShowErrorNoneMenu4Project($activeMenu, $objectID);
|
||||
@@ -845,7 +845,7 @@ class productZen extends product
|
||||
return;
|
||||
}
|
||||
|
||||
$this->product->setMenu($productID, $branch, 0, '', "storyType=$storyType");
|
||||
$this->product->setMenu($productID, $branch, "storyType=$storyType");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -54,6 +54,7 @@ class programplan extends control
|
||||
|
||||
if(!defined('RUN_MODE') || RUN_MODE != 'api') $projectID = $this->project->saveState($projectID, $this->project->getPairsByProgram());
|
||||
|
||||
/* 获取项目下产品并调整三级导航操作按钮。 */
|
||||
$products = $this->loadModel('product')->getProducts($projectID);
|
||||
if($this->session->hasProduct) $this->lang->modulePageNav = $this->product->select($products, $productID, 'programplan', 'browse', $type, 0, 0, '', false);
|
||||
|
||||
|
||||
@@ -1540,13 +1540,14 @@ class programplanModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查阶段是否是叶子阶段。
|
||||
* Check if the stage is a leaf stage.
|
||||
*
|
||||
* @param int $planID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function checkLeafStage($planID)
|
||||
public function checkLeafStage(int $planID): bool
|
||||
{
|
||||
$subStageList = $this->dao->select('id')->from(TABLE_EXECUTION)->where('parent')->eq($planID)->andWhere('deleted')->eq(0)->fetchAll('id');
|
||||
|
||||
|
||||
@@ -1,23 +1,16 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 5) . '/test/lib/init.php';
|
||||
include dirname(__FILE__, 2) . '/programplan.class.php';
|
||||
zdTable('user')->gen(5);
|
||||
|
||||
function initData()
|
||||
{
|
||||
zdTable('user')->gen(5);
|
||||
zdTable('project')->config('checkleafstage')->gen(5);
|
||||
}
|
||||
|
||||
su('admin');
|
||||
|
||||
$execution = zdTable('project');
|
||||
$execution->id->range('1-5');
|
||||
$execution->name->range('瀑布项目1,阶段a,阶段a子1,阶段a子1子1,阶段b');
|
||||
$execution->type->range('project,stage{4}');
|
||||
$execution->project->range('0,1{4}');
|
||||
$execution->parent->range('0,1,2,3,1');
|
||||
$execution->path->range("`,1,`,`,1,2,`,`,1,2,3,`,`,1,2,3,4,`,`,1,5,`");
|
||||
$execution->status->range('doing,doing,doing,closed,suspended');
|
||||
$execution->openedBy->range('admin,user1');
|
||||
$execution->begin->range('20220112 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$execution->end->range('20220212 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$execution->realBegan->range('20220212 000000:0')->type('timestamp')->format('YY/MM/DD');
|
||||
$execution->gen(5);
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,8 +18,9 @@ title=测试programplanModel->checkLeafStage();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
测试id为2判断是否为叶子节点 >> 0
|
||||
测试id为5判断是否为叶子节点 >> 1
|
||||
- 测试id为2判断是否为叶子节点 @0
|
||||
|
||||
- 测试id为5判断是否为叶子节点 @1
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
title: programplanModel::checkLeafStage UTC.
|
||||
desc: programplanModel::checkLeafStage UTC.
|
||||
author: xushenjie
|
||||
version: '1.0'
|
||||
fields:
|
||||
- field: name
|
||||
range: '瀑布项目1,阶段a,阶段a子1,阶段a子1子1,阶段b'
|
||||
- field: type
|
||||
range: '0,1{4}'
|
||||
- field: project
|
||||
range: '0,1{4}'
|
||||
- field: parent
|
||||
range: '0,1,2,3,1'
|
||||
- field: grade
|
||||
range: 1
|
||||
- field: path
|
||||
range: "`,1,`,`,1,2,`,`,1,2,3,`,`,1,2,3,4,`,`,1,5,`"
|
||||
- field: status
|
||||
range: 'doing,doing,doing,closed,suspended'
|
||||
- field: openedBy
|
||||
range: 'admin,user1'
|
||||
- field: begin
|
||||
range: '20230501 000000:0'
|
||||
type: 'timestamp'
|
||||
format: 'YY/MM/DD'
|
||||
- field: end
|
||||
range: '20300501 000000:0'
|
||||
type: 'timestamp'
|
||||
format: 'YY/MM/DD'
|
||||
- field: realBegan
|
||||
range: '20230501 000000:0'
|
||||
type: 'timestamp'
|
||||
format: 'YY/MM/DD'
|
||||
@@ -630,10 +630,10 @@ class projectTao extends projectModel
|
||||
* @param int $program
|
||||
* @param string $path
|
||||
* @param int $grade
|
||||
* @access public
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
public function getParentProgram(string $path, int $grade): string
|
||||
protected function getParentProgram(string $path, int $grade): string
|
||||
{
|
||||
$programList = $this->dao->select('id,name')->from(TABLE_PROGRAM)
|
||||
->where('id')->in(trim($path, ','))
|
||||
@@ -761,10 +761,10 @@ class projectTao extends projectModel
|
||||
* Get the number of stories associated with the project.
|
||||
*
|
||||
* @param array $projectIdList
|
||||
* @access public
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
public function getTotalStoriesByProject(array $projectIdList): array
|
||||
protected function getTotalStoriesByProject(array $projectIdList): array
|
||||
{
|
||||
return $this->dao->select("t1.project, count(t2.id) as allStories, count(if(t2.status = 'active' or t2.status = 'changing', 1, null)) as leftStories, count(if(t2.status = 'closed' and t2.closedReason = 'done', 1, null)) as doneStories")->from(TABLE_PROJECTSTORY)->alias('t1')
|
||||
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
|
||||
@@ -780,10 +780,10 @@ class projectTao extends projectModel
|
||||
* Get the number of tasks associated with the project.
|
||||
*
|
||||
* @param array $projectIdList
|
||||
* @access public
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
public function getTotalTaskByProject(array $projectIdList): array
|
||||
protected function getTotalTaskByProject(array $projectIdList): array
|
||||
{
|
||||
return $this->dao->select("t1.project, count(t1.id) as allTasks, count(if(t1.status = 'wait', 1, null)) as waitTasks, count(if(t1.status = 'doing', 1, null)) as doingTasks, count(if(t1.status = 'done', 1, null)) as doneTasks, count(if(t1.status = 'wait' or t1.status = 'pause' or t1.status = 'cancel', 1, null)) as leftTasks, count(if(t1.status = 'done' or t1.status = 'closed', 1, null)) as litedoneTasks")->from(TABLE_TASK)->alias('t1')
|
||||
->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.execution=t2.id')
|
||||
@@ -812,10 +812,10 @@ class projectTao extends projectModel
|
||||
* Get the number of bugs associated with the project.
|
||||
*
|
||||
* @param array $projectIdList
|
||||
* @access public
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
public function getTotalBugByProject(array $projectIdList): array
|
||||
protected function getTotalBugByProject(array $projectIdList): array
|
||||
{
|
||||
return $this->dao->select("project, count(id) as allBugs, count(if(status = 'active', 1, null)) as leftBugs, count(if(status = 'resolved', 1, null)) as doneBugs")->from(TABLE_BUG)
|
||||
->where('project')->in($projectIdList)
|
||||
|
||||
@@ -15,14 +15,10 @@ pid=1
|
||||
global $tester;
|
||||
|
||||
$tester->loadModel('project');
|
||||
$project1 = $tester->project->getProgramMaxEnd(1);
|
||||
$project2 = $tester->project->getProgramMaxEnd(3);
|
||||
$project3 = $tester->project->getProgramMaxEnd(6);
|
||||
$project4 = $tester->project->getProgramMaxEnd(1);
|
||||
$project5 = $tester->project->getProgramMaxEnd(3);
|
||||
$project6 = $tester->project->getProgramMaxEnd(6);
|
||||
|
||||
a($project1);die;
|
||||
r($project1) && p() && e(); //获取一级项目集最小开始时间
|
||||
r($project1) && p() && e(); //获取一级项目集最大结束时间
|
||||
r($project2) && p() && e(); //获取二级项目集最小开始时间
|
||||
r($project2) && p() && e(); //获取二级项目集最大结束时间
|
||||
r($project3) && p() && e(); //获取三级项目集最小开始时间
|
||||
r($project3) && p() && e(); //获取三级项目集最大结束时间
|
||||
r($project6) && p('maxEnd') && e('2023-06-12'); //获取一级项目集最大结束时间:尾级项目结束时间最大
|
||||
r($project5) && p('maxEnd') && e('2023-07-03'); //获取二级项目集最大结束时间:顶级项目结束时间最大
|
||||
r($project4) && p('maxEnd') && e('2023-05-08'); //获取三级项目集最大结束时间:开始时间等于结束时间
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
su('admin');
|
||||
|
||||
$project = zdTable('project')->config('project')->gen(6);
|
||||
|
||||
/**
|
||||
|
||||
title=测试 projectModel->getProgramMinBegin();
|
||||
cid=1
|
||||
pid=1
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
|
||||
$tester->loadModel('project');
|
||||
$project1 = $tester->project->getProgramMinBegin(1);
|
||||
$project2 = $tester->project->getProgramMinBegin(3);
|
||||
$project3 = $tester->project->getProgramMinBegin(6);
|
||||
|
||||
r($project1) && p('minBegin') && e('2023-05-01'); //获取一级项目集最小开始时间:顶级项目开始时间最小
|
||||
r($project2) && p('minBegin') && e('2023-04-22'); //获取二级项目集最小开始时间:次级项目开始时间最小
|
||||
r($project3) && p('minBegin') && e('2023-05-08'); //获取三级项目集最小开始时间:开始时间等于结束时间
|
||||
@@ -22,7 +22,5 @@ fields:
|
||||
range: '项目集1, 项目集1-1, 项目1-1-2, 项目集3, 项目3-4, 无迭代无产品项目6'
|
||||
- field: code
|
||||
range: 'program1, program1-1, project1-1-2, program3, project3-4, project6'
|
||||
- field: begin
|
||||
range: "'2023-05-01', '2023-05-07', '2023-05-20', '2023-04-04', '2023-05-01', '2023-05-08'"
|
||||
- field: end
|
||||
range: "'2023-06-01', '2023-05-19', '2023-06-12', '2023-07-03', '2023-06-03', '2023-05-08'"
|
||||
range: '2023-06-01', '2023-05-19', '2023-06-12', '2023-07-03', '2023-06-03', '2023-05-08'
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
title: zt_project
|
||||
author: liuhong
|
||||
version: "1.0"
|
||||
fields:
|
||||
- field: id
|
||||
range: 1-6
|
||||
- field: project
|
||||
range: 0
|
||||
- field: model
|
||||
range: ', , ,scrum, ,scrum,scrum'
|
||||
- field: type
|
||||
range: 'program,program,project,program,project,project'
|
||||
- field: status
|
||||
range: 'wait,doing,closed,suspended'
|
||||
- field: parent
|
||||
range: 0, 1, 2, 0, 3, 0
|
||||
- field: grade
|
||||
range: 1, 2, 3, 1, 2, 1
|
||||
- field: path
|
||||
range: '`,1,`, `,1,2,`, `,1,2,3,`, `,4,`, `,4,5,`, `,6,`'
|
||||
- field: name
|
||||
range: '项目集1, 项目集1-1, 项目1-1-2, 项目集3, 项目3-4, 无迭代无产品项目6'
|
||||
- field: code
|
||||
range: 'program1, program1-1, project1-1-2, program3, project3-4, project6'
|
||||
- field: begin
|
||||
range: '2023-05-01', '2023-05-07', '2023-05-20', '2023-05-01', '2023-04-22', '2023-05-08'
|
||||
@@ -25,15 +25,21 @@ $config->task->form->create['version'] = array('type' => 'int', 'required'
|
||||
$config->task->form->assign = array();
|
||||
$config->task->form->assign['assignedTo'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->task->form->assign['left'] = array('type' => 'float', 'required' => true);
|
||||
$config->task->form->assign['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account);
|
||||
$config->task->form->assign['lastEditedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now());
|
||||
$config->task->form->assign['assignedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now());
|
||||
|
||||
$config->task->form->manageTeam = array();
|
||||
$config->task->form->manageTeam['status'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->task->form->manageTeam['estimate'] = array('type' => 'float', 'required' => false, 'default' => 0);
|
||||
$config->task->form->manageTeam['left'] = array('type' => 'float', 'required' => false, 'default' => 0);
|
||||
$config->task->form->manageTeam['consumed'] = array('type' => 'float', 'required' => false, 'default' => 0);
|
||||
$config->task->form->manageTeam['lastEditedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now());
|
||||
$config->task->form->manageTeam['assignedDate'] = array('type' => 'string', 'required' => false, 'default' => helper::now());
|
||||
|
||||
$config->task->form->edit = array();
|
||||
$config->task->form->edit['name'] = array('type' => 'string', 'required' => true);
|
||||
$config->task->form->edit['color'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->task->form->edit['desc'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->task->form->edit['lastEditedBy'] = array('type' => 'string', 'required' => false, 'default' => $app->user->account);
|
||||
$config->task->form->edit['execution'] = array('type' => 'int', 'required' => true);
|
||||
$config->task->form->edit['story'] = array('type' => 'int', 'required' => false, 'default' => 0);
|
||||
$config->task->form->edit['module'] = array('type' => 'int', 'required' => false, 'default' => 0);
|
||||
|
||||
+41
-58
@@ -174,16 +174,18 @@ class task extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑任务。
|
||||
* Edit a task.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param string $taskID
|
||||
* @param string $comment
|
||||
* @param string $from
|
||||
* @param string $from ''|taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function edit(string $taskID, string $comment = 'false', string $from = '')
|
||||
public function edit(string $taskID, string $comment = '', string $from = '')
|
||||
{
|
||||
$taskID = (int)$taskID;
|
||||
$this->commonAction($taskID);
|
||||
|
||||
if(!empty($_POST))
|
||||
@@ -192,15 +194,17 @@ class task extends control
|
||||
$changes = array();
|
||||
|
||||
$postDataFixer = form::data($this->config->task->form->edit);
|
||||
$rawData = $postDataFixer->rawdata;
|
||||
$rawData = $postDataFixer->rawdata;
|
||||
|
||||
if(!$comment or $comment == 'false')
|
||||
/* Update task. */
|
||||
if(empty($comment))
|
||||
{
|
||||
$task = $this->taskZen->prepareEdit($postDataFixer, $taskID);
|
||||
$changes = $this->task->update($task, $rawData);
|
||||
if(dao::isError()) return print(js::error(dao::getError()));
|
||||
}
|
||||
|
||||
/* Record log. */
|
||||
if($rawData->comment != '' or !empty($changes))
|
||||
{
|
||||
$action = !empty($changes) ? 'Edited' : 'Commented';
|
||||
@@ -208,9 +212,9 @@ class task extends control
|
||||
if(!empty($changes)) $this->action->logHistory($actionID, $changes);
|
||||
}
|
||||
|
||||
/* Execute hooks and synchronize the status of related objects. */
|
||||
$this->executeHooks($taskID);
|
||||
|
||||
if($rawData->status == 'doing') $this->loadModel('common')->syncPPEStatus($taskID);
|
||||
if($task->status == 'doing') $this->loadModel('common')->syncPPEStatus($taskID);
|
||||
|
||||
$reponse = $this->taskZen->reponseAfterEdit($taskID, $from, $changes);
|
||||
return is_array($reponse) ? $this->send($reponse) : $reponse;
|
||||
@@ -359,47 +363,45 @@ class task extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 指派任务。
|
||||
* Update assign of task
|
||||
*
|
||||
* @param int $requestID
|
||||
* @param int $taskID
|
||||
* @param string $kanbanGroup
|
||||
* @param string $from
|
||||
* @param stirng $executionID
|
||||
* @param string $taskID
|
||||
* @param string $from ''|taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function assignTo(int $executionID, int $taskID, string $kanbanGroup = 'default', string $from = '')
|
||||
public function assignTo(string $executionID, string $taskID, string $from = '')
|
||||
{
|
||||
$executionID = (int)$executionID;
|
||||
$taskID = (int)$taskID;
|
||||
$this->commonAction($taskID);
|
||||
$task = $this->task->getByID($taskID);
|
||||
|
||||
if(!empty($task->team) and $task->mode == 'multi' and strpos('done,cencel,closed', $task->status) === false)
|
||||
{
|
||||
return $this->editTeam($executionID, $taskID, $kanbanGroup, $from);
|
||||
}
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$postDataFixer = form::data($this->config->task->form->assign);
|
||||
$rawData = $postDataFixer->rawdata;
|
||||
|
||||
/* Assign task. */
|
||||
$task = $this->taskZen->prepareAssignTo($postDataFixer, $taskID);
|
||||
$changes = $this->task->assign($task);
|
||||
$changes = $this->task->assign($task, $this->post->uid);
|
||||
if(dao::isError())
|
||||
{
|
||||
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return print(js::error(dao::getError()));
|
||||
}
|
||||
|
||||
$actionID = $this->loadModel('action')->create('task', $taskID, 'Assigned', $rawData->comment, $task->assignedTo);
|
||||
/* Record log. */
|
||||
$actionID = $this->loadModel('action')->create('task', $taskID, 'Assigned', $this->post->comment, $task->assignedTo);
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
$this->executeHooks($taskID);
|
||||
|
||||
return $this->taskZen->reponseAfterAssignTo($taskID, $from);
|
||||
$reponse = $this->taskZen->reponseAfterAssignTo($taskID, $from);
|
||||
return is_array($reponse) ? $this->send($reponse) : $reponse;
|
||||
}
|
||||
|
||||
$this->taskZen->buildAssignToForm($executionID, $task);
|
||||
$this->taskZen->buildAssignToForm($executionID, $taskID);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1902,24 +1904,29 @@ class task extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理多人任务的团队。
|
||||
* Update assign of multi task.
|
||||
*
|
||||
* @param int $requestID
|
||||
* @param object $taskID
|
||||
* @param string $kanbanGroup
|
||||
* @param string $from
|
||||
* @param string $executionID
|
||||
* @param string $taskID
|
||||
* @param string $from ''|taskkanban
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function editTeam($executionID, $taskID, $kanbanGroup = 'default', $from = '')
|
||||
public function manageTeam(string $executionID, string $taskID, string $from = '')
|
||||
{
|
||||
$task = $this->task->getById($taskID);
|
||||
$executionID = (int)$executionID;
|
||||
$taskID = (int)$taskID;
|
||||
$this->commonAction($taskID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$changes = $this->task->updateTeam($taskID);
|
||||
|
||||
/* Update assign of multi task. */
|
||||
$postData = form::data($this->config->task->form->manageTeam);
|
||||
$task = $this->taskZen->prepareManageTeam($postData, $taskID);
|
||||
$changes = $this->task->updateTeam($task, $this->post->team, $this->post->teamSouce, $this->post->teamEstimate, $this->post->teamConsumed, $this->post->teamLeft);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
@@ -1927,43 +1934,19 @@ class task extends control
|
||||
return print(js::error(dao::getError()));
|
||||
}
|
||||
|
||||
/* Record log. */
|
||||
$actionID = $this->action->create('task', $taskID, 'Edited');
|
||||
$this->action->logHistory($actionID, $changes);
|
||||
|
||||
$this->executeHooks($taskID);
|
||||
|
||||
if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success'));
|
||||
if(isonlybody())
|
||||
{
|
||||
$execution = $this->execution->getByID($task->execution);
|
||||
|
||||
if(($this->app->tab == 'execution' or ($this->config->vision == 'lite' and $this->app->tab == 'project' and $this->session->kanbanview == 'kanban')) and $execution->type == 'kanban')
|
||||
{
|
||||
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $execLaneType, 'id_desc', 0, $execGroupBy, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
|
||||
}
|
||||
|
||||
if($from == 'taskkanban')
|
||||
{
|
||||
$rdSearchValue = $this->session->rdSearchValue ? $this->session->rdSearchValue : '';
|
||||
$kanbanData = $this->loadModel('kanban')->getRDKanban($task->execution, $this->session->execLaneType ? $this->session->execLaneType : 'all', 'id_desc', 0, $kanbanGroup, $rdSearchValue);
|
||||
$kanbanData = json_encode($kanbanData);
|
||||
|
||||
return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)"));
|
||||
}
|
||||
|
||||
return print(js::closeModal('parent.parent', 'this'));
|
||||
}
|
||||
return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent'));
|
||||
$reponse = $this->taskZen->reponseAfterAssignTo($taskID, $from);
|
||||
return is_array($reponse) ? $this->send($reponse) : $reponse;
|
||||
}
|
||||
|
||||
$this->view->task = $task;
|
||||
$this->view->members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted');
|
||||
$this->view->users = $this->loadModel('user')->getPairs();
|
||||
$this->display('', 'editTeam');
|
||||
$this->display('', 'editteam');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+33
-34
@@ -452,7 +452,7 @@ class taskModel extends model
|
||||
* Manage multi task team members.
|
||||
*
|
||||
* @param string $mode
|
||||
* @param object $taskID
|
||||
* @param object $task
|
||||
* @param array $teamList
|
||||
* @param array $teamSourceList
|
||||
* @param array $teamEstimateList
|
||||
@@ -469,10 +469,10 @@ class taskModel extends model
|
||||
$this->dao->delete()->from(TABLE_TASKTEAM)->where('task')->eq($task->id)->exec();
|
||||
|
||||
/* If status of the task is doing, get the person who did not complete the task. */
|
||||
$undoneUsers = array();
|
||||
if($task->status == 'doing')
|
||||
{
|
||||
$efforts = $this->getTaskEfforts($task->id);
|
||||
$undoneUsers = array();
|
||||
$efforts = $this->getTaskEfforts($task->id);
|
||||
foreach($efforts as $effort)
|
||||
{
|
||||
if($effort->left != 0) $undoneUsers[$effort->account] = $effort->account;
|
||||
@@ -1140,14 +1140,15 @@ class taskModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务指派用户。
|
||||
* Assign a task to a user again.
|
||||
*
|
||||
* @param object $task
|
||||
* @param int $taskID
|
||||
* @access public
|
||||
* @return array
|
||||
* @return array|false
|
||||
*/
|
||||
public function assign(object $task): array|false
|
||||
public function assign(object $task, string $uid): array|false
|
||||
{
|
||||
$oldTask = $this->getById($task->id);
|
||||
|
||||
@@ -1159,11 +1160,10 @@ class taskModel extends model
|
||||
|
||||
if($oldTask->parent > 0) $this->updateParentStatus($task->id);
|
||||
|
||||
$task = $this->loadModel('file')->processImgURL($task, $this->config->task->editor->assignto['id'], $this->post->uid);
|
||||
$task = $this->loadModel('file')->processImgURL($task, $this->config->task->editor->assignto['id'], $uid);
|
||||
$this->dao->update(TABLE_TASK)
|
||||
->data($task)
|
||||
->autoCheck()
|
||||
->check('left', 'float')
|
||||
->checkFlow()
|
||||
->where('id')->eq($task->id)
|
||||
->exec();
|
||||
@@ -1172,56 +1172,46 @@ class taskModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a task team.
|
||||
* 更新团队信息。
|
||||
* Update team.
|
||||
*
|
||||
* @param int $taskID
|
||||
* @param object $task
|
||||
* @param array $team
|
||||
* @param array $teamConsumed
|
||||
* @param array $teamLeft
|
||||
* @access public
|
||||
* @return void
|
||||
* @return array|false
|
||||
*/
|
||||
public function updateTeam($taskID)
|
||||
public function updateTeam(object $task, array $team, array $teamSource, array $teamEstimate, array $teamConsumed, array $teamLeft): array|false
|
||||
{
|
||||
$taskID = $task->id;
|
||||
$oldTask = $this->getById($taskID);
|
||||
foreach($this->post->team as $i => $account)
|
||||
|
||||
/* Check team data. */
|
||||
foreach($team as $i => $account)
|
||||
{
|
||||
if(!$account) continue;
|
||||
|
||||
if($this->post->teamConsumed[$i] == 0 and $this->post->teamLeft[$i] == 0)
|
||||
if($teamConsumed[$i] == 0 and $teamLeft[$i] == 0)
|
||||
{
|
||||
dao::$errors[] = $this->lang->task->noticeTaskStart;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$now = helper::now();
|
||||
$task = fixer::input('post')
|
||||
->add('id', $taskID)
|
||||
->setDefault('estimate, left, consumed', 0)
|
||||
->setIF(is_numeric($this->post->estimate), 'estimate', (float)$this->post->estimate)
|
||||
->setIF(is_numeric($this->post->consumed), 'consumed', (float)$this->post->consumed)
|
||||
->setIF(is_numeric($this->post->left), 'left', (float)$this->post->left)
|
||||
->setDefault('lastEditedBy', $this->app->user->account)
|
||||
->setDefault('lastEditedDate', $now)
|
||||
->setDefault('assignedDate', $now)
|
||||
->stripTags($this->config->task->editor->assignto['id'], $this->config->allowedTags)
|
||||
->remove('comment,showModule,team,teamEstimate,teamConsumed,teamLeft,teamSource')
|
||||
->get();
|
||||
|
||||
if(count(array_filter($this->post->team)) > 1)
|
||||
/* Manage the team and calculate task work information. */
|
||||
if(count(array_filter($team)) > 1)
|
||||
{
|
||||
$teams = $this->manageTaskTeam($oldTask->mode, $taskID, $task->status);
|
||||
$teams = $this->manageTaskTeam($oldTask->mode, $task, $team, $teamSource, $teamEstimate, $teamConsumed, $teamLeft);
|
||||
if(!empty($teams)) $task = $this->computeHours4Multiple($oldTask, $task);
|
||||
}
|
||||
if(empty($teams)) $task->mode = '';
|
||||
|
||||
if($oldTask->parent > 0) $this->updateParentStatus($taskID);
|
||||
|
||||
$task = $this->loadModel('file')->processImgURL($task, $this->config->task->editor->assignto['id'], $this->post->uid);
|
||||
$this->dao->update(TABLE_TASK)
|
||||
->data($task)
|
||||
->autoCheck()
|
||||
->checkIF($task->estimate != false, 'estimate', 'float')
|
||||
->checkIF($task->left != false, 'left', 'float')
|
||||
->checkIF($task->consumed != false, 'consumed', 'float')
|
||||
->checkFlow()
|
||||
->where('id')->eq($taskID)
|
||||
->exec();
|
||||
@@ -1955,6 +1945,7 @@ class taskModel extends model
|
||||
*/
|
||||
public function getByList($taskIDList = 0)
|
||||
{
|
||||
if(empty($taskIDList)) return array();
|
||||
return $this->dao->select('*')->from(TABLE_TASK)
|
||||
->where('deleted')->eq(0)
|
||||
->beginIF($taskIDList)->andWhere('id')->in($taskIDList)->fi()
|
||||
@@ -3339,7 +3330,14 @@ class taskModel extends model
|
||||
|
||||
$btnClass .= $task->assignedTo == 'closed' ? ' disabled' : '';
|
||||
$btnClass .= ' iframe btn btn-icon-left btn-sm';
|
||||
$assignToLink = $task->assignedTo == 'closed' ? '#' : helper::createLink('task', 'assignTo', "executionID=$task->execution&taskID=$task->id", '', true);
|
||||
if(!empty($task->team) and $task->mode == 'multi' and strpos('done,cencel,closed', $task->status) === false)
|
||||
{
|
||||
$assignToLink = $task->assignedTo == 'closed' ? '#' : helper::createLink('task', 'manageTeam', "executionID=$task->execution&taskID=$task->id", '', true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$assignToLink = $task->assignedTo == 'closed' ? '#' : helper::createLink('task', 'assignTo', "executionID=$task->execution&taskID=$task->id", '', true);
|
||||
}
|
||||
$assignToHtml = html::a($assignToLink, "<i class='icon icon-hand-right'></i> <span title='" . $assignedToTitle . "'>{$assignedToText}</span>", '', "class='$btnClass'");
|
||||
|
||||
echo !common::hasPriv('task', 'assignTo', $task) ? "<span style='padding-left: 21px' class='{$btnTextClass}'>{$assignedToText}</span>" : $assignToHtml;
|
||||
@@ -3918,6 +3916,7 @@ class taskModel extends model
|
||||
|
||||
/* If both of lane id and column id are not empty, add task to the kanban cell. */
|
||||
if($laneID and $columnID) $this->kanban->addKanbanCell($kanbanID, $laneID, $columnID, 'task', $task->id);
|
||||
|
||||
/* If lane id or column id is empty, update the task type lane of the kanban. */
|
||||
if(!$laneID or !$columnID) $this->kanban->updateLane($kanbanID, 'task');
|
||||
}
|
||||
|
||||
+1
-1
@@ -545,7 +545,7 @@ class taskTao extends taskModel
|
||||
}
|
||||
elseif($task->status == 'doing')
|
||||
{
|
||||
$teamSource = $teamSourceList[$row];
|
||||
$teamSource = zget($teamSourceList, $row);
|
||||
|
||||
if(!empty($teamSource) and $teamSource != $account and isset($undoneUsers[$teamSource])) $member->transfer = $teamSource;
|
||||
if(isset($undoneUsers[$account]) and ($mode == 'multi' or ($mode == 'linear' and $minStatus != 'wait'))) $member->status = 'doing';
|
||||
|
||||
Executable
+74
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/task.class.php';
|
||||
su('admin');
|
||||
|
||||
$task = zdTable('task');
|
||||
$task->id->range('1-4');
|
||||
$task->type->range('test,devel,design,story');
|
||||
$task->design->range('0{2},1,0{4}');
|
||||
$task->name->range('测试,开发,设计,需求')->postfix('任务1');
|
||||
$task->story->range('0{3},1');
|
||||
$task->status->range('wait');
|
||||
$task->gen(4);
|
||||
|
||||
$bug = zdTable('bug');
|
||||
$bug->id->range(1);
|
||||
$bug->product->range('1');
|
||||
$bug->title->range('Bug1');
|
||||
$bug->gen(1);
|
||||
|
||||
$todo = zdTable('todo');
|
||||
$todo->id->range(1);
|
||||
$todo->name->range('待办1');
|
||||
$todo->gen(1);
|
||||
|
||||
$design = zdTable('design');
|
||||
$design->id->range(1);
|
||||
$design->name->range('设计1');
|
||||
$design->gen(1);
|
||||
|
||||
$story = zdTable('story');
|
||||
$story->id->range('1-5');
|
||||
$story->product->range('1');
|
||||
$story->title->range('1-5')->prefix('需求');
|
||||
$story->type->range('story');
|
||||
$story->gen(5);
|
||||
|
||||
/**
|
||||
|
||||
title=测试taskModel->afterCreate();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
*/
|
||||
|
||||
$taskIdList['test'] = array(1);
|
||||
$taskIdList['todo'] = array(2);
|
||||
$taskIdList['design'] = array(3);
|
||||
$taskIdList['story'] = array(4);
|
||||
|
||||
$testTasks[2] = new stdclass();
|
||||
$testTasks[2]->name = '测试子任务1';
|
||||
$testTasks[2]->type = 'test';
|
||||
$testTasks[2]->mailto = '';
|
||||
|
||||
$testTasks[3] = new stdclass();
|
||||
$testTasks[3]->name = '测试子任务2';
|
||||
$testTasks[3]->type = 'test';
|
||||
$testTasks[3]->mailto = '';
|
||||
|
||||
$taskTester = new taskTest();
|
||||
r($taskTester->afterCreateTest()) && p() && e('0'); // 测试空数据
|
||||
r($taskTester->afterCreateTest(0, $taskIdList['test'])) && p() && e('0'); // 测试taskID为空的情况
|
||||
r($taskTester->afterCreateTest(5, $taskIdList['test'])) && p() && e('0'); // 测试taskID不存在的情况
|
||||
r($taskTester->afterCreateTest(1)) && p('name') && e('测试任务1'); // 测试taskIdList为空的情况
|
||||
r($taskTester->afterCreateTest(1, array(), 1)) && p('title') && e('Bug1'); // 测试taskIdList为空,但是有BugID的情况
|
||||
r($taskTester->afterCreateTest(1, array(), 0, 1)) && p('name') && e('待办1'); // 测试taskIdList为空,但是有todoID的情况
|
||||
r($taskTester->afterCreateTest(1, array(), 0, 0, $testTasks)) && p('name') && e('测试任务1'); // 测试taskIdList为空,但是有testTasks的情况
|
||||
r($taskTester->afterCreateTest(1, $taskIdList['test'], 1)) && p('toTask') && e('1'); // 测试Bug转任务后,更新Bug的信息
|
||||
r($taskTester->afterCreateTest(2, $taskIdList['todo'], 0, 1)) && p('status') && e('done'); // 测试待办转任务后,更新待办的信息
|
||||
r($taskTester->afterCreateTest(3, $taskIdList['design'])) && p('designVersion') && e('1'); // 测试任务关联设计后,更新任务中的designVersion字段
|
||||
r($taskTester->afterCreateTest(4, $taskIdList['story'])) && p('stage') && e('planned'); // 测试任务关联需求后,更新需求的阶段
|
||||
r($taskTester->afterCreateTest(1, $taskIdList['test'], 0, 0, $testTasks)) && p('parent') && e('-1'); // 测试任务创建子任务后,父任务的parent字段的值
|
||||
@@ -10,43 +10,41 @@ title=taskModel->assign();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 执行task模块的assign方法,参数是$taskIDlist[0],$waitTask
|
||||
- wait状态任务指派
|
||||
- 第0条的field属性 @assignedTo
|
||||
- 第0条的old属性 @old1
|
||||
- 第0条的new属性 @user92
|
||||
|
||||
- 执行task模块的assign方法,参数是$taskIDlist[0],$waitTaskLeft
|
||||
- wait状态任务指派修改预计剩余
|
||||
- 第1条的field属性 @left
|
||||
- 第1条的old属性 @0
|
||||
- 第1条的new属性 @1
|
||||
|
||||
- 执行task模块的assign方法,参数是$taskIDlist[1],$doingTask
|
||||
- doing状态任务指派
|
||||
- 第0条的field属性 @assignedTo
|
||||
- 第0条的old属性 @old2
|
||||
- 第0条的new属性 @user93
|
||||
|
||||
- 执行task模块的assign方法,参数是$taskIDlist[2],$doneTask
|
||||
- done状态任务指派
|
||||
- 第0条的field属性 @assignedTo
|
||||
- 第0条的old属性 @old3
|
||||
- 第0条的new属性 @user94
|
||||
|
||||
- 执行task模块的assign方法,参数是$taskIDlist[3],$pauseTask
|
||||
- pause状态任务指派
|
||||
- 第0条的field属性 @assignedTo
|
||||
- 第0条的old属性 @old4
|
||||
- 第0条的new属性 @user95
|
||||
|
||||
- 执行task模块的assign方法,参数是$taskIDlist[4],$cancelTask
|
||||
- cancel状态任务指派
|
||||
- 第0条的field属性 @assignedTo
|
||||
- 第0条的old属性 @old5
|
||||
- 第0条的new属性 @user96
|
||||
|
||||
- 执行task模块的assign方法,参数是$taskIDlist[5],$closedTask
|
||||
- closed状态任务指派
|
||||
- 第0条的field属性 @assignedTo
|
||||
- 第0条的old属性 @old6
|
||||
- 第0条的new属性 @user97
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
function initData()
|
||||
@@ -87,4 +85,4 @@ r($task->assignTest($taskIDlist[1],$doingTask)) && p('0:field,old,new') && e('a
|
||||
r($task->assignTest($taskIDlist[2],$doneTask)) && p('0:field,old,new') && e('assignedTo,old3,user94'); // done状态任务指派
|
||||
r($task->assignTest($taskIDlist[3],$pauseTask)) && p('0:field,old,new') && e('assignedTo,old4,user95'); // pause状态任务指派
|
||||
r($task->assignTest($taskIDlist[4],$cancelTask)) && p('0:field,old,new') && e('assignedTo,old5,user96'); // cancel状态任务指派
|
||||
r($task->assignTest($taskIDlist[5],$closedTask)) && p('0:field,old,new') && e('assignedTo,old6,user97'); // closed状态任务指派
|
||||
r($task->assignTest($taskIDlist[5],$closedTask)) && p('0:field,old,new') && e('assignedTo,old6,user97'); // closed状态任务指派
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/task.class.php';
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=taskModel->updateTeam();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 分配2个成员团队后任务
|
||||
- 第1条的field属性 @estimate
|
||||
- 第1条的old属性 @0
|
||||
- 第1条的new属性 @3.5
|
||||
|
||||
- 分配1个成员团队后任务
|
||||
- 第1条的field属性 @mode
|
||||
- 第1条的old属性 @multi
|
||||
- 第1条的new属性 @~~
|
||||
|
||||
- 分配预计剩余为0工时团队后任务 @总计消耗"和"预计剩余"不能同时为0
|
||||
|
||||
*/
|
||||
|
||||
function initData()
|
||||
{
|
||||
$task = zdTable('task');
|
||||
$task->mode->range('multi');
|
||||
$task->gen(6);
|
||||
|
||||
$user = zdTable('user')->gen(50);
|
||||
}
|
||||
|
||||
initData();
|
||||
$taskIDList = array('1','2','3','4','5','6');
|
||||
$taskStatusList = array('doing','wait','done');
|
||||
$teamList = array('user1','user2','user3');
|
||||
|
||||
$task = new taskTest();
|
||||
r($task->updateTeamTest($taskIDList[0], $taskStatusList[1], array($teamList[0], $teamList[1]), array($teamList[0], $teamList[1]), $teamEstimateList = array(1, 2.5), $teamConsumedList = array(0, 0), $teamLeftList = array(1, 0.5))) && p('1:field,old,new') && e('estimate,0,3.5'); //分配2个成员团队后任务
|
||||
r($task->updateTeamTest($taskIDList[1], $taskStatusList[1], array($teamList[0]), array($teamList[0]), $teamEstimateList = array(1), $teamConsumedList = array(0), $teamLeftList = array(1))) && p('1:field,old,new') && e('mode,multi,~~'); //分配1个成员团队后任务
|
||||
r($task->updateTeamTest($taskIDList[2], $taskStatusList[1], array($teamList[0], $teamList[1]), array($teamList[0], $teamList[1]), $teamEstimateList = array(1, 2.5), $teamConsumedList = array(0, 0), $teamLeftList = array(0, 0))) && p() && e('"总计消耗"和"预计剩余"不能同时为0'); //分配预计剩余为0工时团队后任务
|
||||
@@ -19,6 +19,16 @@ title=taskModel->batchComputeProgress();
|
||||
timeout=0
|
||||
cid=2
|
||||
|
||||
sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory
|
||||
- 测试任务消耗工时为0,剩余工时为0的情况第1条的progress属性 @0
|
||||
|
||||
- 测试任务消耗工时不为0,剩余工时为0的情况第2条的progress属性 @100
|
||||
|
||||
- 测试任务消耗工时为15,剩余工时为1的情况第3条的progress属性 @94
|
||||
|
||||
- 测试任务消耗工时为20,剩余工时为5的情况第4条的progress属性 @80
|
||||
|
||||
- 测试任务消耗工时为25,剩余工时为10的情况第5条的progress属性 @71
|
||||
|
||||
*/
|
||||
$tester->loadModel('task');
|
||||
@@ -32,4 +42,4 @@ r($tester->task->batchComputeProgress($taskList)) && p('1:progress') && e('0');
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('2:progress') && e('100'); // 测试任务消耗工时不为0,剩余工时为0的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('3:progress') && e('94'); // 测试任务消耗工时为15,剩余工时为1的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('4:progress') && e('80'); // 测试任务消耗工时为20,剩余工时为5的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('5:progress') && e('71'); // 测试任务消耗工时为25,剩余工时为10的情况
|
||||
r($tester->task->batchComputeProgress($taskList)) && p('5:progress') && e('71'); // 测试任务消耗工时为25,剩余工时为10的情况
|
||||
@@ -22,6 +22,25 @@ title=taskModel->buildTaskTree();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory
|
||||
- 测试空数据的情况 @0
|
||||
|
||||
- 测试数据中有父任务时,重构结构后的任务数量 @6
|
||||
|
||||
- 测试数据中有父任务时,重构结构后子任务的数据第children[4]条的name属性 @子任务4
|
||||
|
||||
- 测试数据中没有父任务时,重构结构后的任务数量 @6
|
||||
|
||||
- 测试数据中没有父任务时,重构结构后的子任务中父任务的名称第4条的parentName属性 @父任务1
|
||||
|
||||
- 测试数据中有父子任务时,重构结构后的子任务中父任务的名称第1条的name属性 @父任务1
|
||||
|
||||
- 测试数据中有父子任务时,重构结构后的任务数量 @2
|
||||
|
||||
- 测试数据中只有父任务时,重构结构后的父任务的名称第1条的name属性 @父任务1
|
||||
|
||||
- 测试数据中只有父任务时,重构结构后的任务数量 @3
|
||||
|
||||
*/
|
||||
|
||||
$taskTester = new taskTest();
|
||||
@@ -49,4 +68,4 @@ r($notParentTasks) && p('4:parentName') && e('父任务1'); // 测试
|
||||
r($hasParentTasks) && p('1:name') && e('父任务1'); // 测试数据中有父子任务时,重构结构后的子任务中父任务的名称
|
||||
r($hasParentTasksCount) && p() && e('2'); // 测试数据中有父子任务时,重构结构后的任务数量
|
||||
r($parentTasks) && p('1:name') && e('父任务1'); // 测试数据中只有父任务时,重构结构后的父任务的名称
|
||||
r($parentTasksCount) && p() && e('3'); // 测试数据中只有父任务时,重构结构后的任务数量
|
||||
r($parentTasksCount) && p() && e('3'); // 测试数据中只有父任务时,重构结构后的任务数量
|
||||
@@ -65,92 +65,91 @@ title=taskModel->computeCurrentTaskStatus();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 执行$task1
|
||||
sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory
|
||||
- 查询 task1 情况的task信息 currentTask[0] taskID 1 currentTasksestimate 状态自动变更 没有工时消耗 团队成员members[0]
|
||||
- 属性status @doing
|
||||
- 属性assignedTo @user1
|
||||
- 属性estimate @9
|
||||
- 属性left @0
|
||||
- 属性consumed @10
|
||||
|
||||
- 执行$task2
|
||||
- 查询 task2 情况的task信息 currentTask[0] taskID 1 currentTasksestimate 状态自动变更 没有工时消耗 团队成员members[0]
|
||||
- 属性status @doing
|
||||
- 属性assignedTo @user1
|
||||
- 属性estimate @9
|
||||
- 属性left @0
|
||||
- 属性consumed @10
|
||||
|
||||
- 执行$task3
|
||||
- 查询 task3 情况的task信息 currentTask[0] taskID 1 currentTasksestimate 状态自动变更 没有工时消耗 团队成员members[0]
|
||||
- 属性status @doing
|
||||
- 属性assignedTo @user1
|
||||
- 属性estimate @9
|
||||
- 属性left @0
|
||||
- 属性consumed @10
|
||||
|
||||
- 执行$task4
|
||||
- 查询 task4 情况的task信息 currentTask[0] taskID 1 currentTasksestimate 状态非自动变更 没有工时消耗 团队成员members[0]
|
||||
- 属性status @doing
|
||||
- 属性assignedTo @user1
|
||||
- 属性estimate @9
|
||||
- 属性left @0
|
||||
- 属性consumed @10
|
||||
|
||||
- 执行$task5
|
||||
- 查询 task5 情况的task信息 currentTask[0] taskID 1 currentTasksestimate 状态非自动变更 有工时消耗 团队成员members[0]
|
||||
- 属性status @doing
|
||||
- 属性assignedTo @user1
|
||||
- 属性estimate @9
|
||||
- 属性left @0
|
||||
- 属性consumed @10
|
||||
|
||||
- 执行$task6
|
||||
- 查询 task6 情况的task信息 currentTask[0] taskID 1 currentTasksestimate 状态非自动变更 有工时消耗 团队成员members[1]
|
||||
- 属性status @doing
|
||||
- 属性assignedTo @user1
|
||||
- 属性estimate @9
|
||||
- 属性left @0
|
||||
- 属性consumed @10
|
||||
|
||||
- 执行$task7
|
||||
- 查询 task7 情况的task信息 currentTask[1] taskID 2 currentTasksestimate 状态自动变更 有工时消耗 团队成员members[0]
|
||||
- 属性status @done
|
||||
- 属性assignedTo @admin
|
||||
- 属性estimate @8
|
||||
- 属性left @8
|
||||
- 属性consumed @0
|
||||
|
||||
- 执行$task8
|
||||
- 查询 task8 情况的task信息 currentTask[1] taskID 2 currentTasksestimate 状态自动变更 有工时消耗 团队成员members[0]
|
||||
- 属性status @done
|
||||
- 属性assignedTo @admin
|
||||
- 属性estimate @8
|
||||
- 属性left @8
|
||||
- 属性consumed @0
|
||||
|
||||
- 执行$task9
|
||||
- 查询 task9 情况的task信息 currentTask[1] taskID 2 currentTasksestimate 状态自动变更 有工时消耗 团队成员members[0]
|
||||
- 属性status @done
|
||||
- 属性assignedTo @admin
|
||||
- 属性estimate @8
|
||||
- 属性left @8
|
||||
- 属性consumed @0
|
||||
|
||||
- 执行$task10
|
||||
- 查询 task10 情况的task信息 currentTask[1] taskID 2 currentTasksestimate 状态非自动变更 有工时消耗 团队成员members[0]
|
||||
- 属性status @done
|
||||
- 属性assignedTo @admin
|
||||
- 属性estimate @8
|
||||
- 属性left @8
|
||||
- 属性consumed @0
|
||||
|
||||
- 执行$task11
|
||||
- 查询 task11 情况的task信息 currentTask[1] taskID 2 currentTasksestimate 状态非自动变更 没有工时消耗 团队成员members[0]
|
||||
- 属性status @done
|
||||
- 属性assignedTo @admin
|
||||
- 属性estimate @8
|
||||
- 属性left @8
|
||||
- 属性consumed @0
|
||||
|
||||
- 执行$task12
|
||||
- 查询 task12 情况的task信息 currentTask[1] taskID 2 currentTasksestimate 状态非自动变更 没有工时消耗 团队成员members[1]
|
||||
- 属性status @done
|
||||
- 属性assignedTo @admin
|
||||
- 属性estimate @8
|
||||
- 属性left @8
|
||||
- 属性consumed @0
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
$task = new taskTest();
|
||||
|
||||
@@ -16,8 +16,20 @@ function initData()
|
||||
/**
|
||||
|
||||
title=测试computeTaskProgress
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory
|
||||
- 测试任务消耗工时为0,剩余工时为0的情况 @0
|
||||
|
||||
- 测试任务消耗工时不为0,剩余工时为0的情况 @100
|
||||
|
||||
- 测试任务消耗工时为15,剩余工时为1的情况 @94
|
||||
|
||||
- 测试任务消耗工时为20,剩余工时为5的情况 @80
|
||||
|
||||
- 测试任务消耗工时为25,剩余工时为10的情况 @71
|
||||
|
||||
*/
|
||||
initData();
|
||||
|
||||
@@ -30,4 +42,4 @@ r($tester->task->computeTaskProgress($taskList[1])) && p() && e('0'); //测试
|
||||
r($tester->task->computeTaskProgress($taskList[2])) && p() && e('100'); //测试任务消耗工时不为0,剩余工时为0的情况
|
||||
r($tester->task->computeTaskProgress($taskList[3])) && p() && e('94'); //测试任务消耗工时为15,剩余工时为1的情况
|
||||
r($tester->task->computeTaskProgress($taskList[4])) && p() && e('80'); //测试任务消耗工时为20,剩余工时为5的情况
|
||||
r($tester->task->computeTaskProgress($taskList[5])) && p() && e('71'); //测试任务消耗工时为25,剩余工时为10的情况
|
||||
r($tester->task->computeTaskProgress($taskList[5])) && p() && e('71'); //测试任务消耗工时为25,剩余工时为10的情况
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user