diff --git a/Dockerfile.test b/Dockerfile.test index 03cef88a60..fe9f782e05 100644 --- a/Dockerfile.test +++ b/Dockerfile.test @@ -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 diff --git a/Jenkinsfile b/Jenkinsfile index 4a98a87a2f..c9d074c160 100755 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -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' diff --git a/lib/zin/wg/history/css/v1.css b/lib/zin/wg/history/css/v1.css index 38a6ccf1fe..fd3640341f 100644 --- a/lib/zin/wg/history/css/v1.css +++ b/lib/zin/wg/history/css/v1.css @@ -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 { diff --git a/lib/zin/wg/history/v1.php b/lib/zin/wg/history/v1.php index ac7c2c8a7e..5adebdd95f 100644 --- a/lib/zin/wg/history/v1.php +++ b/lib/zin/wg/history/v1.php @@ -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, '
'))
         {
@@ -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(<<switchDisplay),
+            set::icon('plus'),
+            on::click(<<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(<<switchDisplay),
-                    h::i(setClass('icon icon-plus icon-sm')),
-                    on::click(<<action->create)
-                ),
+                $this->reverseBtn(),
+                $this->expandAllBtn(),
+                $this->commentBtn(),
             ),
-            div(setClass('detail-content'), $this->buildHistoriesList())
+            div(setClass('detail-content'), $this->historyList())
         );
     }
 }
diff --git a/module/block/css/productstatisticblock.ui.css b/module/block/css/productstatisticblock.ui.css
new file mode 100644
index 0000000000..c753cbc820
--- /dev/null
+++ b/module/block/css/productstatisticblock.ui.css
@@ -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;}
diff --git a/module/block/model.php b/module/block/model.php
index 32764c870f..00fa2e5e46 100644
--- a/module/block/model.php
+++ b/module/block/model.php
@@ -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;
     }
 
     /**
diff --git a/module/block/test/model/appendcountparams.php b/module/block/test/model/appendcountparams.php
deleted file mode 100755
index 090fd5968c..0000000000
--- a/module/block/test/model/appendcountparams.php
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env php
-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 空
\ No newline at end of file
diff --git a/module/block/test/model/checkapi.php b/module/block/test/model/checkapi.php
index a04fa668ba..6997cd7526 100755
--- a/module/block/test/model/checkapi.php
+++ b/module/block/test/model/checkapi.php
@@ -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'); // 测试错误的哈希值
\ No newline at end of file
diff --git a/module/block/test/model/create.php b/module/block/test/model/create.php
index 9fbb185e38..a5aa0776a4 100755
--- a/module/block/test/model/create.php
+++ b/module/block/test/model/create.php
@@ -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 字段字符超出长度
\ No newline at end of file
diff --git a/module/block/test/model/getassigntomeparams.php b/module/block/test/model/getassigntomeparams.php
deleted file mode 100755
index e82aeaf37a..0000000000
--- a/module/block/test/model/getassigntomeparams.php
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env php
-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'); // 获取当前登陆用户需求的默认参数
\ No newline at end of file
diff --git a/module/block/test/model/getavailableblocks.php b/module/block/test/model/getavailableblocks.php
index f2f24d5364..ae639c4363 100755
--- a/module/block/test/model/getavailableblocks.php
+++ b/module/block/test/model/getavailableblocks.php
@@ -9,9 +9,6 @@ title=测试 blockModel->getAvailableBlocks();
 cid=1
 pid=1
 
-通过获取项目的可用区块 >> 项目计划,最新动态
-通过获取测试的可用区块 >> 测试统计,Bug列表,用例列表,版本列表
-
 */
 
 $block = new blockTest();
diff --git a/module/block/test/model/getblock.php b/module/block/test/model/getblock.php
deleted file mode 100755
index 68c8c45db3..0000000000
--- a/module/block/test/model/getblock.php
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env php
-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的区块
\ No newline at end of file
diff --git a/module/block/test/model/getblocklist.php b/module/block/test/model/getblocklist.php
deleted file mode 100755
index 64cc7240ef..0000000000
--- a/module/block/test/model/getblocklist.php
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env php
-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('项目计划;最新计划');
\ No newline at end of file
diff --git a/module/block/test/model/getbugparams.php b/module/block/test/model/getbugparams.php
deleted file mode 100755
index 338a2c3bf8..0000000000
--- a/module/block/test/model/getbugparams.php
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env php
-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区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getbuildparams.php b/module/block/test/model/getbuildparams.php
deleted file mode 100755
index 39e03c683d..0000000000
--- a/module/block/test/model/getbuildparams.php
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env php
-getBuildParams();
-cid=1
-pid=1
-
-测试获取版本区块参数 >> 数量,20,input
-
-*/
-
-$block = new blockTest();
-$data = $block->getBuildParamsTest();
-
-r($data) && p('count:name,default,control') && e('数量,20,input'); //测试获取版本区块参数
\ No newline at end of file
diff --git a/module/block/test/model/getbyid.php b/module/block/test/model/getbyid.php
index c91889a9ad..b1bbbba46a 100755
--- a/module/block/test/model/getbyid.php
+++ b/module/block/test/model/getbyid.php
@@ -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的内容
\ No newline at end of file
diff --git a/module/block/test/model/getcaseparams.php b/module/block/test/model/getcaseparams.php
deleted file mode 100755
index 334fe013cc..0000000000
--- a/module/block/test/model/getcaseparams.php
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env php
-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('数量;类型;排序'); //测试通过模块获取用例区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getexecutionparams.php b/module/block/test/model/getexecutionparams.php
deleted file mode 100755
index 5c80eab9ae..0000000000
--- a/module/block/test/model/getexecutionparams.php
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env php
-getExecutionParams();
-cid=1
-pid=1
-
-测试获取执行区块的参数 >> 数量;类型
-
-*/
-
-$block = new blockTest();
-$data = $block->getExecutionParamsTest();
-
-r($data) && p('count:name;type:name') && e('数量;类型'); //测试获取执行区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getexecutionstatisticparams.php b/module/block/test/model/getexecutionstatisticparams.php
deleted file mode 100755
index 183de9b9ea..0000000000
--- a/module/block/test/model/getexecutionstatisticparams.php
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env php
-getExecutionStatisticParams();
-cid=1
-pid=1
-
-测试获取执行区块的参数 >> 数量;类型
-
-*/
-
-$block = new blockTest();
-$data = $block->getExecutionStatisticParamsTest();
-
-r($data) && p('count:name;type:name') && e('数量;类型'); //测试获取执行区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/gethiddenblocks.php b/module/block/test/model/gethiddenblocks.php
deleted file mode 100755
index e8a222fc1c..0000000000
--- a/module/block/test/model/gethiddenblocks.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-getHiddenBlocks();
-cid=1
-pid=1
-
-测试获取隐藏的区块 >> 未获取到隐藏的区块
-
-*/
-
-$block = new blockTest();
-
-r($block->getHiddenBlocksTest('my')) && p('message') && e('未获取到隐藏的区块'); //测试获取隐藏的区块
\ No newline at end of file
diff --git a/module/block/test/model/getlastkey.php b/module/block/test/model/getlastkey.php
deleted file mode 100755
index 4593256e0e..0000000000
--- a/module/block/test/model/getlastkey.php
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env php
-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
\ No newline at end of file
diff --git a/module/block/test/model/getlistparams.php b/module/block/test/model/getlistparams.php
deleted file mode 100755
index 48799a7461..0000000000
--- a/module/block/test/model/getlistparams.php
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env php
-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('数量;类型;排序'); //测试通过模块获取区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getmaxorderbydashboard.php b/module/block/test/model/getmaxorderbydashboard.php
index 0c47617e4b..47478b0327 100644
--- a/module/block/test/model/getmaxorderbydashboard.php
+++ b/module/block/test/model/getmaxorderbydashboard.php
@@ -2,20 +2,19 @@
 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
diff --git a/module/block/test/model/getmydashboard.php b/module/block/test/model/getmydashboard.php
index eea65dad87..6934c8ca41 100644
--- a/module/block/test/model/getmydashboard.php
+++ b/module/block/test/model/getmydashboard.php
@@ -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属性
diff --git a/module/block/test/model/getplanparams.php b/module/block/test/model/getplanparams.php
deleted file mode 100755
index d4f4ebd7a4..0000000000
--- a/module/block/test/model/getplanparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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"}}'); // 获取计划参数
\ No newline at end of file
diff --git a/module/block/test/model/getproductparams.php b/module/block/test/model/getproductparams.php
deleted file mode 100755
index 92455e2fbb..0000000000
--- a/module/block/test/model/getproductparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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};'); // 获取产品区块的参数
diff --git a/module/block/test/model/getproductstatisticparams.php b/module/block/test/model/getproductstatisticparams.php
deleted file mode 100755
index 9d1057dfd9..0000000000
--- a/module/block/test/model/getproductstatisticparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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};'); // 获取产品统计区块的参数
diff --git a/module/block/test/model/getprojectdynamicparams.php b/module/block/test/model/getprojectdynamicparams.php
deleted file mode 100755
index cc326b7f07..0000000000
--- a/module/block/test/model/getprojectdynamicparams.php
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env php
-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};'); // 获取项目动态区块参数
diff --git a/module/block/test/model/getprojectparams.php b/module/block/test/model/getprojectparams.php
deleted file mode 100755
index 016f529b9c..0000000000
--- a/module/block/test/model/getprojectparams.php
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env php
-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"}}'); //获取计划参数
diff --git a/module/block/test/model/getprojectstatisticparams.php b/module/block/test/model/getprojectstatisticparams.php
deleted file mode 100755
index 55ec0f0e0f..0000000000
--- a/module/block/test/model/getprojectstatisticparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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
\ No newline at end of file
diff --git a/module/block/test/model/getprojectteamparams.php b/module/block/test/model/getprojectteamparams.php
deleted file mode 100755
index 777d55fd01..0000000000
--- a/module/block/test/model/getprojectteamparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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};'); // 测试获取项目团队
diff --git a/module/block/test/model/getqastatisticparams.php b/module/block/test/model/getqastatisticparams.php
deleted file mode 100755
index 72fb78ce21..0000000000
--- a/module/block/test/model/getqastatisticparams.php
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env php
-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
\ No newline at end of file
diff --git a/module/block/test/model/getreleaseparams.php b/module/block/test/model/getreleaseparams.php
deleted file mode 100755
index 385d928357..0000000000
--- a/module/block/test/model/getreleaseparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-getReleaseParams();
-cid=1
-pid=1
-
-测试name >> 数量,20,input
-
-*/
-
-$block = new blockTest();
-
-r($block->getReleaseParamsTest()) && p('name,default,control') && e('数量,20,input');  //测试name
\ No newline at end of file
diff --git a/module/block/test/model/getscrumlistparams.php b/module/block/test/model/getscrumlistparams.php
deleted file mode 100755
index 09bf516922..0000000000
--- a/module/block/test/model/getscrumlistparams.php
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env php
-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
\ No newline at end of file
diff --git a/module/block/test/model/getscrumproductparams.php b/module/block/test/model/getscrumproductparams.php
deleted file mode 100755
index fff6bf6faf..0000000000
--- a/module/block/test/model/getscrumproductparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-getScrumProductParams();
-cid=1
-pid=1
-
-测试获取产品区块的参数 >> 数量;20;input
-
-*/
-
-$block = new blockTest();
-
-r($block->getScrumProductParamsTest()) && p('count:name;count:default;count:control') && e('数量;20;input'); // 测试获取产品区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getscrumroadmapparams.php b/module/block/test/model/getscrumroadmapparams.php
deleted file mode 100755
index a35c36473e..0000000000
--- a/module/block/test/model/getscrumroadmapparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-getScrumRoadMapParams();
-cid=1
-pid=1
-
-测试获取产品路线图区块的参数 >> 0
-
-*/
-
-$block = new blockTest();
-
-r($block->getScrumRoadMapParamsTest()) && p() && e('0'); // 测试获取产品路线图区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getscrumtestparams.php b/module/block/test/model/getscrumtestparams.php
deleted file mode 100755
index cdcc4d675b..0000000000
--- a/module/block/test/model/getscrumtestparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-getScrumTestParams();
-cid=1
-pid=1
-
-测试获取测试单区块的参数 >> 数量;类型
-
-*/
-
-$block = new blockTest();
-
-r($block->getScrumTestParamsTest()) && p('count:name;type:name') && e('数量;类型'); // 测试获取测试单区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getstatisticparams.php b/module/block/test/model/getstatisticparams.php
deleted file mode 100755
index 7d3e20ee94..0000000000
--- a/module/block/test/model/getstatisticparams.php
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/usr/bin/env php
-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"}}');  // 获取测试区块的参数
\ No newline at end of file
diff --git a/module/block/test/model/getstoryparams.php b/module/block/test/model/getstoryparams.php
deleted file mode 100755
index 05e4c1c985..0000000000
--- a/module/block/test/model/getstoryparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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"}}'); // 获取需求的参数
\ No newline at end of file
diff --git a/module/block/test/model/getstorysestimatehours.php b/module/block/test/model/getstorysestimatehours.php
deleted file mode 100755
index affb340cfa..0000000000
--- a/module/block/test/model/getstorysestimatehours.php
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env php
-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 的预计工时
\ No newline at end of file
diff --git a/module/block/test/model/gettaskparams.php b/module/block/test/model/gettaskparams.php
deleted file mode 100755
index 5cdbe3e02f..0000000000
--- a/module/block/test/model/gettaskparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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的参数
\ No newline at end of file
diff --git a/module/block/test/model/gettesttaskparams.php b/module/block/test/model/gettesttaskparams.php
deleted file mode 100755
index 4e48a6d40f..0000000000
--- a/module/block/test/model/gettesttaskparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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参数
\ No newline at end of file
diff --git a/module/block/test/model/gettodoparams.php b/module/block/test/model/gettodoparams.php
deleted file mode 100755
index 7ca72385eb..0000000000
--- a/module/block/test/model/gettodoparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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参数
\ No newline at end of file
diff --git a/module/block/test/model/getwaterfallissueparams.php b/module/block/test/model/getwaterfallissueparams.php
deleted file mode 100755
index d026af32e5..0000000000
--- a/module/block/test/model/getwaterfallissueparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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的参数
\ No newline at end of file
diff --git a/module/block/test/model/getwaterfallriskparams.php b/module/block/test/model/getwaterfallriskparams.php
deleted file mode 100755
index 9139370692..0000000000
--- a/module/block/test/model/getwaterfallriskparams.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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 参数
\ No newline at end of file
diff --git a/module/block/test/model/getwelcomeblockdata.php b/module/block/test/model/getwelcomeblockdata.php
deleted file mode 100755
index 8e182242ae..0000000000
--- a/module/block/test/model/getwelcomeblockdata.php
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env php
-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}'); // 获取欢迎区块的数据
diff --git a/module/block/test/model/initblock.php b/module/block/test/model/initblock.php
index f2438b194a..ad213dee25 100755
--- a/module/block/test/model/initblock.php
+++ b/module/block/test/model/initblock.php
@@ -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的内容
diff --git a/module/block/test/model/islongblock.php b/module/block/test/model/islongblock.php
index 713a79b38c..7f6c32e76c 100755
--- a/module/block/test/model/islongblock.php
+++ b/module/block/test/model/islongblock.php
@@ -2,35 +2,46 @@
 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 的时候 检查是否为长区块
\ No newline at end of file
+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'); // 测试 空 对象 检查是否为长区块
\ No newline at end of file
diff --git a/module/block/test/model/save.php b/module/block/test/model/save.php
deleted file mode 100755
index 7857008401..0000000000
--- a/module/block/test/model/save.php
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env php
-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 变量
diff --git a/module/block/test/model/update.php b/module/block/test/model/update.php
index a45e8a26f8..abfbd75d78 100644
--- a/module/block/test/model/update.php
+++ b/module/block/test/model/update.php
@@ -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 字段字符超出长度
\ No newline at end of file
diff --git a/module/block/test/tao/fetchmyblocks.php b/module/block/test/tao/fetchmyblocks.php
new file mode 100644
index 0000000000..15b3eff80f
--- /dev/null
+++ b/module/block/test/tao/fetchmyblocks.php
@@ -0,0 +1,34 @@
+#!/usr/bin/env php
+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属性
diff --git a/module/block/ui/productstatisticblock.html.php b/module/block/ui/productstatisticblock.html.php
new file mode 100644
index 0000000000..8cdcdc66f1
--- /dev/null
+++ b/module/block/ui/productstatisticblock.html.php
@@ -0,0 +1,289 @@
+
+* @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();
diff --git a/module/block/ui/projectstatisticblock.html.php b/module/block/ui/projectstatisticblock.html.php
index 96a93ba55e..01e7b99a49 100644
--- a/module/block/ui/projectstatisticblock.html.php
+++ b/module/block/ui/projectstatisticblock.html.php
@@ -1,7 +1,7 @@
 
@@ -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();
diff --git a/module/block/ui/recentprojectblock.html.php b/module/block/ui/recentprojectblock.html.php
index 2e6d548b57..1e32c9fe2f 100644
--- a/module/block/ui/recentprojectblock.html.php
+++ b/module/block/ui/recentprojectblock.html.php
@@ -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'),
diff --git a/module/block/zen.php b/module/block/zen.php
index 40cc9bcf61..fd370c665a 100644
--- a/module/block/zen.php
+++ b/module/block/zen.php
@@ -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'] = '[';
diff --git a/module/bug/tao.php b/module/bug/tao.php
index 4cccf81dc0..b9248ff9b2 100644
--- a/module/bug/tao.php
+++ b/module/bug/tao.php
@@ -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();
diff --git a/module/bug/test/bug.class.php b/module/bug/test/bug.class.php
index 084419b479..d494431892 100644
--- a/module/bug/test/bug.class.php
+++ b/module/bug/test/bug.class.php
@@ -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;
+    }
 }
diff --git a/module/bug/test/model/update.php b/module/bug/test/model/update.php
index a2601b1843..2c977226b4 100755
--- a/module/bug/test/model/update.php
+++ b/module/bug/test/model/update.php
@@ -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类型
\ No newline at end of file
+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('『解决版本』不能为空。');          // 测试解决方案为已修复时,不输入解决版本
\ No newline at end of file
diff --git a/module/bug/test/tao/data/bug_updatelinkbug.yaml b/module/bug/test/tao/data/bug_updatelinkbug.yaml
new file mode 100644
index 0000000000..ce1e65fe58
--- /dev/null
+++ b/module/bug/test/tao/data/bug_updatelinkbug.yaml
@@ -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: '[

【步骤】


【结果】


【期望】


,【步骤】进入成果展示
【结果】乱码
【期望】正常显示
]' +- 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} +... diff --git a/module/bug/test/tao/data/sql/bug.sql b/module/bug/test/tao/data/sql/bug.sql new file mode 100644 index 0000000000..be592d58e5 --- /dev/null +++ b/module/bug/test/tao/data/sql/bug.sql @@ -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 diff --git a/module/bug/test/tao/data/sql/zt_bug_zd.sql b/module/bug/test/tao/data/sql/zt_bug_zd.sql new file mode 100755 index 0000000000..0d06c4e5ee --- /dev/null +++ b/module/bug/test/tao/data/sql/zt_bug_zd.sql @@ -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', '', '', '', '', '

【步骤】


【结果】


【期望】


', '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', '', '', '', '', '【步骤】进入成果展示
【结果】乱码
【期望】正常显示
', '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', '', '', '', '

【步骤】


【结果】


【期望】


', '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', '', '', '', '【步骤】进入成果展示
【结果】乱码
【期望】正常显示
', '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', '', '', '', '

【步骤】


【结果】


【期望】


', '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'); diff --git a/module/bug/test/tao/updatelinkbug.php b/module/bug/test/tao/updatelinkbug.php new file mode 100755 index 0000000000..08ceaa8daa --- /dev/null +++ b/module/bug/test/tao/updatelinkbug.php @@ -0,0 +1,53 @@ +#!/usr/bin/env php +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 \ No newline at end of file diff --git a/module/bug/zen.php b/module/bug/zen.php index 4a7af9d80a..2f3f1fc993 100644 --- a/module/bug/zen.php +++ b/module/bug/zen.php @@ -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; diff --git a/module/doc/control.php b/module/doc/control.php index 78b9c1a7f8..ec3b3eb75d 100755 --- a/module/doc/control.php +++ b/module/doc/control.php @@ -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; diff --git a/module/doc/model.php b/module/doc/model.php index 70a4125ddb..e627fc8987 100644 --- a/module/doc/model.php +++ b/module/doc/model.php @@ -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'); diff --git a/module/product/config.php b/module/product/config.php index 5d397e6828..9740d97fb5 100644 --- a/module/product/config.php +++ b/module/product/config.php @@ -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'); diff --git a/module/product/control.php b/module/product/control.php index 57ac7e293a..f1b07d3c7d 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -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'), " " . $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); diff --git a/module/product/model.php b/module/product/model.php index d50484f001..6f5e348fc5 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -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 = "
"; - if($isMobile) $output = "{$currentProduct->name} "; - - 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 .= "
"; - } - else - { - $output .= "{$branchName} "; - } - } - - if(!$isMobile) $output .= '
'; - } - - 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 = "
"; - - $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 .= "
"; - } - } + $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]); } } diff --git a/module/product/tao.php b/module/product/tao.php index 76d4c5ba05..d6cfcc22aa 100644 --- a/module/product/tao.php +++ b/module/product/tao.php @@ -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 = "
"; + 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 .= "id}', '$currentModule', '$currentMethod', '$extra')\">{$branchName} "; + + 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 = "{$currentProduct->name} "; + + /* 处理分支。根据条件,判断是否追加分支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); + } } diff --git a/module/product/test/model/checkpriv.php b/module/product/test/model/checkpriv.php index f0457e9869..de52781c13 100755 --- a/module/product/test/model/checkpriv.php +++ b/module/product/test/model/checkpriv.php @@ -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能否看到不存在的产品 diff --git a/module/product/test/model/getmobiledropmenu.php b/module/product/test/model/getmobiledropmenu.php new file mode 100755 index 0000000000..0f01bcb62d --- /dev/null +++ b/module/product/test/model/getmobiledropmenu.php @@ -0,0 +1,38 @@ +#!/usr/bin/env php +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'); diff --git a/module/product/test/model/getroadmap.php b/module/product/test/model/getroadmap.php index c94dc12fb9..0c688908c9 100755 --- a/module/product/test/model/getroadmap.php +++ b/module/product/test/model/getroadmap.php @@ -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数量 diff --git a/module/product/test/model/getswitcher.php b/module/product/test/model/getswitcher.php new file mode 100755 index 0000000000..2a0ef6a0be --- /dev/null +++ b/module/product/test/model/getswitcher.php @@ -0,0 +1,34 @@ +#!/usr/bin/env php +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'); + diff --git a/module/product/test/model/setmenu.php b/module/product/test/model/setmenu.php new file mode 100755 index 0000000000..f3ff3b1e53 --- /dev/null +++ b/module/product/test/model/setmenu.php @@ -0,0 +1,25 @@ +#!/usr/bin/env php +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'); diff --git a/module/product/test/product.class.php b/module/product/test/product.class.php index 085c6364cc..98875227fd 100644 --- a/module/product/test/product.class.php +++ b/module/product/test/product.class.php @@ -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); + } } diff --git a/module/product/test/tao/buildselect4mobile.php b/module/product/test/tao/buildselect4mobile.php new file mode 100755 index 0000000000..d8bdc27fac --- /dev/null +++ b/module/product/test/tao/buildselect4mobile.php @@ -0,0 +1,52 @@ +#!/usr/bin/env php +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'); diff --git a/module/product/test/tao/computelocate4dropmenu.php b/module/product/test/tao/computelocate4dropmenu.php new file mode 100755 index 0000000000..d62e716ab5 --- /dev/null +++ b/module/product/test/tao/computelocate4dropmenu.php @@ -0,0 +1,54 @@ +#!/usr/bin/env php +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'); diff --git a/module/product/test/tao/getbranchselect4mobile.php b/module/product/test/tao/getbranchselect4mobile.php new file mode 100755 index 0000000000..ca283b12f1 --- /dev/null +++ b/module/product/test/tao/getbranchselect4mobile.php @@ -0,0 +1,32 @@ +#!/usr/bin/env php +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'); diff --git a/module/product/test/tao/getbranchselect4pc.php b/module/product/test/tao/getbranchselect4pc.php new file mode 100755 index 0000000000..693fe8dfc5 --- /dev/null +++ b/module/product/test/tao/getbranchselect4pc.php @@ -0,0 +1,44 @@ +#!/usr/bin/env php +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'); diff --git a/module/product/zen.php b/module/product/zen.php index 74dd7f943e..f6fb53276b 100644 --- a/module/product/zen.php +++ b/module/product/zen.php @@ -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"); } /** diff --git a/module/programplan/control.php b/module/programplan/control.php index 6961ccf6fb..28897a122e 100644 --- a/module/programplan/control.php +++ b/module/programplan/control.php @@ -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); diff --git a/module/programplan/model.php b/module/programplan/model.php index 11524ebcf9..80bc48c081 100755 --- a/module/programplan/model.php +++ b/module/programplan/model.php @@ -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'); diff --git a/module/programplan/test/model/checkleafstage.php b/module/programplan/test/model/checkleafstage.php index 95cbd14024..f766303bcb 100755 --- a/module/programplan/test/model/checkleafstage.php +++ b/module/programplan/test/model/checkleafstage.php @@ -1,23 +1,16 @@ #!/usr/bin/env php 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 */ diff --git a/module/programplan/test/model/yaml/checkleafstage/checkleafstage.yaml b/module/programplan/test/model/yaml/checkleafstage/checkleafstage.yaml new file mode 100644 index 0000000000..52225e216a --- /dev/null +++ b/module/programplan/test/model/yaml/checkleafstage/checkleafstage.yaml @@ -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' diff --git a/module/project/tao.php b/module/project/tao.php index 50f7d99196..cc5fd4853d 100755 --- a/module/project/tao.php +++ b/module/project/tao.php @@ -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) diff --git a/module/project/test/model/getprogrammaxend.php b/module/project/test/model/getprogrammaxend.php index 22e75d8070..53f3e1fdcf 100755 --- a/module/project/test/model/getprogrammaxend.php +++ b/module/project/test/model/getprogrammaxend.php @@ -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'); //获取三级项目集最大结束时间:开始时间等于结束时间 diff --git a/module/project/test/model/getprogramminbegin.php b/module/project/test/model/getprogramminbegin.php new file mode 100644 index 0000000000..6a76ce2df8 --- /dev/null +++ b/module/project/test/model/getprogramminbegin.php @@ -0,0 +1,24 @@ +#!/usr/bin/env php +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'); //获取三级项目集最小开始时间:开始时间等于结束时间 diff --git a/module/project/test/model/yaml/getprogrammaxend/project.yaml b/module/project/test/model/yaml/getprogrammaxend/project.yaml index 25ed2bb9ad..230181f50b 100644 --- a/module/project/test/model/yaml/getprogrammaxend/project.yaml +++ b/module/project/test/model/yaml/getprogrammaxend/project.yaml @@ -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' diff --git a/module/project/test/model/yaml/getprogramminbegin/project.yaml b/module/project/test/model/yaml/getprogramminbegin/project.yaml new file mode 100644 index 0000000000..aef1007a25 --- /dev/null +++ b/module/project/test/model/yaml/getprogramminbegin/project.yaml @@ -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' diff --git a/module/task/config/form.php b/module/task/config/form.php index a8a3ef0941..3b2c531017 100644 --- a/module/task/config/form.php +++ b/module/task/config/form.php @@ -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); diff --git a/module/task/control.php b/module/task/control.php index e8ce797d1e..22577d5843 100755 --- a/module/task/control.php +++ b/module/task/control.php @@ -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'); } /** diff --git a/module/task/model.php b/module/task/model.php index d5fd6d5f2f..1d679d7f32 100755 --- a/module/task/model.php +++ b/module/task/model.php @@ -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, " {$assignedToText}", '', "class='$btnClass'"); echo !common::hasPriv('task', 'assignTo', $task) ? "{$assignedToText}" : $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'); } diff --git a/module/task/tao.php b/module/task/tao.php index b7bac12155..d5cd3a61cf 100644 --- a/module/task/tao.php +++ b/module/task/tao.php @@ -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'; diff --git a/module/task/test/model/aftercreate.php b/module/task/test/model/aftercreate.php new file mode 100755 index 0000000000..519b3fbb1b --- /dev/null +++ b/module/task/test/model/aftercreate.php @@ -0,0 +1,74 @@ +#!/usr/bin/env php +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字段的值 diff --git a/module/task/test/model/assign.php b/module/task/test/model/assign.php index 0881dd1338..9e498c60d4 100755 --- a/module/task/test/model/assign.php +++ b/module/task/test/model/assign.php @@ -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状态任务指派 \ No newline at end of file +r($task->assignTest($taskIDlist[5],$closedTask)) && p('0:field,old,new') && e('assignedTo,old6,user97'); // closed状态任务指派 diff --git a/module/task/test/model/updateteam.php b/module/task/test/model/updateteam.php new file mode 100644 index 0000000000..140f13ceb3 --- /dev/null +++ b/module/task/test/model/updateteam.php @@ -0,0 +1,44 @@ +#!/usr/bin/env php +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工时团队后任务 diff --git a/module/task/test/tao/batchcomputeprogress.php b/module/task/test/tao/batchcomputeprogress.php index d60aed8d18..c6ab7d5ce9 100755 --- a/module/task/test/tao/batchcomputeprogress.php +++ b/module/task/test/tao/batchcomputeprogress.php @@ -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的情况 \ No newline at end of file diff --git a/module/task/test/tao/buildtasktree.php b/module/task/test/tao/buildtasktree.php index 0e9d143261..e05439a036 100755 --- a/module/task/test/tao/buildtasktree.php +++ b/module/task/test/tao/buildtasktree.php @@ -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'); // 测试数据中只有父任务时,重构结构后的任务数量 \ No newline at end of file diff --git a/module/task/test/tao/computecurrenttaskstatus.php b/module/task/test/tao/computecurrenttaskstatus.php index 12330b9202..aae518b794 100755 --- a/module/task/test/tao/computecurrenttaskstatus.php +++ b/module/task/test/tao/computecurrenttaskstatus.php @@ -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(); diff --git a/module/task/test/tao/computetaskprogress.php b/module/task/test/tao/computetaskprogress.php index d5b6d9966a..2cd5e358e3 100755 --- a/module/task/test/tao/computetaskprogress.php +++ b/module/task/test/tao/computetaskprogress.php @@ -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的情况 \ No newline at end of file diff --git a/module/task/test/tao/docreate.php b/module/task/test/tao/docreate.php index b96669178c..af5e401fe7 100755 --- a/module/task/test/tao/docreate.php +++ b/module/task/test/tao/docreate.php @@ -12,6 +12,95 @@ title=taskModel->doCreate(); timeout=0 cid=2 +sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory +- 测试正常的创建开发任务 + - 属性name @开发任务一 + - 属性execution @101 + - 属性type @devel + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @0000-00-00 + - 属性deadline @0000-00-00 + +- 测试正常的创建设计任务 + - 属性name @设计任务一 + - 属性execution @101 + - 属性type @design + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @2023-04-01 + - 属性deadline @0000-00-00 + +- 测试正常的创建需求任务 + - 属性name @需求任务一 + - 属性execution @101 + - 属性type @request + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @0000-00-00 + - 属性deadline @2024-01-01 + +- 测试正常的创建测试任务 + - 属性name @测试任务一 + - 属性execution @101 + - 属性type @test + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @0000-00-00 + - 属性deadline @0000-00-00 + +- 测试正常的创建研究任务 + - 属性name @研究任务一 + - 属性execution @101 + - 属性type @study + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @2023-04-01 + - 属性deadline @2024-01-01 + +- 测试正常的创建讨论任务 + - 属性name @讨论任务一 + - 属性execution @101 + - 属性type @discuss + - 属性estimate @0 + - 属性version @1 + - 属性estStarted @2021-01-10 + - 属性deadline @2021-03-19 + +- 测试正常的创建界面任务 + - 属性name @界面任务一 + - 属性execution @101 + - 属性type @ui + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @2021-01-10 + - 属性deadline @2021-03-19 + +- 测试正常的创建事务任务 + - 属性name @事务任务一 + - 属性execution @101 + - 属性type @affair + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @2021-01-10 + - 属性deadline @2021-03-19 + +- 测试正常的创建其他任务 + - 属性name @其他任务一 + - 属性execution @101 + - 属性type @misc + - 属性estimate @1 + - 属性version @1 + - 属性estStarted @2021-01-10 + - 属性deadline @2021-03-19 + +- 测试不输入执行创建任务 @『所属执行』不能为空。 + +- 测试不输入名称创建任务 @『任务名称』不能为空。 + +- 测试不输入类型创建任务 @『任务类型』不能为空。 + +- 测试不输入类型创建任务 @『最初预计』应当是数字,可以是小数。 */ $devel = array('execution' => 101, 'name' => '开发任务一', 'type' => 'devel', 'estimate' => 1, 'version' => 1, 'estStarted' => null, 'deadline' => null); @@ -42,4 +131,4 @@ r($task->doCreateObject($misc)) && p('name,execution,type,estimate,vers r($task->doCreateObject($noexecution)) && p('execution:0') && e('『所属执行』不能为空。'); // 测试不输入执行创建任务 r($task->doCreateObject($noname)) && p('name:0') && e('『任务名称』不能为空。'); // 测试不输入名称创建任务 r($task->doCreateObject($notype)) && p('type:0') && e('『任务类型』不能为空。'); // 测试不输入类型创建任务 -r($task->doCreateObject($errorEstimate)) && p('estimate:0') && e('『最初预计』应当是数字,可以是小数。'); // 测试不输入类型创建任务 +r($task->doCreateObject($errorEstimate)) && p('estimate:0') && e('『最初预计』应当是数字,可以是小数。'); // 测试不输入类型创建任务 \ No newline at end of file diff --git a/module/task/test/tao/fetchexecutiontasks.php b/module/task/test/tao/fetchexecutiontasks.php index 12c641ef88..336ff4b522 100755 --- a/module/task/test/tao/fetchexecutiontasks.php +++ b/module/task/test/tao/fetchexecutiontasks.php @@ -64,163 +64,162 @@ title=taskModel->fetchExecutionTasks(); timeout=0 cid=1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[0], $productIdList[0], $type[0], $modules[0], $orderBy[0], $count[0]属性 @0 +sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory +- 测试获取执行ID 0 product 0 type all module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[0], $productIdList[0], $type[0], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 0 product 0 type all module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 0 type all module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[0], $orderBy[0], $count[1]属性 @10 +- 测试获取执行ID 1 product 0 type all module 空 orederBy 'status_asc, id_desc' 的任务数量 @10 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[0], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type all module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[0], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 1 product 1 type all module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[1], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 1 product 1 type assignedbyme module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[1], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 1 product 1 type assignedbyme module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[2], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type myinvolved module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[2], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 1 product 1 type myinvolved module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[3], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type undone module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[3], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 1 product 1 type undone module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[4], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 1 product 1 type needconfirm module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[4], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 1 product 1 type needconfirm module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[5], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type assignedtome module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[5], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 1 product 1 type assignedtome module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[6], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type finishedbyme module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[6], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 1 product 1 type finishedbyme module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[7], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type delayed module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[7], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 1 product 1 type delayed module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[8], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type wait module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[8], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 1 product 1 type wait module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[9], $modules[0], $orderBy[0], $count[0]第11条的name属性 @任务11 +- 测试获取执行ID 1 product 1 type doing module 空 orederBy 'status_asc, id_desc' 的任务第11条的name属性 @任务11 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[9], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 1 product 1 type doing module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[10], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 1 product 1 type done module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[10], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 1 product 1 type done module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[11], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 1 product 1 type pause module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[11], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 1 product 1 type pause module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[12], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 1 product 1 type cancel module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[12], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 1 product 1 type cancel module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[13], $modules[0], $orderBy[0], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 1 type array('wait', 'doing', 'done', 'pause', 'cancel') module 空 orederBy 'status_asc, id_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[1], $type[13], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 1 product 1 type array('wait', 'doing', 'done', 'pause', 'cancel') module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[1], $orderBy[0], $count[0]第17条的name属性 @任务17 +- 测试获取执行ID 1 product 0 type all module array(2) orederBy 'status_asc, id_desc' 的任务第17条的name属性 @任务17 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[1], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 1 product 0 type all module array(2) orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[2], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 1 product 0 type all module array(8) orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[2], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 1 product 0 type all module array(8) orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[3], $orderBy[0], $count[0]第17条的name属性 @任务17 +- 测试获取执行ID 1 product 0 type all module array(2,8) orederBy 'status_asc, id_desc' 的任务第17条的name属性 @任务17 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[3], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 1 product 0 type all module array(2,8) orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[0], $orderBy[1], $count[0]第1条的name属性 @任务1 +- 测试获取执行ID 1 product 0 type all module 空 orederBy 'pri_desc' 的任务第1条的name属性 @任务1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[1], $productIdList[0], $type[0], $modules[0], $orderBy[1], $count[1]属性 @10 +- 测试获取执行ID 1 product 0 type all module 空 orederBy 'pri_desc' 的任务数量 @10 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[0], $orderBy[0], $count[0]第18条的name属性 @任务18 +- 测试获取执行ID 2 product 0 type all module 空 orederBy 'status_asc, id_desc' 的任务第18条的name属性 @任务18 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[0], $orderBy[0], $count[1]属性 @10 +- 测试获取执行ID 2 product 0 type all module 空 orederBy 'status_asc, id_desc' 的任务数量 @10 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[0], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type all module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[0], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 2 product 1 type all module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[1], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 2 product 1 type assignedbyme module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[1], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 2 product 1 type assignedbyme module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[2], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type myinvolved module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[2], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 2 product 1 type myinvolved module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[3], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type undone module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[3], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 2 product 1 type undone module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[4], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type needconfirm module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[4], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 2 product 1 type needconfirm module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[5], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type assignedtome module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[5], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 2 product 1 type assignedtome module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[6], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type finishedbyme module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[6], $modules[0], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 2 product 1 type finishedbyme module 空 orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[7], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 2 product 1 type delayed module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[7], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 2 product 1 type delayed module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[8], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 2 product 1 type wait module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[8], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 2 product 1 type wait module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[9], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 2 product 1 type doing module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[9], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 2 product 1 type doing module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[10], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 2 product 1 type done module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[10], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 2 product 1 type done module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[11], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type pause module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[11], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 2 product 1 type pause module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[12], $modules[0], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 2 product 1 type cancel module 空 orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[12], $modules[0], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 2 product 1 type cancel module 空 orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[13], $modules[0], $orderBy[0], $count[0]第6条的name属性 @任务6 +- 测试获取执行ID 2 product 1 type array('wait', 'doing', 'done', 'pause', 'cancel') module 空 orederBy 'status_asc, id_desc' 的任务第6条的name属性 @任务6 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[1], $type[13], $modules[0], $orderBy[0], $count[1]属性 @1 +- 测试获取执行ID 2 product 1 type array('wait', 'doing', 'done', 'pause', 'cancel') module 空 orederBy 'status_asc, id_desc' 的任务数量 @1 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[1], $orderBy[0], $count[0]第2条的name属性 @任务2 +- 测试获取执行ID 2 product 0 type all module array(2) orederBy 'status_asc, id_desc' 的任务第2条的name属性 @任务2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[1], $orderBy[0], $count[1]属性 @2 +- 测试获取执行ID 2 product 0 type all module array(2) orederBy 'status_asc, id_desc' 的任务数量 @2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[2], $orderBy[0], $count[0]属性 @0 +- 测试获取执行ID 2 product 0 type all module array(8) orederBy 'status_asc, id_desc' 的任务 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[2], $orderBy[0], $count[1]属性 @0 +- 测试获取执行ID 2 product 0 type all module array(8) orederBy 'status_asc, id_desc' 的任务数量 @0 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[3], $orderBy[0], $count[0]第2条的name属性 @任务2 +- 测试获取执行ID 2 product 0 type all module array(2,8) orederBy 'status_asc, id_desc' 的任务第2条的name属性 @任务2 -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[3], $orderBy[0], $count[1]属性 @2 - -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[0], $orderBy[1], $count[0]第20条的name属性 @任务20 - -- 执行task模块的fetchExecutionTasks方法,参数是$executionIdList[2], $productIdList[0], $type[0], $modules[0], $orderBy[1], $count[1]属性 @10 +- 测试获取执行ID 2 product 0 type all module array(2,8) orederBy 'status_asc, id_desc' 的任务数量 @2 +- 测试获取执行ID 2 product 0 type all module 空 orederBy 'pri_desc' 的任务第20条的name属性 @任务20 +- 测试获取执行ID 2 product 0 type all module 空 orederBy 'pri_desc' 的任务数量 @10 */ diff --git a/module/task/test/tao/getassignedto4multi.php b/module/task/test/tao/getassignedto4multi.php index ce43dba8e6..4ffb987525 100755 --- a/module/task/test/tao/getassignedto4multi.php +++ b/module/task/test/tao/getassignedto4multi.php @@ -28,11 +28,16 @@ title=taskModel->getAssignedTo4Multi(); timeout=0 cid=1 -- 执行taskTester模块的getAssignedTo4Multi方法,参数是$taskIdList[0] @admin -- 执行taskTester模块的getAssignedTo4Multi方法,参数是$taskIdList[1] @dev01 -- 执行taskTester模块的getAssignedTo4Multi方法,参数是$taskIdList[1], next @dev02 -- 执行taskTester模块的getAssignedTo4Multi方法,参数是$taskIdList[2] @dev01 -- 执行taskTester模块的getAssignedTo4Multi方法,参数是$taskIdList[3] @admin +sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory +- 测试获取并行任务的指派人 @admin + +- 测试获取串行任务的当前指派人 @dev01 + +- 测试获取并行任务的下一个指派人 @dev02 + +- 测试获取已完成的串行任务的当前指派人 @dev01 + +- 测试获取普通任务的指派人 @admin */ @@ -43,4 +48,4 @@ r($taskTester->getAssignedTo4MultiTest($taskIdList[0])) && p() && e('adm r($taskTester->getAssignedTo4MultiTest($taskIdList[1])) && p() && e('dev01'); // 测试获取串行任务的当前指派人 r($taskTester->getAssignedTo4MultiTest($taskIdList[1], 'next')) && p() && e('dev02'); // 测试获取并行任务的下一个指派人 r($taskTester->getAssignedTo4MultiTest($taskIdList[2])) && p() && e('dev01'); // 测试获取已完成的串行任务的当前指派人 -r($taskTester->getAssignedTo4MultiTest($taskIdList[3])) && p() && e('admin'); // 测试获取普通任务的指派人 +r($taskTester->getAssignedTo4MultiTest($taskIdList[3])) && p() && e('admin'); // 测试获取普通任务的指派人 \ No newline at end of file diff --git a/module/task/test/tao/getlistbyreportcondition.php b/module/task/test/tao/getlistbyreportcondition.php old mode 100644 new mode 100755 index 63e706859b..c745adcede --- a/module/task/test/tao/getlistbyreportcondition.php +++ b/module/task/test/tao/getlistbyreportcondition.php @@ -43,6 +43,7 @@ title=taskModel->getDataOfTasksPerExecution(); timeout=0 cid=1 +sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory - 获取任务id,execution列表信息在执行2中 - 第2条的id属性 @2 - 第2条的execution属性 @2 @@ -57,8 +58,6 @@ cid=1 - 获取执行3的任务个数 @2 - - */ initData(); diff --git a/module/task/test/tao/getteammembersbyidlist.php b/module/task/test/tao/getteammembersbyidlist.php index d3dfe6dba0..7a2d4a4eec 100755 --- a/module/task/test/tao/getteammembersbyidlist.php +++ b/module/task/test/tao/getteammembersbyidlist.php @@ -18,9 +18,12 @@ title=taskModel->getTeamMembersByIdList(); timeout=0 cid=1 -- 执行$emptyData属性 @0 -- 执行count($taskTeamGroup)属性 @2 -- 执行$firstTaskTeam第0条的account属性 @admin +sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory +- 测试传入空的taskIdList @0 + +- 测试查询给定taskIdList的任务数量 @2 + +- 测试查询任务id为1团队中第一个人的用户名第0条的account属性 @admin */ @@ -34,4 +37,4 @@ $firstTaskTeam = current($taskTeamGroup); r($emptyData) && p() && e('0'); // 测试传入空的taskIdList r(count($taskTeamGroup)) && p() && e('2'); // 测试查询给定taskIdList的任务数量 -r($firstTaskTeam) && p('0:account') && e('admin'); // 测试查询任务id为1团队中第一个人的用户名 +r($firstTaskTeam) && p('0:account') && e('admin'); // 测试查询任务id为1团队中第一个人的用户名 \ No newline at end of file diff --git a/module/task/test/tao/managetaskteammember.php b/module/task/test/tao/managetaskteammember.php new file mode 100755 index 0000000000..fce3436ac5 --- /dev/null +++ b/module/task/test/tao/managetaskteammember.php @@ -0,0 +1,112 @@ +#!/usr/bin/env php +manageTaskTeamMember(); +cid=1 +pid=1 + +*/ + +$modeList = array('linear', 'multi'); +$taskIdList = array(1, 2, 3); +$taskStatusList = array('wait', 'doing', 'done'); +$row = array(0, 1, 2, 3, 4, 5); +$account = array('admin', 'user1', 'user2', 'user3', 'user4', 'user5', 'user6', 'user7', 'user9'); +$minStatus = array('done', 'doing', 'wait'); +$undoneUsersList = array(array('admin' => 'admin', 'user1' => 'user1', 'user2' => 'user2', 'user3' => 'user3'), array('user4' => 'user4', 'user5' => 'user5', 'user6' => 'user6', 'user7' => 'user7', 'user8' => 'user8'), array()); +$teamSourceList = array(array('admin', 'user1', 'user2', 'user3'), array('admin', 'user1', 'user2', 'user4'), array('user4', 'user5', 'user6', 'user7', 'user9'), array('user4', 'user5', 'user6', 'user7', 'user8')); +$teamEstimateList = array(array(1, 2, 3, 4), array(2, 3, 4, 5, 7)); +$teamConsumedList = array(array(4, 3, 2, 1), array(4, 3, 2, 1, 0)); +$teamLeftList = array(array(0, 0, 0, 0), array(0, 1, 3, 5, 7)); +$inTeams = array(true, false); + +$task = new taskTest(); + +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 admin 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[0], $row[5], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 admin 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 admin 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[0], $row[5], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 admin 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的串行多人任务内用户 admin 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[0], $row[5], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的串行多人任务内用户 admin 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[0], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的串行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 admin 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[1], $row[5], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 admin 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[0], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 admin 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[1], $row[5], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 admin 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[1], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的并行多人任务内用户 admin 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[1], $row[5], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的并行多人任务内用户 admin 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[0], $taskStatusList[2], $modeList[1], $row[0], $account[0], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 1 任务状态为 done 最小任务状态为done 的并行多人任务内用户 admin 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + + +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 user6 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[0], $row[5], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 user6 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 user6 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[0], $row[5], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 user6 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的串行多人任务内用户 user6 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[0], $row[5], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的串行多人任务内用户 user6 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[0], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的串行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 user6 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[1], $row[5], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 user6 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[0], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 wait 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 user6 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[1], $row[5], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 user6 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[1], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 doing 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 + +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的并行多人任务内用户 user6 不存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[1], $row[5], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], false, false, $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的并行多人任务内用户 user6 不存在期望 消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[0])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[0], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在用户列表中的成员信息 +r($task->manageTaskTeamMemberTest($taskIdList[1], $taskStatusList[2], $modeList[1], $row[0], $account[6], $minStatus[0], $undoneUsersList[2], $teamSourceList[0], $teamEstimateList[0], $teamConsumedList[0], $teamLeftList[0], $inTeams[1])) && p('minStatus,memberData') && e(''); // 测试更新任务ID 2 任务状态为 done 最小任务状态为done 的并行多人任务内用户 user6 存在消耗和剩余的 不在未完成任务列表 不在用户列表中的成员信息 diff --git a/module/task/test/tao/removecreaterequiredfields.php b/module/task/test/tao/removecreaterequiredfields.php index 7fd9a53e30..a83c095cca 100755 --- a/module/task/test/tao/removecreaterequiredfields.php +++ b/module/task/test/tao/removecreaterequiredfields.php @@ -21,8 +21,80 @@ title=taskModel->removeCreateRequiredFields(); timeout=0 cid=1 -*/ +sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory +- 测试任务执行为短期执行 阶段类型为mix 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,story,estimate,estStarted,deadline,module +- 测试任务执行为短期执行 阶段类型为mix 任务类型为dev 有选择需求时候的必填项 @name,type,execution,story,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为request 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为request 任务类型为dev 有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为review 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为review 任务类型为dev 有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为mix 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,story,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为mix 任务类型为dev 有选择需求时候的必填项 @name,type,execution,story,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为request 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为request 任务类型为dev 有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为review 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为review 任务类型为dev 有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为mix 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为mix 任务类型为dev 有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为request 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为request 任务类型为dev 有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为review 任务类型为dev 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为review 任务类型为dev 有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为mix 任务类型为test 没有选择需求时候的必填项 @name,type,execution,story,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为mix 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为短期执行 阶段类型为request 任务类型为test 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为request 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为短期执行 阶段类型为review 任务类型为test 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为短期执行 阶段类型为review 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为长期执行 阶段类型为mix 任务类型为test 没有选择需求时候的必填项 @name,type,execution,story,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为mix 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为长期执行 阶段类型为request 任务类型为test 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为request 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为长期执行 阶段类型为review 任务类型为test 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为长期执行 阶段类型为review 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为运维执行 阶段类型为mix 任务类型为test 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为mix 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为运维执行 阶段类型为request 任务类型为test 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为request 任务类型为test 有选择需求时候的必填项 @name,type,execution + +- 测试任务执行为运维执行 阶段类型为review 任务类型为test 没有选择需求时候的必填项 @name,type,execution,estimate,estStarted,deadline,module + +- 测试任务执行为运维执行 阶段类型为review 任务类型为test 有选择需求时候的必填项 @name,type,execution + +*/ $selectTestStoryList = array(false, true); @@ -63,4 +135,4 @@ r($task->removeCreateRequiredFieldsTest($tasks[15], $selectTestStoryList[1])) & r($task->removeCreateRequiredFieldsTest($tasks[16], $selectTestStoryList[0])) && p() && e('name,type,execution,estimate,estStarted,deadline,module'); // 测试任务执行为运维执行 阶段类型为request 任务类型为test 没有选择需求时候的必填项 r($task->removeCreateRequiredFieldsTest($tasks[16], $selectTestStoryList[1])) && p() && e('name,type,execution'); // 测试任务执行为运维执行 阶段类型为request 任务类型为test 有选择需求时候的必填项 r($task->removeCreateRequiredFieldsTest($tasks[17], $selectTestStoryList[0])) && p() && e('name,type,execution,estimate,estStarted,deadline,module'); // 测试任务执行为运维执行 阶段类型为review 任务类型为test 没有选择需求时候的必填项 -r($task->removeCreateRequiredFieldsTest($tasks[17], $selectTestStoryList[1])) && p() && e('name,type,execution'); // 测试任务执行为运维执行 阶段类型为review 任务类型为test 有选择需求时候的必填项 +r($task->removeCreateRequiredFieldsTest($tasks[17], $selectTestStoryList[1])) && p() && e('name,type,execution'); // 测试任务执行为运维执行 阶段类型为review 任务类型为test 有选择需求时候的必填项 \ No newline at end of file diff --git a/module/task/test/tao/settaskfiles.php b/module/task/test/tao/settaskfiles.php index 544269bade..133e557e6b 100755 --- a/module/task/test/tao/settaskfiles.php +++ b/module/task/test/tao/settaskfiles.php @@ -21,6 +21,17 @@ title=taskModel->setTaskFiles(); timeout=0 cid=1 +sed: can't read /home/tianshujie/repo/zentaopms/test/config/my.php: No such file or directory +- 测试空数据 @0 + +- 测试传入的任务ID @0 + +- 测试插入任务附件的数量 @10 + +- 测试插入附件数据的对象ID第1条的objectID属性 @6 + +- 测试获取任务ID为5的附件数据的数量 @0 + */ $taskIdList = range(1, 5); @@ -35,4 +46,4 @@ r($emptyData) && p() && e('0'); // 测试空数据 r($emptyTaskID) && p() && e('0'); // 测试传入的任务ID r(count($insertData)) && p() && e('10'); // 测试插入任务附件的数量 r($insertData) && p('1:objectID') && e('6'); // 测试插入附件数据的对象ID -r(count($taskFiles)) && p() && e('0'); // 测试获取任务ID为5的附件数据的数量 +r(count($taskFiles)) && p() && e('0'); // 测试获取任务ID为5的附件数据的数量 \ No newline at end of file diff --git a/module/task/test/tao/yaml/managetaskteammember/effort_managetaskteammember.yaml b/module/task/test/tao/yaml/managetaskteammember/effort_managetaskteammember.yaml new file mode 100644 index 0000000000..6982b41d06 --- /dev/null +++ b/module/task/test/tao/yaml/managetaskteammember/effort_managetaskteammember.yaml @@ -0,0 +1,13 @@ +--- +title: zt_effort +author: auto_managetaskteammember +version: "1.0" +fields: +- field: objectType + range: task +- field: objectID + range: 1{4},2{6} +- field: left + range: 0{4},0-7,0-7,0-7 +... + diff --git a/module/task/test/tao/yaml/managetaskteammember/taskteam_managetaskteammember.yaml b/module/task/test/tao/yaml/managetaskteammember/taskteam_managetaskteammember.yaml new file mode 100644 index 0000000000..80d838bf18 --- /dev/null +++ b/module/task/test/tao/yaml/managetaskteammember/taskteam_managetaskteammember.yaml @@ -0,0 +1,24 @@ +--- +title: zt_taskteam +author: auto_managetaskteammember +version: "1.0" +fields: +- field: task + range: 1-5 +- field: left + range: 0-4 +- field: estimate + range: 1-10{2} +- field: consumed + range: 1,3,0,2 +- field: account + note: "用户账号" + fields: + - field: account1 + range: admin,user{99} + - field: account2 + range: "[],1-99" +- field: status + range: "done,doing,wait,doing" +... + diff --git a/module/task/test/task.class.php b/module/task/test/task.class.php index 2468b770b0..5c05263afa 100644 --- a/module/task/test/task.class.php +++ b/module/task/test/task.class.php @@ -304,6 +304,38 @@ class taskTest } } + /** + * Test assign a task to a team again. + * + * @param int $taskID + * @param string $status + * @param array $team + * @param array $teamSource + * @param array $teamConsumed + * @param araay $teamLeft + * @access public + * @return object + */ + public function updateTeamTest($taskID, $status, $team, $teamSource, $teamEstimate, $teamConsumed, $teamLeft) + { + global $tester; + + $task = new stdclass(); + $task->id = $taskID; + $task->status = $status; + $task->lastEditedBy = $tester->app->user->account; + $object = $this->objectModel->updateTeam($task, $team, $teamSource, $teamEstimate, $teamConsumed, $teamLeft); + if(dao::isError()) + { + $errors = dao::getError(); + return array_shift($errors); + } + else + { + return $object; + } + } + /** * Test cancel a task. * @@ -1721,4 +1753,114 @@ class taskTest return $cards; } + + /** + * Other data processing after task creation. + * + * @param int $taskID + * @param int $taskIdList + * @param int $bugID + * @param int $todoID + * @param array $testTasks + * @access public + * @return object|bool + */ + public function afterCreateTest($taskID = 0, $taskIdList = array(), $bugID = 0, $todoID = 0, $testTasks = array()) + { + global $tester; + $_SERVER['HTTP_HOST'] = $tester->config->db->host; + + $task = $this->objectModel->getByID($taskID); + if(!$task) return false; + + $result = $this->objectModel->afterCreate($task, $taskIdList, $bugID, $todoID, $testTasks); + if(!$result) return false; + + if($bugID) + { + $object = $tester->dao->findById($bugID)->from(TABLE_BUG)->fetch(); + } + elseif($todoID) + { + $object = $tester->dao->findById($todoID)->from(TABLE_TODO)->fetch(); + } + elseif($task->story) + { + $object = $tester->dao->findById($task->story)->from(TABLE_STORY)->fetch(); + } + else + { + $object = $tester->dao->findById($taskID)->from(TABLE_TASK)->fetch(); + } + + return $object; + } + + /** + * Test manage multi task team members. + * + * @param int $taskID + * @param string $taskStatus + * @param string $mode + * @param array $teamList + * @param array $teamSourceList + * @param array $teamEstimateList + * @param array|bool $teamConsumedList + * @param array|bool $teamLeftList + + * @access public + * @return array + */ + public function manageTaskTeamTest(int $taskID, string $taskStatus, string $mode, array $teamList, array $teamSourceList, array $teamEstimateList, array|bool $teamConsumedList, array|bool $teamLeftList): array + { + $task = new stdclass(); + $task->id = $taskID; + $task->status = $taskStatus; + $teams = $this->objectModel->manageTaskTeam($mode, $task, $teamList, $teamSourceList, $teamEstimateList, $teamConsumedList, $teamLeftList); + if(dao::isError()) + { + return dao::getError(); + } + else + { + return $teams; + } + } + + /** + * Test manage multi task team member. + * + * @param int $taskID + * @param string $taskStatus + * @param string $mode + * @param int $row + * @param string $account + * @param string $minStatus + * @param array $undoneUsers + * @param array $teamSourceList + * @param array $teamEstimateList + * @param array|bool $teamConsumedList + * @param array|bool $teamLeftList + * @param bool $inTeams + * @access public + * @return string + */ + public function manageTaskTeamMemberTest(int $taskID, string $taskStatus, string $mode, int $row, string $account, string $minStatus, array $undoneUsers, array $teamSourceList, array $teamEstimateList, array|bool $teamConsumedList, array|bool $teamLeftList, bool $inTeams): string + { + global $tester; + $tester->dao->delete()->from(TABLE_TASKTEAM)->where('task')->eq($taskID)->exec(); + + $task = new stdclass(); + $task->id = $taskID; + $task->status = $taskStatus; + $minStatus = $this->objectModel->manageTaskTeamMember($mode, $task, $row, $account, $minStatus, $undoneUsers, $teamSourceList, $teamEstimateList, $teamConsumedList, $teamLeftList, $inTeams); + if(dao::isError()) + { + return dao::getError(); + } + else + { + return $minStatus; + } + } } diff --git a/module/task/ui/assignto.html.php b/module/task/ui/assignto.html.php index 51b1e7d8da..27bf1d3e4b 100644 --- a/module/task/ui/assignto.html.php +++ b/module/task/ui/assignto.html.php @@ -1,4 +1,5 @@ name; +$formTitle = $task->name; $assignedToOptions = $members; diff --git a/module/task/ui/edit.html.php b/module/task/ui/edit.html.php index 8e164412bf..819fe66ed9 100644 --- a/module/task/ui/edit.html.php +++ b/module/task/ui/edit.html.php @@ -68,363 +68,417 @@ formPanel ( set::title($formTitle), // The form title is diffrent from the page title, setStyle(['max-width' => '100%']), + setClass('mx-8'), div ( - setClass('flex'), - cell - ( - set('width', '67%'), - formGroup + setClass('flex'), + cell ( - set::label($lang->task->name), - set::name('name'), - set::value($task->name), - set::placeholder($lang->task->name), - set::control('input'), - set::required(true), - set::autofocus(true), - ), - formGroup - ( - set::label($lang->task->desc), - set::name('desc'), - set::value(htmlSpecialString($task->desc)), - set::control('textarea'), - ), - formGroup - ( - set::label($lang->comment), - set::name('comment'), - set::value(''), - set::control('textarea'), - ), - history - ( - set::actions($actions), - set::users($users), - set::methodName($methodName), - ) - ), - cell - ( - on::change('#execution'), - set('width', '33%'), - formGroup - ( - set::name("execution"), - set::label($lang->task->execution), - set::required(true), - set::value($task->execution), - set::control("picker"), - set::items($executionOptions) - ), - formGroup - ( - set::name("module"), - set::label($lang->task->module), - set::value($task->module), - set::control("picker"), - set::items($moduleOptions) - ), - formGroup - ( - set::name("story"), - set::label($lang->task->story), - set::value($task->story), - set::control("picker"), - set::items($storyOptions) - ), - (empty($modeText)) - ? formGroup - ( - set::name("mode"), - set::label($lang->task->mode), - set::value($task->mode), - set::control("picker"), - set::items($modeOptions) - ) - : label - ( - $modeText - ), - formGroup - ( - set::label($lang->task->assignedTo), - inputGroup + set('width', '67%'), + h::strong ( - control(set(array - ( - 'name' => "assignedTo", - 'id' => "assignedTo", - 'value' => $task->assignedTo, - 'disabled' => (!empty($task->team) and $task->mode == 'linear') ? true : false, - 'type' => "picker", - 'items' => $assignedToOptions - ))), - btn(set(array - ( - 'type' => "btn", - 'text' => $lang->task->team, - 'class' => "input-group-btn team-group" - ))) + $lang->task->name, + setClass('leading-8') + ), + input + ( + set::label($lang->task->name), + set::name('name'), + set::value($task->name), + set::placeholder($lang->task->name), + set::control('input'), + set::required(true), + set::autofocus(true), + ), + h::strong + ( + $lang->task->desc, + setClass('leading-8') + ), + textarea + ( + set::label($lang->task->desc), + set::name('desc'), + set::value(htmlSpecialString($task->desc)), + set::control('textarea'), + ), + h::strong + ( + $lang->comment, + setClass('leading-8') + ), + textarea + ( + set::label($lang->comment), + set::name('comment'), + set::value(''), + set::control('textarea'), + ), + history + ( + set::actions($actions), + set::users($users), + set::methodName($methodName), ) ), - formGroup + cell ( - set::name("type"), - set::label($lang->task->type), - set::required(true), - set::value($task->type), - set::control("picker"), - set::items($typeOptions) - ), - empty($task->children) - ? formGroup - ( - set::name("status"), - set::label($lang->task->status), - set::value($task->status), - set::control("picker"), - set::items($statusOptions) - ) - : null, - formGroup - ( - set::name("pri"), - set::label($lang->task->pri), - set::value($task->pri), - set::control("picker"), - set::items($priOptions) - ), - formGroup - ( - set::label($lang->task->mailto), - inputGroup + on::change('#execution'), + set('width', '33%'), + setClass('pl-5'), + h::strong ( - control(set(array - ( - 'name' => "mailto[]", - 'id' => "mailto", - 'value' => $task->mailto, - 'type' => "picker", - 'items' => $mailtoOptions, - 'multiple' => true - ))), - control(set(array - ( - 'name' => "contactListMenu", - 'id' => "contactListMenu", - 'value' => "", - 'disabled' => false, - 'type' => "picker", - 'onchange' => "setMailto", - 'items' => $contactListMenuOptions - ))) - ) - ), - formGroup - ( - set::name("estStarted"), - set::label($lang->task->estStarted), - set::value($task->estStarted), - set::control("date") - ), - formGroup - ( - set::name("deadline"), - set::label($lang->task->deadline), - set::value($task->deadline), - set::control("date") - ), - formGroup - ( - set::name("estimate"), - set::label($lang->task->estimate), - set::value($task->estimate), - set::control("text") - ), - formGroup - ( - set::name("left"), - set::label($lang->task->left), - set::value($task->left), - set::control("text") - ), - formGroup - ( - set::name("realStarted"), - set::label($lang->task->realStarted), - set::value(helper::isZeroDate($task->realStarted) ? '' : $task->realStarted), - set::control("datetime") - ), - formGroup - ( - set::name("finishedBy"), - set::label($lang->task->finishedBy), - set::value($task->finishedBy), - set::control("picker"), - set::items($finishedByOptions) - ), - formGroup - ( - set::name("finishedDate"), - set::label($lang->task->finishedDate), - set::value($task->finishedDate), - set::control("datetime") - ), - formGroup - ( - set::name("canceledBy"), - set::label($lang->task->canceledBy), - set::value($task->canceledBy), - set::control("picker"), - set::items($canceledByOptions) - ), - formGroup - ( - set::name("canceledDate"), - set::label($lang->task->canceledDate), - set::value($task->canceledDate), - set::control("datetime") - ), - formGroup - ( - set::name("closedBy"), - set::label($lang->task->closedBy), - set::value($task->closedBy), - set::control("picker"), - set::items($closedByOptions) - ), - formGroup - ( - set::name("closedReason"), - set::label($lang->task->closedReason), - set::value($task->closedReason), - set::control("picker"), - set::items($closedReasonOptions) - ), - formGroup - ( - set::name("closedDate"), - set::label($lang->task->closedDate), - set::value($task->closedDate), - set::control("datetime") - ), - formRow - ( - set::hidden(true), - formGroup - ( - set::name("team[]"), - set::value("zenggang"), - set::control("picker"), - set::id("team"), - set::items($teamOptions) + $lang->task->legendBasic, + setClass('leading-8') ), formGroup ( - inputGroup - ( - - ) - ) - ), - formRow - ( - set::hidden(true), - formGroup - ( - set::name("team[]"), - set::value("zenggang"), + set::name("execution"), + set::label($lang->task->execution), + set::required(true), + set::value($task->execution), set::control("picker"), - set::id("team"), - set::items($teamOptions) + set::strong(true), + set::items($executionOptions) ), formGroup ( - inputGroup - ( - - ) - ) - ), - formRow - ( - set::hidden(true), - formGroup - ( - set::name("team[]"), + set::name("module"), + set::label($lang->task->module), + set::value($task->module), set::control("picker"), - set::id("team"), - set::items($teamOptions) + set::strong(true), + set::items($moduleOptions) ), formGroup ( - inputGroup - ( - - ) - ) - ), - formRow - ( - set::hidden(true), - formGroup - ( - set::name("team[]"), + set::name("story"), + set::label($lang->task->story), + set::value($task->story), set::control("picker"), - set::id("team"), - set::items($teamOptions) + set::strong(true), + set::items($storyOptions) + ), + (empty($modeText)) + ? formGroup + ( + set::name("mode"), + set::label($lang->task->mode), + set::value($task->mode), + set::control("picker"), + set::strong(true), + set::items($modeOptions) + ) + : label + ( + $modeText ), formGroup ( + set::label($lang->task->assignedTo), + set::strong(true), inputGroup ( - + control(set(array + ( + 'name' => "assignedTo", + 'id' => "assignedTo", + 'value' => $task->assignedTo, + 'disabled' => (!empty($task->team) and $task->mode == 'linear') ? true : false, + 'type' => "picker", + 'items' => $assignedToOptions + ))), + btn(set(array + ( + 'type' => "btn", + 'text' => $lang->task->team, + 'class' => "input-group-btn team-group" + ))) ) - ) - ), - formRow - ( - set::hidden(true), - formGroup - ( - set::name("team[]"), - set::control("picker"), - set::id("team"), - set::items($teamOptions) ), formGroup ( - inputGroup - ( - - ) + set::name("type"), + set::label($lang->task->type), + set::required(true), + set::value($task->type), + set::control("picker"), + set::strong(true), + set::items($typeOptions) + ), + empty($task->children) + ? formGroup + ( + set::name("status"), + set::label($lang->task->status), + set::value($task->status), + set::control("picker"), + set::strong(true), + set::items($statusOptions) ) - ), - formRow - ( - set::hidden(true), + : null, formGroup ( - set::name("team[]"), + set::name("pri"), + set::label($lang->task->pri), + set::value($task->pri), set::control("picker"), - set::id("team"), - set::items($teamOptions) + set::strong(true), + set::items($priOptions) ), formGroup ( + set::label($lang->task->mailto), + set::strong(true), inputGroup ( + control(set(array + ( + 'name' => "mailto[]", + 'id' => "mailto", + 'value' => $task->mailto, + 'type' => "picker", + 'items' => $mailtoOptions, + 'multiple' => true + ))), + control(set(array + ( + 'name' => "contactListMenu", + 'id' => "contactListMenu", + 'value' => "", + 'disabled' => false, + 'type' => "picker", + 'onchange' => "setMailto", + 'items' => $contactListMenuOptions + ))) + ) + ), + h::strong + ( + $lang->task->legendEffort, + setClass('leading-8') + ), + formGroup + ( + set::name("estStarted"), + set::label($lang->task->estStarted), + set::value($task->estStarted), + set::strong(true), + set::control("date") + ), + formGroup + ( + set::name("deadline"), + set::label($lang->task->deadline), + set::value($task->deadline), + set::strong(true), + set::control("date") + ), + formGroup + ( + set::name("estimate"), + set::label($lang->task->estimate), + set::value($task->estimate), + set::strong(true), + set::control("text") + ), + formGroup + ( + set::name("left"), + set::label($lang->task->left), + set::value($task->left), + set::strong(true), + set::control("text") + ), + h::strong + ( + $lang->task->legendLife, + setClass('leading-8') + ), + formGroup + ( + set::name("realStarted"), + set::label($lang->task->realStarted), + set::value(helper::isZeroDate($task->realStarted) ? '' : $task->realStarted), + set::strong(true), + set::control("datetime") + ), + formGroup + ( + set::name("finishedBy"), + set::label($lang->task->finishedBy), + set::value($task->finishedBy), + set::control("picker"), + set::strong(true), + set::items($finishedByOptions) + ), + formGroup + ( + set::name("finishedDate"), + set::label($lang->task->finishedDate), + set::value($task->finishedDate), + set::strong(true), + set::control("datetime") + ), + formGroup + ( + set::name("canceledBy"), + set::label($lang->task->canceledBy), + set::value($task->canceledBy), + set::control("picker"), + set::strong(true), + set::items($canceledByOptions) + ), + formGroup + ( + set::name("canceledDate"), + set::label($lang->task->canceledDate), + set::value($task->canceledDate), + set::strong(true), + set::control("datetime") + ), + formGroup + ( + set::name("closedBy"), + set::label($lang->task->closedBy), + set::value($task->closedBy), + set::control("picker"), + set::strong(true), + set::items($closedByOptions) + ), + formGroup + ( + set::name("closedReason"), + set::label($lang->task->closedReason), + set::value($task->closedReason), + set::control("picker"), + set::strong(true), + set::items($closedReasonOptions) + ), + formGroup + ( + set::name("closedDate"), + set::label($lang->task->closedDate), + set::value($task->closedDate), + set::strong(true), + set::control("datetime") + ), + formRow + ( + set::hidden(true), + formGroup + ( + set::name("team[]"), + set::value("zenggang"), + set::control("picker"), + set::id("team"), + set::strong(true), + set::items($teamOptions) + ), + formGroup + ( + inputGroup + ( + ) + ) + ), + formRow + ( + set::hidden(true), + formGroup + ( + set::name("team[]"), + set::value("zenggang"), + set::control("picker"), + set::id("team"), + set::strong(true), + set::items($teamOptions) + ), + formGroup + ( + inputGroup + ( + + ) + ) + ), + formRow + ( + set::hidden(true), + formGroup + ( + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + inputGroup + ( + + ) + ) + ), + formRow + ( + set::hidden(true), + formGroup + ( + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + inputGroup + ( + + ) + ) + ), + formRow + ( + set::hidden(true), + formGroup + ( + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + inputGroup + ( + + ) + ) + ), + formRow + ( + set::hidden(true), + formGroup + ( + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + inputGroup + ( + + ) ) ) ) - ) ) ); - /* ====== Render page ====== */ render(); diff --git a/module/task/ui/manageteam.html.php b/module/task/ui/manageteam.html.php new file mode 100644 index 0000000000..ab92f5907a --- /dev/null +++ b/module/task/ui/manageteam.html.php @@ -0,0 +1,135 @@ + + * @package task + * @link https://www.zentao.net + */ +namespace zin; + +formPanel +( + set::title($formTitle), // The form title is diffrent from the page title, + formRow + ( + formGroup + ( + set::width("1/3"), + set::name("team[]"), + set::value("productManager"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + set::width("1/3"), + inputGroup + ( + + ) + ) + ), + formRow + ( + formGroup + ( + set::width("1/3"), + set::name("team[]"), + set::value("zenggang"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + set::width("1/3"), + inputGroup + ( + + ) + ) + ), + formRow + ( + formGroup + ( + set::width("1/3"), + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + set::width("1/3"), + inputGroup + ( + + ) + ) + ), + formRow + ( + formGroup + ( + set::width("1/3"), + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + set::width("1/3"), + inputGroup + ( + + ) + ) + ), + formRow + ( + formGroup + ( + set::width("1/3"), + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + set::width("1/3"), + inputGroup + ( + + ) + ) + ), + formRow + ( + formGroup + ( + set::width("1/3"), + set::name("team[]"), + set::control("picker"), + set::id("team"), + set::items($teamOptions) + ), + formGroup + ( + set::width("1/3"), + inputGroup + ( + + ) + ) + ) +); + +render(); + diff --git a/module/task/view/editteam.html.php b/module/task/view/editteam.html.php index 2623b1d505..474c6aae40 100755 --- a/module/task/view/editteam.html.php +++ b/module/task/view/editteam.html.php @@ -37,7 +37,7 @@ -
execution&taskID=$task->id")?>' id='teamForm'> + execution&taskID=$task->id")?>' id='teamForm'> diff --git a/module/task/zen.php b/module/task/zen.php index 618fd03449..c085b3314f 100644 --- a/module/task/zen.php +++ b/module/task/zen.php @@ -22,11 +22,11 @@ class taskZen extends task private $executionPairs = array(); /** - * 准备创建数据。 + * 准备编辑数据。 * Prepare edit data. * * @param form $postDataFixer - * @param int $taskID + * @param int $taskID * @access protected * @return object */ @@ -63,6 +63,7 @@ class taskZen extends task ->setIF($oldTask->parent < 0, 'left', $oldTask->left) ->setIF($oldTask->name != $postData->name || $oldTask->estStarted != $postData->estStarted || $oldTask->deadline != $postData->deadline, 'version', $oldTask->version + 1) + ->add('lastEditedBy', $this->app->user->account) ->add('lastEditedDate', $now) ->stripTags($this->config->task->editor->edit['id'], $this->config->allowedTags) ->join('mailto', ',') @@ -76,12 +77,12 @@ class taskZen extends task * Reponse after edit. * * @param int $taskID - * @param string $from + * @param string $from ''|taskkanban * @param array[] $changes * @access protected - * @return int + * @return array|int */ - protected function reponseAfterEdit(int $taskID, string $from, array $changes) + protected function reponseAfterEdit(int $taskID, string $from, array $changes): array|int { $task = $this->task->getById($taskID); if($task->fromBug != 0) @@ -97,31 +98,7 @@ class taskZen extends task } } - if(isonlybody()) - { - $execution = $this->execution->getByID($task->execution); - $execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all'; - $execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default'; - if(($this->app->tab == 'execution' or ($this->config->vision == 'lite' and $this->app->tab == 'project')) 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') - { - $taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : ''; - $kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue); - $kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData); - $kanbanData = $kanbanData[$kanbanType]; - $kanbanData = json_encode($kanbanData); - - return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)")); - } - return print(js::reload('parent.parent')); - } + if(isonlybody()) return $this->reponseKanban($task, $from); if(defined('RUN_MODE') && RUN_MODE == 'api') return array('status' => 'success', 'data' => $taskID); return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); @@ -141,17 +118,18 @@ class taskZen extends task $tasks = $this->task->getParentTaskPairs($this->view->execution->id, $task->parent); if(isset($tasks[$taskID])) unset($tasks[$taskID]); + /* Prepare to assign to relevant parameters. */ if(!isset($this->view->members[$task->assignedTo])) $this->view->members[$task->assignedTo] = $task->assignedTo; if(isset($this->view->members['closed']) or $task->status == 'closed') $this->view->members['closed'] = 'Closed'; + /* Get the executions of the task. */ $executions = !empty($task->project) ? $this->execution->getByProject($task->project, 'all', 0, true) : array(); /* Get task members. */ $taskMembers = array(); if(!empty($task->team)) { - $teamAccounts = $task->members; - foreach($teamAccounts as $teamAccount) + foreach($task->members as $teamAccount) { if(!isset($this->view->members[$teamAccount])) continue; $taskMembers[$teamAccount] = $this->view->members[$teamAccount]; @@ -176,18 +154,37 @@ class taskZen extends task $this->display(); } + /** + * 准备管理团队的数据。 + * Prepare manage team data. + * + * @param form $postData + * @param int $taskID + * @access protected + * @return object + */ + protected function prepareManageTeam(form $postData, int $taskID): object + { + $now = helper::now(); + $task = $postData->add('id', $taskID) + ->add('lastEditedBy', $this->app->user->account) + ->get(); + return $task; + } + /** * 准备指派给的数据. * Prepare assignto data. * * @param form $postDataFixer - * @param int $taskID + * @param int $taskID * @access protected * @return object */ protected function prepareAssignTo(form $postDataFixer, int $taskID): object { $task = $postDataFixer->add('id', $taskID) + ->add('lastEditedBy', $this->app->user->account) ->stripTags($this->config->task->editor->assignto['id'], $this->config->allowedTags) ->get(); return $task; @@ -198,38 +195,17 @@ class taskZen extends task * Reponse after assignto. * * @param int $taskID + * @param string $from ''|taskkanban * @access protected - * @return int + * @return array|int */ - protected function reponseAfterAssignTo(int $taskID, string $from) + protected function reponseAfterAssignTo(int $taskID, string $from): array|int { - if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return $this->send(array('result' => 'success')); - if(isonlybody()) - { - $task = $this->task->getById($taskID); - $execution = $this->execution->getByID($task->execution); - $execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all'; - $execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default'; - 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); + if($this->viewType == 'json' or (defined('RUN_MODE') && RUN_MODE == 'api')) return array('result' => 'success'); - return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban($kanbanData)")); - } - if($from == 'taskkanban') - { - $taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : ''; - $kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue); - $kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData); - $kanbanData = $kanbanData[$kanbanType]; - $kanbanData = json_encode($kanbanData); + $task = $this->task->getById($taskID); + if(isonlybody()) return $this->reponseKanban($task, $from); - return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)")); - } - return print(js::closeModal('parent.parent', 'this')); - } return print(js::locate($this->createLink('task', 'view', "taskID=$taskID"), 'parent')); } @@ -237,16 +213,17 @@ class taskZen extends task * 构建指派给表格。 * Build AssignTo Form. * - * @param int $executionID - * @param object $task + * @param int $executionID + * @param int $taskID * @access protected * @return void */ - protected function buildAssignToForm(int $executionID, object $task): void + protected function buildAssignToForm(int $executionID, int $taskID): void { $this->loadModel('action'); $members = $this->loadModel('user')->getTeamMemberPairs($executionID, 'execution', 'nodeleted'); + $task = $this->task->getByID($taskID); /* Compute next assignedTo. */ if(!empty($task->team) and strpos('done,cencel,closed', $task->status) === false) { @@ -265,6 +242,43 @@ class taskZen extends task $this->display(); } + /** + * 返回看板下响应。 + * Reposn from kanban. + * + * @param object $task + * @param string $from ''|taskkanban + * @access private + * @return int + */ + private function reponseKanban(object $task, string $from): int + { + $execution = $this->execution->getByID($task->execution); + $execLaneType = $this->session->execLaneType ? $this->session->execLaneType : 'all'; + $execGroupBy = $this->session->execGroupBy ? $this->session->execGroupBy : 'default'; + + $inLiteKanban = $this->config->vision == 'lite' and $this->app->tab == 'project' and $this->session->kanbanview == 'kanban'; + if(($this->app->tab == 'execution' or $inLiteKanban) 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') + { + $taskSearchValue = $this->session->taskSearchValue ? $this->session->taskSearchValue : ''; + $kanbanData = $this->loadModel('kanban')->getExecutionKanban($task->execution, $execLaneType, $execGroupBy, $taskSearchValue); + $kanbanType = $execLaneType == 'all' ? 'task' : key($kanbanData); + $kanbanData = $kanbanData[$kanbanType]; + $kanbanData = json_encode($kanbanData); + + return print(js::closeModal('parent.parent', '', "parent.parent.updateKanban(\"task\", $kanbanData)")); + } + return print(js::closeModal('parent.parent', 'this')); + } + /** * 设置任务二级导航。 * Set the task secondary navigation. diff --git a/module/todo/js/common.ui.js b/module/todo/js/common.ui.js index 5ef4c517ee..03ea9b445f 100644 --- a/module/todo/js/common.ui.js +++ b/module/todo/js/common.ui.js @@ -126,7 +126,7 @@ function loadList(type, id, objectID) * 选择开始时间后,自动给出默认终止时间。 * After selecting the start time, the default end time is automatically given. * - * @return viod + * @return void */ function selectNext() { @@ -135,49 +135,6 @@ function selectNext() $('#end').trigger('chosen:updated'); } -function setBeginsAndEnds(i, beginOrEnd) -{ - if(!i) - { - for(j = 0; j < batchCreateNum; j++) - { - if(j != 0) $('#begins' + j)[0].selectedIndex = $('#ends' + (j - 1))[0].selectedIndex; - $('#ends' + j)[0].selectedIndex = $('#begins' + j)[0].selectedIndex + 3; - $('#begins' + j, '#ends' + j).trigger('chosen:updated'); - } - } - else - { - if(beginOrEnd == 'begin') - { - $('#ends' + i)[0].selectedIndex = $('#begins' + i)[0].selectedIndex + 3; - $('#ends' + i).trigger('chosen:updated'); - } - - if(batchCreateNum) - { - for(j = i+1; j < batchCreateNum; j++) - { - $('#begins' + j)[0].selectedIndex = $('#ends' + (j - 1))[0].selectedIndex; - $('#ends' + j)[0].selectedIndex = $('#begins' + j)[0].selectedIndex + 3; - $('#begins' + j, '#ends' + j).trigger('chosen:updated'); - } - } - } -} - -function switchTimeList(number) -{ - if($('#switchTime' + number).prop('checked')) - { - $('#begins' + number, '#ends' + number).attr('disabled', 'disabled').trigger('chosen:updated'); - } - else - { - $('#begins' + number, '#ends' + number).removeAttr('disabled').trigger('chosen:updated'); - } -} - /** * 切换起止时间的禁用状态。 * Switch the disabled state of start and end time. @@ -238,7 +195,7 @@ function showEvery(switcher) * 周期设置为天并为指定时,更改月份时获取天数。 * When the cycle is set to days and specified, obtain the number of days when changing the month. * - * @param int $specifiedMonth + * @param int specifiedMonth * @return void */ function setDays(specifiedMonth) @@ -259,3 +216,16 @@ function setDays(specifiedMonth) $('#specifiedDay').append(html); } } + +/** + * 更改日期。 + * Change date. + * + * @param object dateInput + * @return void + */ +function changeDate(dateInput) +{ + console.log(dateInput); + $('#switchDate').prop('checked', !$(dateInput).val()); +} diff --git a/module/todo/js/create.ui.js b/module/todo/js/create.ui.js index 603e91b2b8..3213cb8f24 100644 --- a/module/todo/js/create.ui.js +++ b/module/todo/js/create.ui.js @@ -4,7 +4,7 @@ selectNext(); * 切换周期类型,用于展示周期类型的交互。 * Toggle cycle, used to display the interaction of cycle. * - * @param object tab + * @param object switcher * @return void */ function toggleCycle(switcher) @@ -31,12 +31,12 @@ function toggleCycle(switcher) * 更改待办日期。 * Change todo date. * - * @param object tab + * @param object dateInput * @return void */ function changeCreateDate(dateInput) { - $('#switchDate').prop('checked', !$(dateInput).val()); + changeDate(dateInput); var selectTime = $(dateInput).val() != today ? start : nowTime; $('#begin').val(selectTime); $('#begin').trigger('chosen:updated'); diff --git a/module/todo/test/model/getlist.php b/module/todo/test/model/getlist.php index 001a6550d0..897fb247ea 100755 --- a/module/todo/test/model/getlist.php +++ b/module/todo/test/model/getlist.php @@ -2,7 +2,7 @@ config('getlist')->gen(9); global $tester; $tester->loadModel('todo'); + $day = date('Y-m-d'); //今天 -$lastday = date("Y-m-d", strtotime("-1 day")); //昨天 +$lastday = date('Y-m-d', strtotime('-1 day')); //昨天 $week = date('Y-m-d', (time() - ((date('w') == 0 ? 7 : date('w')) - 1) * 24 * 3600)); //本周一 $month = date('Y-m-01'); //本月1日 -$lastweekday = date("Y-m-d", strtotime("-7 day")); //上周的今天 +$lastweekday = date('Y-m-d', strtotime('-7 day')); //上周的今天 $season = ceil((date('n')) / 3); //当月是第几季度 $season = date('Y-m-d', mktime(0, 0, 0, (int)$season * 3 - 3 + 1, 1, (int)date('Y'))); //本季度第一天 @@ -36,14 +37,14 @@ $lastDayNum = '2'; //修改天数为昨天的数量 $last7DayNum = '1'; //修改天数为7天前的数量 r($tester->todo->editDate(array(1), date('Y-m-d'))) && p() && e('1'); // 修改id为1的待办的日期 -r($tester->todo->editDate(array(2, 3), date("Y-m-d", strtotime("-1 day")))) && p() && e('1'); // 修改id为2,3的待办的日期 +r($tester->todo->editDate(array(2, 3), date('Y-m-d', strtotime('-1 day')))) && p() && e('1'); // 修改id为2,3的待办的日期 r($tester->todo->editDate(array(4), $lastweekday)) && p() && e('1'); // 修改id为2,3的待办的日期 /* 本周上周实际待办数量 */ $thisWeekNum = $dayNum; $lastWeekNum = $lastDayNum; -if(date("w") != 1){ +if(date('w') != 1){ $thisWeekNum = $dayNum + $lastDayNum; $lastWeekNum = $defaultNum; } @@ -53,7 +54,7 @@ if(strtotime($week)- 7*86400 <= strtotime($lastweekday)) $lastWeekNum += $last7D $thisMonthNum = $dayNum; $lastMonthNum = $lastweekday == $month ? $defaultNum : $last7DayNum; if(strtotime($month) <= strtotime($lastday)) $thisMonthNum += $lastDayNum; -if(date("w") == 1) $thisMonthNum += $last7DayNum; +if(date('w') == 1) $thisMonthNum += $last7DayNum; if($month == $day) $lastMonthNum += $lastDayNum; /* 本季度实际待办数量 */ @@ -65,7 +66,7 @@ $thisweek = $todo->getListTest($typeList[2]) == $thisWeekNum ? '1' : '0'; $lastweek = $todo->getListTest($typeList[3]) == $lastWeekNum ? '1' : '0'; $thismonth = $todo->getListTest($typeList[4]) == $thisMonthNum ? '1' : '0'; $lastmonth = $todo->getListTest($typeList[5]) == $lastMonthNum ? '1' : '0'; -$thisSeason = $todo->getListTest($typeList[6]) == $thisSeasonNum ? '1' : '0'; +$thisseason = $todo->getListTest($typeList[6]) == $thisSeasonNum ? '1' : '0'; r($thisweek) && p() && e('1'); // 获取type为thisweek 当前用户的代办数量 r($lastweek) && p() && e('1'); // 获取type为lastweek 当前用户的代办数量 diff --git a/module/todo/test/model/update.php b/module/todo/test/model/update.php index 7267be901d..53311e091a 100755 --- a/module/todo/test/model/update.php +++ b/module/todo/test/model/update.php @@ -11,7 +11,7 @@ function initData() /** -title=测试 todoModel::update; +title=测试 todoModel->update(); timeout=0 cid=1 diff --git a/module/todo/test/todo.class.php b/module/todo/test/todo.class.php index c987af6b01..36883744b2 100755 --- a/module/todo/test/todo.class.php +++ b/module/todo/test/todo.class.php @@ -374,7 +374,7 @@ class todoTest * @access public * @return array */ - public function getByExportListTest(string $orderBy, string $queryCondition , string $checkedItem): array + public function getByExportListTest(string $orderBy, string $queryCondition, string $checkedItem): array { return $this->objectModel->getByExportList($orderBy, $queryCondition, $checkedItem); } diff --git a/module/todo/ui/assignto.html.php b/module/todo/ui/assignto.html.php index 59d2e283cf..05e531f61c 100755 --- a/module/todo/ui/assignto.html.php +++ b/module/todo/ui/assignto.html.php @@ -31,9 +31,11 @@ formPanel set::width('1/2'), input ( + set::class('date'), set::name('date'), set::type('date'), - set::value(date('Y-m-d')) + set::value(date('Y-m-d')), + on::change('changeDate(this)') ) ), formGroup @@ -41,6 +43,7 @@ formPanel set::class(array('items-center', 'pl-2')), checkbox ( + set::id('switchDate'), set::name('future'), set::text($lang->todo->periods['future']), on::change('togglePending(this)') diff --git a/module/todo/ui/edit.html.php b/module/todo/ui/edit.html.php index 4599cb0d26..ef2a096a69 100644 --- a/module/todo/ui/edit.html.php +++ b/module/todo/ui/edit.html.php @@ -49,9 +49,8 @@ else * Build date control for off-cycle todo display. * * @param object $todo - * @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型。 */ -function buildDateControl(object $todo): mixed +function buildDateControl(object $todo) { global $lang; @@ -78,7 +77,7 @@ function buildDateControl(object $todo): mixed 'type' => 'date', 'width' => '1/4' )), - on::change('changeCreateDate(this)') + on::change('changeDate(this)') ), ), formGroup @@ -102,17 +101,294 @@ function buildDateControl(object $todo): mixed } /** - * 构建周期类型和设置。 - * Build cycle types and settings. + * 构建周期为天的设置。 + * Build setting with cycle of day. * * @param object $todo - * @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型。 */ -function buildCycleConfig(object $todo): mixed +function buildCycleOfDayConfig(object $todo) +{ + global $lang; + return formRow + ( + set::class('cycle-config cycle-type-detail type-day hidden'), + + formGroup + ( + set(array + ( + 'label' => $lang->todo->cycleConfig, + 'required' => true, + 'width' => '1/3' + )), + inputGroup + ( + + set::class('have-fix'), + span + ( + set::class('input-group-addon justify-center'), + $lang->todo->from + ), + input(set(array + ( + 'id' => 'date', + 'name' => 'date', + 'type' => 'date', + 'value' => $todo->date + ))), + ) + ), + div + ( + set::class('config-day flex items-center highlight-suffix'), + span + ( + set::class('input-group-addon ring-0 bg-white'), + $lang->todo->every + ), + + inputControl + ( + + set::suffix($lang->todo->cycleDay), + set::suffixWidth('30'), + input + ( + set::id('everyInput'), + set::name('config[day]'), + set::value(isset($todo->config->day) ? $todo->config->day : '') + ) + ) + ) + ); +} + +/** + * 构建周期为周的设置。 + * Build setting with cycle of week. + * + * @param object $todo + */ +function buildCycleOfWeekConfig(object $todo) { global $lang; - if(!$todo->cycle) return null; + return formRow + ( + set::class('cycle-config cycle-type-detail type-week hidden'), + + formGroup + ( + set(array + ( + 'label' => $lang->todo->cycleConfig, + 'required' => true, + 'width' => '1/2' + )), + inputGroup + ( + set::class('have-fix'), + span + ( + set::class('input-group-addon'), + $lang->todo->weekly + ), + select(set(array + ( + 'id' => 'config[week]', + 'name' => 'config[week]', + 'items' => $lang->todo->dayNames, + 'value' => $todo->config->week + ))) + ) + ) + ); +} + +/** + * 构建周期为月的设置。 + * Build setting with cycle of month. + * + * @param object $todo + */ +function buildCycleOfMonthConfig(object $todo) +{ + global $lang; + + $days = array(); + for($day = 1; $day <= 31; $day ++) $days[$day] = $day . $lang->todo->day; + + return formRow + ( + set::class('cycle-config cycle-type-detail type-month hidden'), + + formGroup + ( + set(array + ( + 'label' => $lang->todo->cycleConfig, + 'required' => true, + 'class' => 'have-fix', + 'width' => '1/2' + )), + inputGroup + ( + + span + ( + set::class('input-group-addon'), + $lang->todo->monthly + ), + select(set(array + ( + 'id' => 'config[month]', + 'name' => 'config[month]', + 'items' => $days, + 'value' => $todo->config->month + ))) + ) + ) + ); +} + +/** + * 构建周期为年的设置。 + * Build setting with cycle of year. + * + * @param object $todo + */ +function buildCycleOfYearConfig(object $todo) +{ + global $lang; + + $days = array(); + for($day = 1; $day <= 31; $day ++) $days[$day] = $day . $lang->todo->day; + + return formRow + ( + set::class('cycle-config cycle-type-detail type-year hidden'), + + formGroup + ( + set(array + ( + 'label' => $lang->todo->cycleConfig, + 'required' => true, + 'class' => 'have-fix', + 'width' => '1/2' + )), + inputGroup + ( + span + ( + set::class('input-group-addon'), + $lang->todo->specify + ), + select + ( + set(array + ( + 'id' => 'config[specify][month]', + 'name' => 'config[specify][month]', + 'items' => $lang->datepicker->monthNames, + 'multiple' => false, + 'value' => isset($todo->config->specify->month) ? $todo->config->specify->month : 0 + )), + on::change('setDays(this.value)') + ), + select(set(array + ( + 'id' => 'specifiedDay', + 'name' => 'config[specify][day]', + 'items' => $days, + 'multiple' => false, + 'value' => isset($todo->config->specify->day) ? $todo->config->specify->day : 1 + ))) + ) + ) + ); + +} + +/** + * 构建生成待办控件。 + * Build generating todo control. + * + * @param object $todo + */ +function buildBeforeDays($todo) +{ + global $lang; + + return formRow + ( + set::class('cycle-config'), + formGroup + ( + set(array + ( + 'label' => $lang->todo->generate, + 'class' => 'have-fix highlight-suffix', + 'width' => '1/3' + )), + inputControl + ( + set::prefix($lang->todo->advance), + set::prefixWidth('42'), + input(set(array + ( + 'class' => 'before-days', + 'name' => 'config[beforeDays]', + 'value' => $todo->config->beforeDays + ))), + to::suffix($lang->todo->cycleDay), + set::suffixWidth('30') + ) + ) + ); + +} + +/** + * 构建周期时间控件。 + * Build deadline control. + * + * @param object $todo + */ +function buildDeadline($todo) +{ + global $lang; + return formRow + ( + set::class('cycle-config'), + formGroup + ( + set(array + ( + 'label' => $lang->todo->deadline, + 'width' => '1/3', + )), + input(set(array + ( + 'type' => 'date', + 'name' => 'config[end]', + 'value' => $todo->config->end + ))) + ) + + ); +} + +/** + * 构建周期类型。 + * Build cycle type. + * + * @param object $todo + */ +function buildCycleType(object $todo) +{ + global $lang; $cycleTypeOptions = array ( @@ -121,242 +397,52 @@ function buildCycleConfig(object $todo): mixed array('text' => $lang->todo->cycleMonth, 'value' => 'month'), array('text' => $lang->todo->cycleYear, 'value' => 'year') ); + return formRow + ( + set::class('cycle-config'), + formGroup + ( + set::label($lang->todo->cycleType), + set::required(true), + radioList + ( + set(array + ( + 'name' => 'cycleType', + 'id' => 'cycleType', + 'value' => $todo->config->type, + 'inline' => true, + 'items' => $cycleTypeOptions + )), + on::change('changeCycleType') + ) + ) + ); - $days = array(); - for($day = 1; $day <= 31; $day ++) $days[$day] = $day . $lang->todo->day; +} + +/** + * 构建周期类型和设置。 + * Build cycle types and settings. + * + * @param object $todo + * @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型。 + */ +function buildCycleConfig(object $todo) +{ + global $lang; + + if(!$todo->cycle) return null; return fragment ( - formRow - ( - set::class('cycle-config'), - formGroup - ( - set::label($lang->todo->cycleType), - set::required(true), - radioList - ( - set(array - ( - 'name' => 'cycleType', - 'id' => 'cycleType', - 'value' => $todo->config->type, - 'inline' => true, - 'items' => $cycleTypeOptions - )), - on::change('changeCycleType') - ) - ) - ), - - formRow - ( - set::class('cycle-config cycle-type-detail type-day hidden'), - - formGroup - ( - set(array - ( - 'label' => $lang->todo->cycleConfig, - 'required' => true, - 'width' => '1/3' - )), - inputGroup - ( - - set::class('have-fix'), - span - ( - set::class('input-group-addon justify-center'), - $lang->todo->from - ), - input(set(array - ( - 'id' => 'date', - 'name' => 'date', - 'type' => 'date', - 'value' => $todo->date - ))), - ) - ), - div - ( - set::class('config-day flex items-center highlight-suffix'), - span - ( - set::class('input-group-addon ring-0 bg-white'), - $lang->todo->every - ), - - inputControl - ( - - set::suffix($lang->todo->cycleDay), - set::suffixWidth('30'), - input - ( - set::id('everyInput'), - set::name('config[day]'), - set::value(isset($todo->config->day) ? $todo->config->day : '') - ) - ) - ) - ), - - formRow - ( - set::class('cycle-config cycle-type-detail type-week hidden'), - - formGroup - ( - set(array - ( - 'label' => $lang->todo->cycleConfig, - 'required' => true, - 'width' => '1/2' - )), - inputGroup - ( - set::class('have-fix'), - span - ( - set::class('input-group-addon'), - $lang->todo->weekly - ), - select(set(array - ( - 'id' => 'config[week]', - 'name' => 'config[week]', - 'items' => $lang->todo->dayNames, - 'value' => $todo->config->week - ))) - ) - ) - ), - formRow - ( - set::class('cycle-config cycle-type-detail type-month hidden'), - - formGroup - ( - set(array - ( - 'label' => $lang->todo->cycleConfig, - 'required' => true, - 'class' => 'have-fix', - 'width' => '1/2' - )), - inputGroup - ( - - span - ( - set::class('input-group-addon'), - $lang->todo->monthly - ), - select(set(array - ( - 'id' => 'config[month]', - 'name' => 'config[month]', - 'items' => $days, - 'value' => $todo->config->month - ))) - ) - ) - ), - formRow - ( - set::class('cycle-config cycle-type-detail type-year hidden'), - - formGroup - ( - set(array - ( - 'label' => $lang->todo->cycleConfig, - 'required' => true, - 'class' => 'have-fix', - 'width' => '1/2' - )), - inputGroup - ( - span - ( - set::class('input-group-addon'), - $lang->todo->specify - ), - select - ( - set(array - ( - 'id' => 'config[specify][month]', - 'name' => 'config[specify][month]', - 'items' => $lang->datepicker->monthNames, - 'multiple' => false, - 'value' => isset($todo->config->specify->month) ? $todo->config->specify->month : 0 - )), - on::change('setDays(this.value)') - ), - select(set(array - ( - 'id' => 'specifiedDay', - 'name' => 'config[specify][day]', - 'items' => $days, - 'multiple' => false, - 'value' => isset($todo->config->specify->day) ? $todo->config->specify->day : 1 - ))) - ) - ) - ), - - - formRow - ( - set::class('cycle-config'), - formGroup - ( - set(array - ( - 'label' => $lang->todo->generate, - 'class' => 'have-fix highlight-suffix', - 'width' => '1/3' - )), - inputControl - ( - set::prefix($lang->todo->advance), - set::prefixWidth('42'), - input(set(array - ( - 'class' => 'before-days', - 'name' => 'config[beforeDays]', - 'value' => $todo->config->beforeDays - ))), - to::suffix($lang->todo->cycleDay), - set::suffixWidth('30') - ) - ) - ), - - formRow - ( - set::class('cycle-config'), - formGroup - ( - set(array - ( - 'label' => $lang->todo->deadline, - 'width' => '1/3', - )), - input(set(array - ( - 'type' => 'date', - 'name' => 'config[end]', - 'value' => $todo->config->end - ))) - ) - ) - + buildCycleType($todo), + buildCycleOfDayConfig($todo), + buildCycleOfWeekConfig($todo), + buildCycleOfMonthConfig($todo), + buildCycleOfYearConfig($todo), + buildDeadline($todo) ); - } /** diff --git a/module/tree/model.php b/module/tree/model.php index 1f8c61c4c3..10ee28493f 100644 --- a/module/tree/model.php +++ b/module/tree/model.php @@ -2046,7 +2046,7 @@ class treeModel extends model break; } if(strpos($this->session->{$module->type . 'List'}, 'param=' . $moduleID)) $this->session->set($module->type . 'List', str_replace('param=' . $moduleID, 'param=0', $this->session->{$module->type . 'List'})); - if($cookieName) setcookie($cookieName, 0, time() - 3600, $this->config->webRoot, '', $this->config->cookieSecure, false); + if($cookieName) setcookie($cookieName, 0, time() - 3600, $this->config->webRoot, '', $this->config->cookieSecure, true); return true; } diff --git a/test/data/block.yaml b/test/data/block.yaml index a1091c08e0..b6b79656a0 100644 --- a/test/data/block.yaml +++ b/test/data/block.yaml @@ -4,25 +4,3 @@ version: "1.0" fields: - field: id range: 1-10000 - - field: account - fields: - - field: account1 - range: - - field: account2 - range: - - field: module - range: my{16},product{5},project{5},qa{4} - - field: title - range: '[欢迎,最新动态,我的贡献,待处理,我的待办,项目统计,我近期参与的项目,项目人力投入,项目列表,版本列表,执行统计,执行总览,执行列表,任务列表,产品统计,测试统计,产品统计,未关闭的产品,指派给我的软件需求,发布列表,计划列表,项目概况,迭代列表,待测版本,迭代总览,最新动态,测试统计,由我创建的Bug,指派给我的用例,所有版本列表]' - - field: source - range: '[]{4},todo,project{4},execution{5},product,qa,product{5},project{5},qa{4}' - - field: params - range: '[]{3},`{"todoCount":"20","taskCount":"20","bugCount":"20","riskCount":"20","issueCount":"20","storyCount":"20","meetingCount":"20"}`,`{"count":"10"}`,`{"type":"undone","count":"15"}`, , ,`{"orderBy":"id_desc","count":"15"}`,`{"count":"20"}`,`{"type":"undone","count":"20"}`, ,`{"type":"doing","count":"20"}`,`{"type":"assignedTo","count":"20","orderBy":"id_desc"}`,`{"type":"all","count":"20"}`,`{"type":"all","count":"20"}`,`{"type":"closed","count":"20"}`,`{"count":"15","type":"noclosed"}`,`{"count":"15","orderBy":"id_desc","type":"assignedTo"}`,`{"count":"10"}`,`{"count":"10"}`,`{"count":"10"}`,`{"type":"involved","count":"10"}`,`{"type":"wait","count":"15"}`, , ,`{"type":"noclosed","count":"20"}`,`{"count":"15","orderBy":"id_asc","type":"openedBy"}`,`{"count":"15","orderBy":"pri_asc","type":"assigntome"}`,`{"count":"15","orderBy":"id_desc","type":"all"}`' - - field: order - range: 1-16,1-5,1-5,1-4 - - field: grid - range: 8{2},4,8,4{3},8{4},4,8{5},4{3},8,4{2},8{4},4{2},8 - - field: height - range: 0 - - field: hidden - range: 0 diff --git a/test/data/branch.yaml b/test/data/branch.yaml index 6617f10ca2..6c61444ab9 100644 --- a/test/data/branch.yaml +++ b/test/data/branch.yaml @@ -16,6 +16,8 @@ fields: range: 分支 - field: name2 range: 1-10000 + - field: desc + range: "" - field: status range: active,closed - field: order @@ -25,6 +27,10 @@ fields: postfix: "" loop: 0 format: "" + - field: createdDate + range: "(-3M)-(+M):1D" + type: timestamp + format: "YY/MM/DD" - field: deleted note: "是否删除" range: 0 diff --git a/test/data/effort.yaml b/test/data/effort.yaml index 16699b5e26..2d2d853e38 100644 --- a/test/data/effort.yaml +++ b/test/data/effort.yaml @@ -24,6 +24,8 @@ fields: postfix: "" loop: 0 format: "" + - field: extra + range: "extra" - field: product note: "产品ID" range: "0" @@ -44,7 +46,7 @@ fields: - field: account1 range: admin,user{99} - field: account2 - range: [],1-99 + range: "[],1-99" format: "" - field: work note: "工作内容" diff --git a/test/data/taskteam.yaml b/test/data/taskteam.yaml new file mode 100644 index 0000000000..3325de3450 --- /dev/null +++ b/test/data/taskteam.yaml @@ -0,0 +1,29 @@ +title: table zt_taskteam +desc: "系统日志" +author: automated export +version: "1.0" +fields: + - field: id + range: 1-1000 + - field: task + range: 1-50 + - field: left + range: 0-3 + - field: estimate + range: 1-10{2} + - field: consumed + range: 1,3,0,2 + - field: account + note: "用户账号" + fields: + - field: account1 + range: admin,user{99} + - field: account2 + range: "[],1-99" + - field: status + range: done,doing,wait,doing + - field: transfer + range: "[]" + - field: order + range: 1-1000 + diff --git a/test/data/zt_block.sql b/test/data/zt_block.sql index 17e581eeab..2905f9d53c 100644 --- a/test/data/zt_block.sql +++ b/test/data/zt_block.sql @@ -1,36 +1 @@ truncate `zt_block`; -INSERT INTO `zt_block` (`id`, `account`, `vision`, `module`, `type`, `title`, `source`, `block`, `params`, `order`, `grid`, `height`, `hidden`) VALUES -(102, 'admin', 'rnd', 'my', '', '待处理', '', 'assigntome', '{\"todoCount\":\"20\",\"taskCount\":\"20\",\"bugCount\":\"20\",\"riskCount\":\"20\",\"issueCount\":\"20\",\"storyCount\":\"20\",\"meetingCount\":\"20\"}', 8, 8, 0, 0), -(101, 'admin', 'rnd', 'my', '', '我近期参与的项目', 'project', 'recentproject', '', 7, 8, 0, 0), -(100, 'admin', 'rnd', 'my', '', '我的贡献', '', 'contribute', '', 6, 4, 0, 0), -(97, 'admin', 'rnd', 'my', '', '流程图', '', 'flowchart', '', 3, 8, 0, 0), -(98, 'admin', 'rnd', 'my', '', '我的待办', 'todo', 'list', '{\"count\":\"20\"}', 4, 4, 0, 0), -(99, 'admin', 'rnd', 'my', '', '项目统计', 'project', 'statistic', '{\"count\":\"20\"}', 5, 8, 0, 0), -(95, 'admin', 'rnd', 'my', '', '欢迎', '', 'welcome', '', 1, 8, 0, 0), -(96, 'admin', 'rnd', 'my', '', '最新动态', '', 'dynamic', '', 2, 4, 0, 0), -(41, 'admin', 'lite', 'my', '', '欢迎', '', 'welcome', '', 1, 8, 0, 0), -(42, 'admin', 'lite', 'my', '', '最新动态', '', 'dynamic', '', 2, 4, 0, 0), -(43, 'admin', 'lite', 'my', '', '流程图', '', 'flowchart', '', 3, 8, 0, 0), -(44, 'admin', 'lite', 'my', '', '我的待办', 'todo', 'list', '{\"count\":\"20\"}', 4, 4, 0, 0), -(45, 'admin', 'lite', 'my', '', '看板列表', 'execution', 'scrumlist', '{\"count\":\"15\",\"type\":\"doing\",\"orderBy\":\"id_desc\"}', 5, 8, 0, 0), -(46, 'admin', 'lite', 'my', '', '我近期参与的项目', 'project', 'recentproject', '', 7, 8, 0, 0), -(47, 'admin', 'lite', 'my', '', '待处理', '', 'assigntome', '{\"todoCount\":\"20\",\"taskCount\":\"20\",\"bugCount\":\"20\",\"riskCount\":\"20\",\"issueCount\":\"20\",\"storyCount\":\"20\",\"meetingCount\":\"20\"}', 8, 8, 0, 0), -(48, 'admin', 'lite', 'my', '', '项目列表', 'project', 'project', '{\"orderBy\":\"id_desc\",\"count\":\"15\"}', 10, 8, 0, 0), -(110, 'admin', 'rnd', 'qa', '', '待测版本列表', 'qa', 'testtask', '{\"count\":15,\"orderBy\":\"id_desc\",\"type\":\"wait\"}', 4, 8, 0, 0), -(109, 'admin', 'rnd', 'qa', '', '指派给我的用例', 'qa', 'case', '{\"count\":15,\"orderBy\":\"id_desc\",\"type\":\"assigntome\"}', 3, 4, 0, 0), -(108, 'admin', 'rnd', 'qa', '', '指派给我的Bug', 'qa', 'bug', '{\"count\":15,\"orderBy\":\"id_desc\",\"type\":\"assignedTo\"}', 2, 4, 0, 0), -(107, 'admin', 'rnd', 'qa', '', '测试统计', 'qa', 'statistic', '{\"type\":\"noclosed\",\"count\":\"20\"}', 1, 8, 0, 0), -(53, '', 'rnd', 'my', '', '欢迎', '', 'welcome', '', 1, 8, 0, 0), -(54, '', 'rnd', 'my', '', '最新动态', '', 'dynamic', '', 2, 4, 0, 0), -(55, '', 'rnd', 'my', '', '流程图', '', 'flowchart', '', 3, 8, 0, 0), -(56, '', 'rnd', 'my', '', '我的待办', 'todo', 'list', '{\"count\":\"20\"}', 4, 4, 0, 0), -(57, '', 'rnd', 'my', '', '项目统计', 'project', 'statistic', '{\"count\":\"20\"}', 5, 8, 0, 0), -(58, '', 'rnd', 'my', '', '我的贡献', '', 'contribute', '', 6, 4, 0, 0), -(59, '', 'rnd', 'my', '', '我近期参与的项目', 'project', 'recentproject', '', 7, 8, 0, 0), -(60, '', 'rnd', 'my', '', '待处理', '', 'assigntome', '{\"todoCount\":\"20\",\"taskCount\":\"20\",\"bugCount\":\"20\",\"riskCount\":\"20\",\"issueCount\":\"20\",\"storyCount\":\"20\",\"meetingCount\":\"20\"}', 8, 8, 0, 0), -(61, '', 'rnd', 'my', '', '项目人力投入', 'project', 'projectteam', '', 9, 8, 0, 0), -(62, '', 'rnd', 'my', '', '项目列表', 'project', 'project', '{\"orderBy\":\"id_desc\",\"count\":\"15\"}', 10, 8, 0, 0), -(106, 'admin', 'rnd', 'project', 'waterfall', '最新动态', 'project', 'projectdynamic', '', 6, 4, 0, 0), -(105, 'admin', 'rnd', 'project', 'waterfall', '项目计划', 'project', 'waterfallgantt', '', 3, 8, 0, 0), -(103, 'admin', 'rnd', 'my', '', '项目人力投入', 'project', 'projectteam', '', 9, 8, 0, 0), -(104, 'admin', 'rnd', 'my', '', '项目列表', 'project', 'project', '{\"orderBy\":\"id_desc\",\"count\":\"15\"}', 10, 8, 0, 0); diff --git a/test/data/zt_block.yaml b/test/data/zt_block.yaml index 59638d88af..76452f2624 100644 --- a/test/data/zt_block.yaml +++ b/test/data/zt_block.yaml @@ -4,80 +4,4 @@ author: automated export version: "1.0" fields: - field: id - note: "Id" range: 1-10000 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: account - note: "所属用户" - from: common.user.v1.yaml - use: user - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: module - note: "所属模块" - range: product,project,qa,my - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: title - note: "区块名称" - range: 1-10000 - prefix: "这是区块名称" - postfix: "" - loop: 0 - format: "" - - field: source - range: 0,todo,project,qa,product - note: "来源模块" - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: block - note: "来源区块" - range: product,project,qa,todo,assigntome,dynamic,flowchart,welcome,html,statistic,overview,list,story,plan,release,task,build,bug,case,testtask - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: params - note: "设置参数" - range: 1-10000 - prefix: "这是json格式参数" - postfix: "" - loop: 0 - format: "" - - field: order - note: "排序" - range: 1-100 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: grid - note: "位置" - range: 8,4 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: height - note: "高度" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" - - field: hidden - note: "隐藏" - range: 0 - prefix: "" - postfix: "" - loop: 0 - format: "" diff --git a/test/devdata/block.yaml b/test/devdata/block.yaml index fc569bbf3d..b6b79656a0 100644 --- a/test/devdata/block.yaml +++ b/test/devdata/block.yaml @@ -4,29 +4,3 @@ version: "1.0" fields: - field: id range: 1-10000 - - field: account - fields: - - field: account1 - range: - - field: account2 - range: - - field: module - range: my{16},product{5},project{5},qa{4} - - field: type - range: []{21},scrum{5},[]{4} - - field: title - range: [欢迎,最新动态,我的贡献,待处理,我的待办,项目统计,我近期参与的项目,项目人力投入,项目列表,版本列表,执行统计,执行总览,执行列表,任务列表,产品统计,测试统计,产品统计,未关闭的产品,指派给我的软件需求,发布列表,计划列表,项目概况,迭代列表,待测版本,迭代总览,最新动态,测试统计,由我创建的Bug,指派给我的用例,所有版本列表] - - field: source - range: []{4},todo,project{4},execution{5},product,qa,product{5},project{5},qa{4} - - field: block - range: [welcome,dynamic,contribute,assigntome,list,statistic,recentproject,projectteam,project,build,statistic,overview,list,task,statistic,statistic,statistic,list,story,release,plan,scrumoverview,scrumlist,scrumtest,sprint,projectdynamic,statistic,bug,case,testtask] - - field: params - range: []{3},`{"todoCount":"20","taskCount":"20","bugCount":"20","riskCount":"20","issueCount":"20","storyCount":"20","meetingCount":"20"}`,`{"count":"10"}`,`{"type":"undone","count":"15"}`, , ,`{"orderBy":"id_desc","count":"15"}`,`{"count":"20"}`,`{"type":"undone","count":"20"}`, ,`{"type":"doing","count":"20"}`,`{"type":"assignedTo","count":"20","orderBy":"id_desc"}`,`{"type":"all","count":"20"}`,`{"type":"all","count":"20"}`,`{"type":"closed","count":"20"}`,`{"count":"15","type":"noclosed"}`,`{"count":"15","orderBy":"id_desc","type":"assignedTo"}`,`{"count":"10"}`,`{"count":"10"}`,`{"count":"10"}`,`{"type":"involved","count":"10"}`,`{"type":"wait","count":"15"}`, , ,`{"type":"noclosed","count":"20"}`,`{"count":"15","orderBy":"id_asc","type":"openedBy"}`,`{"count":"15","orderBy":"pri_asc","type":"assigntome"}`,`{"count":"15","orderBy":"id_desc","type":"all"}` - - field: order - range: 1-16,1-5,1-5,1-4 - - field: grid - range: 8{2},4,8,4{3},8{4},4,8{5},4{3},8,4{2},8{4},4{2},8 - - field: height - range: 0 - - field: hidden - range: 0 diff --git a/test/model/block/getstorysestimatehours.php b/test/model/block/getstorysestimatehours.php deleted file mode 100755 index 1f4e52e4d7..0000000000 --- a/test/model/block/getstorysestimatehours.php +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env php -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 的预计工时 \ No newline at end of file