From fd306d7c78a85c42e159242ffbd7d83c412b61d3 Mon Sep 17 00:00:00 2001 From: xushenjie Date: Fri, 5 May 2023 01:00:21 +0000 Subject: [PATCH 01/80] + Add unit test yaml data files for todoModel::batchCreate(). --- .../model/yaml/batchcreate/batchcreate.yaml | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 module/todo/test/model/yaml/batchcreate/batchcreate.yaml diff --git a/module/todo/test/model/yaml/batchcreate/batchcreate.yaml b/module/todo/test/model/yaml/batchcreate/batchcreate.yaml new file mode 100644 index 0000000000..8875351c60 --- /dev/null +++ b/module/todo/test/model/yaml/batchcreate/batchcreate.yaml @@ -0,0 +1,33 @@ +title: Batch create todos for todoModel::batchCreate UTC. +desc: Batch create todos for todoModel::batchCreate UTC. +author: xushenjie +version: 1.0.0 + +fields: + - field: account + range: 'admin' + - field: name + range: 1-5 + prefix: '批量待办' + - field: date + range: 1-9 + prefix: '2023-04-2' + - field: type + range: 'custom' + - field: begin + range: 1000-1100 + - field: end + range: 1200-1300 + - field: assignedTo + range: 'admin' + - field: desc + range: 1-5 + prefix: '批量待办描述' + - field: status + range: 'wait,doing,doing,doing,wait' + - field: objectID + range: 0 + - field: assignedBy + range: 'admin' + - field: pri + range: 1-4 From 462d4957bf17c4cef6ace94e9a9b2008cc2f2320 Mon Sep 17 00:00:00 2001 From: lanzongjun Date: Fri, 5 May 2023 09:29:35 +0800 Subject: [PATCH 02/80] * test --- module/todo/control.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/module/todo/control.php b/module/todo/control.php index a5ea4c66ab..acdca87fd5 100755 --- a/module/todo/control.php +++ b/module/todo/control.php @@ -11,7 +11,10 @@ declare(strict_types=1); */ class todo extends control { + sdasdasdasdasdas /** + * sadasdasd + * * Construct function, load model of task, bug, my. * * @access public From 50687f1555925af2b3baa08f9206701092c47732 Mon Sep 17 00:00:00 2001 From: chentao Date: Fri, 5 May 2023 10:04:34 +0800 Subject: [PATCH 03/80] * product: fix sonar errors. --- module/product/control.php | 6 ++---- module/product/model.php | 4 ++-- module/product/zen.php | 8 ++++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/module/product/control.php b/module/product/control.php index 47da78d20f..c8da60f69e 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -1213,10 +1213,8 @@ class product extends control { return printf($this->lang->build->noProduct, $this->createLink('execution', 'manageproducts', "executionID=$executionID&from=buildCreate", '', 'true'), 'project'); } - else - { - return print(html::select('product', $products, empty($product) ? '' : $product->id, "onchange='loadBranches(this.value);' class='form-control chosen' required data-toggle='modal' data-type='iframe'")); - } + + return print(html::select('product', $products, '', "onchange='loadBranches(this.value);' class='form-control chosen' required data-toggle='modal' data-type='iframe'")); } /** diff --git a/module/product/model.php b/module/product/model.php index 5457ee4085..577443a338 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -1315,7 +1315,7 @@ class productModel extends model { if(in_array($project->model, array('waterfall', 'waterfallplus'))) $hasWaterfall = true; } - $orderBy = $hasWaterfall ? 't2.begin_asc,t2.id_asc' : 't2.begin_desc,t2.id_desc'; + $waterFallOrderBy = $hasWaterfall ? 't2.begin_asc,t2.id_asc' : 't2.begin_desc,t2.id_desc'; $executions = $this->dao->select('t2.id,t2.name,t2.project,t2.grade,t2.path,t2.parent,t2.attribute,t2.multiple,t3.name as projectName')->from(TABLE_PROJECTPRODUCT)->alias('t1') ->leftJoin(TABLE_EXECUTION)->alias('t2')->on('t1.project = t2.id') @@ -1328,7 +1328,7 @@ class productModel extends model ->beginIF(strpos($mode, 'noclosed') !== false)->andWhere('t2.status')->ne('closed')->fi() ->beginIF(strpos($mode, 'multiple') !== false)->andWhere('t2.multiple')->eq('1')->fi() ->andWhere('t2.deleted')->eq('0') - ->orderBy($orderBy) + ->orderBy($waterFallOrderBy) ->fetchAll('id'); /* Only show leaf executions. */ diff --git a/module/product/zen.php b/module/product/zen.php index aaaf765743..ae51a1f4b4 100644 --- a/module/product/zen.php +++ b/module/product/zen.php @@ -79,9 +79,9 @@ class productZen extends product { if($this->app->getViewType() == 'mhtml') return $this->product->setMenu(); - if($moduleName == 'qa') return $this->setShowErrorNoneMenu4QA($activeMenu); - if($moduleName == 'project') return $this->setShowErrorNoneMenu4Project($activeMenu, $objectID); - if($moduleName == 'execution') return $this->setShowErrorNoneMenu4Execution($activeMenu, $objectID); + if($moduleName == 'qa') $this->setShowErrorNoneMenu4QA($activeMenu); + if($moduleName == 'project') $this->setShowErrorNoneMenu4Project($activeMenu, $objectID); + if($moduleName == 'execution') $this->setShowErrorNoneMenu4Execution($activeMenu, $objectID); } /** @@ -401,7 +401,7 @@ class productZen extends product $message = $this->executeHooks($productID); if($message) $this->lang->saveSuccess = $message; - return $this->sendCreateLocate($productID, $programID); + $this->sendCreateLocate($productID, $programID); } /** From d0075f617c75da0edd92adedb35d9e3f8d9b8418 Mon Sep 17 00:00:00 2001 From: jukui Date: Fri, 5 May 2023 10:11:20 +0800 Subject: [PATCH 04/80] * Optimized getList function for todo model. --- module/todo/model.php | 10 +++------- module/todo/tao.php | 10 +++++----- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/module/todo/model.php b/module/todo/model.php index 7c9727be6a..ab286b09bc 100755 --- a/module/todo/model.php +++ b/module/todo/model.php @@ -249,30 +249,26 @@ class todoModel extends model */ public function getList(string $type = 'today', string $account = '', string|array $status = 'all', int $limit = 0, object $pager = null, string $orderBy="date, status, begin"): array { - $todos = array(); $type = strtolower($type); $dateRange = $this->dateRange($type); if(empty($account)) $account = $this->app->user->account; - $stmt = $this->todoTao->getListQuery($type, $account, $status, (string)$dateRange['begin'], (string)$dateRange['end'], $limit, $orderBy, $pager); + $todos = $this->todoTao->getListBy($type, $account, $status, (string)$dateRange['begin'], (string)$dateRange['end'], $limit, $orderBy, $pager); /* Set session. */ $sql = explode('WHERE', $this->dao->get()); $sql = explode('ORDER', $sql[1]); $this->session->set('todoReportCondition', $sql[0]); - while($todo = $stmt->fetch()) + foreach($todos as $todo) { $todo = $this->todoTao->setTodoNameByType($todo); $todo->begin = date::formatTime($todo->begin); $todo->end = date::formatTime($todo->end); - /* If is private, change the title to private. */ if($todo->private and $this->app->user->account != $todo->account) $todo->name = $this->lang->todo->thisIsPrivate; - - $todos[] = $todo; } return $todos; @@ -303,7 +299,7 @@ class todoModel extends model $dateRange['thisseason'] = array('begin' => date::getThisSeason()['begin'], 'end' => date::getThisSeason()['end']); $dateRange['thisyear'] = array('begin' => date::getThisYear()['begin'], 'end' => date::getThisYear()['end']); - return isset($dateRange[$type]) ? $dateRange[$type] : array('begin' => $type, 'end' => $type);; + return isset($dateRange[$type]) ? $dateRange[$type] : array('begin' => $type, 'end' => $type); } /** diff --git a/module/todo/tao.php b/module/todo/tao.php index a341af9768..00413df041 100644 --- a/module/todo/tao.php +++ b/module/todo/tao.php @@ -478,8 +478,8 @@ class todoTao extends todoModel } /** - * 构造待办列表查询语句。 - * Build query for todo list. + * 获取待办列表数据。 + * Get the todo list data. * * @param string $type * @param string $account @@ -490,9 +490,9 @@ class todoTao extends todoModel * @param string $orderBy * @param object $pager * @access protected - * @return object + * @return array */ - protected function getListQuery(string $type, string $account, array|string $status, string $begin, string $end, int $limit, string $orderBy, object $pager = null): object + protected function getListBy(string $type, string $account, array|string $status, string $begin, string $end, int $limit, string $orderBy, object $pager = null): array { return $this->dao->select('*')->from(TABLE_TODO) ->where('deleted')->eq('0') @@ -512,6 +512,6 @@ class todoTao extends todoModel ->orderBy($orderBy) ->beginIF($limit > 0)->limit($limit)->fi() ->page($pager) - ->query(); + ->fetchAll(); } } From 6d6c61ec071055eba4d36f7f6cf6723282115fe1 Mon Sep 17 00:00:00 2001 From: liuruogu Date: Fri, 5 May 2023 10:00:56 +0800 Subject: [PATCH 05/80] * Code review. --- .scannerwork/.sonar_lock | 0 .scannerwork/class-mapping.csv | 0 .scannerwork/report-task.txt | 6 +++++ module/block/control.php | 6 +++-- module/block/js/create.ui.js | 38 ++++++++++++++++++------------ module/block/test/model/create.php | 24 +++++++++---------- module/block/ui/create.html.php | 12 +++++++++- module/block/zen.php | 2 +- 8 files changed, 57 insertions(+), 31 deletions(-) create mode 100644 .scannerwork/.sonar_lock create mode 100644 .scannerwork/class-mapping.csv create mode 100644 .scannerwork/report-task.txt diff --git a/.scannerwork/.sonar_lock b/.scannerwork/.sonar_lock new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.scannerwork/class-mapping.csv b/.scannerwork/class-mapping.csv new file mode 100644 index 0000000000..e69de29bb2 diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt new file mode 100644 index 0000000000..60c38be90c --- /dev/null +++ b/.scannerwork/report-task.txt @@ -0,0 +1,6 @@ +projectKey=zentaopms +serverUrl=http://10.0.1.249:6230 +serverVersion=9.9.0.65466 +dashboardUrl=http://10.0.1.249:6230/dashboard?id=zentaopms +ceTaskId=AYfmgmd5aBmpAvupYydG +ceTaskUrl=http://10.0.1.249:6230/api/ce/task?id=AYfmgmd5aBmpAvupYydG diff --git a/module/block/control.php b/module/block/control.php index 1c975d73cc..ba96ea0975 100755 --- a/module/block/control.php +++ b/module/block/control.php @@ -26,6 +26,7 @@ class block extends control } /** + * 创建区块 * Create a block under a dashboard. * * @param string $dashboard @@ -43,7 +44,7 @@ class block extends control $formData->account = $this->app->user->account; $formData->vision = $this->config->vision; $formData->order = $this->block->getMaxOrderByDashboard($dashboard) + 1; - $formData->params = helper::jsonEncode($formData->params); + $formData->params = json_encode($formData->params); $this->block->create($formData); if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError())); @@ -55,12 +56,13 @@ class block extends control $this->view->module = $module; $this->view->code = $code; $this->view->modules = $this->blockZen->getAvailableModules($dashboard); - $this->view->codes = $this->blockZen->getAvailableBlocks($dashboard, $module); + $this->view->codes = $this->blockZen->getAvailableCodes($dashboard, $module); $this->view->params = $this->blockZen->getAvailableParams($dashboard, $module, $code); $this->display(); } /** + * 编辑区块 * Update a block. * * @param string $dashboard diff --git a/module/block/js/create.ui.js b/module/block/js/create.ui.js index 30424ed14d..9a2e34f9e4 100644 --- a/module/block/js/create.ui.js +++ b/module/block/js/create.ui.js @@ -3,32 +3,40 @@ function getForm(event) const field = $(event.target).attr('id'); const module = $('#module').val(); const code = field == 'module' ? '' : $('#code').val(); - const url = $.createLink('block', 'create', 'dashboard='+ dashboard +'&module=' + module + '&code=' + (code ? code : '')); + const url = $.createLink('block', 'create', 'dashboard=' + dashboard + '&module=' + module + '&code=' + (code ? code : '')); loadPage(url, '#codesRow, #paramsRow'); } -function onParamsTypeChange(event) +/** + * Get block title. + * + * @return void + */ +function onParamsTypeChange() { const lang = config.clientLang; - const $code = document.querySelector('#code'); + const $code = $('#code')[0]; + /* 在项目仪表盘创建的待测版本区块时,直接取类型名称为该区块的标题。*/ + /* When creating a test version block in the project dashboard, directly take the name of the block of type.*/ if($('#module').val() == 'scrumtest' && $('#paramstype').val() != 'all') { $('#title').val($code.options[$code.selectedIndex].text); + return; + } + + const $paramstype = $('#paramstype')[0]; + let blockTitle = ''; + + /* Chinese attributives come first, while other language items have attributives placed after. */ + if(lang.indexOf('zh') >= 0) + { + blockTitle = $paramstype.options[$paramstype.selectedIndex].text + of + $code.options[$code.selectedIndex].text; } else { - const $paramstype = document.querySelector('#paramstype'); - - if(lang.indexOf('zh') >= 0) - { - const blockTitle = $paramstype.options[$paramstype.selectedIndex].text + of + $code.options[$code.selectedIndex].text; - } - else - { - const blockTitle = $code.options[$code.selectedIndex].text + of + $paramstype.options[$paramstype.selectedIndex].text; - } - - $('#title').val(blockTitle); + blockTitle = $code.options[$code.selectedIndex].text + of + $paramstype.options[$paramstype.selectedIndex].text; } + + $('#title').val(blockTitle); } diff --git a/module/block/test/model/create.php b/module/block/test/model/create.php index 9b2c4928bd..9fbb185e38 100755 --- a/module/block/test/model/create.php +++ b/module/block/test/model/create.php @@ -27,7 +27,7 @@ cid=39 - 执行block模块的getByID方法,参数是$newBlockID - 属性account @admin - 属性vision @rnd - - 属性module @my + - 属性dashboard @my - 属性title @区块123 - 属性source @my - 属性block @bug @@ -45,21 +45,21 @@ $tester->loadModel('block'); initData(); $block = new stdclass(); -$block->account = 'admin'; -$block->vision = 'rnd'; -$block->module = 'my'; -$block->title = '区块123'; -$block->order = '5'; +$block->account = 'admin'; +$block->vision = 'rnd'; +$block->dashboard = 'my'; +$block->title = '区块123'; +$block->order = '5'; $accoutTooLangBlock = new stdclass(); -$accoutTooLangBlock->account = 'adminadminadminadminadminadminadminadmin1'; -$accoutTooLangBlock->vision = 'rnd'; -$accoutTooLangBlock->module = 'my'; -$accoutTooLangBlock->title = 'long account'; -$accoutTooLangBlock->order = '5'; +$accoutTooLangBlock->account = 'adminadminadminadminadminadminadminadmin1'; +$accoutTooLangBlock->vision = 'rnd'; +$accoutTooLangBlock->dashboard = 'my'; +$accoutTooLangBlock->title = 'long account'; +$accoutTooLangBlock->order = '5'; $blockTest = new blockTest(); $newBlockID = $blockTest->createTest($block); -r($tester->block->getByID($newBlockID)) && p('account,vision,module,title,order') && e('admin,rnd,my,区块123,5'); // 测试获取正常的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 字段字符超出长度 diff --git a/module/block/ui/create.html.php b/module/block/ui/create.html.php index 5f0836a951..44d94ed86a 100644 --- a/module/block/ui/create.html.php +++ b/module/block/ui/create.html.php @@ -19,6 +19,16 @@ $paramsRows = array(); $showModules = ($dashboard == 'my' and $modules); $showCodes = (($showModules and $module and $codes) or $dashboard != 'my'); +if($module == 'scrumtest' && $code != 'all') +{ + $blockTitle = zget($codes, $code); +} +else +{ + $typeOptions = isset($params['type']['options']) ? $params['type']['options'] : array(); + $blockTitle = (count($typeOptions) ? $typeOptions[array_keys($typeOptions)[0]] . $lang->block->of : '') . zget($codes, $code); +} + foreach($params as $key => $row) { $paramsRows[] = formGroup @@ -79,7 +89,7 @@ form ( set::label($lang->block->name), set::name('title'), - set::value(zget($codes, $code)), + set::value($blockTitle), set::class('form-row'), set::control('input') ), diff --git a/module/block/zen.php b/module/block/zen.php index 9e506df62b..77987914d2 100644 --- a/module/block/zen.php +++ b/module/block/zen.php @@ -59,7 +59,7 @@ class blockZen extends block * @access protected * @return string[]|true */ - protected function getAvailableBlocks($dashboard, $module): array|bool + protected function getAvailableCodes($dashboard, $module): array|bool { if(!$this->selfCall) { From 38f7254d6711a9234fecbb2c2597b0130b28f3f3 Mon Sep 17 00:00:00 2001 From: liuruogu Date: Fri, 5 May 2023 10:19:39 +0800 Subject: [PATCH 06/80] * Code review. --- .scannerwork/report-task.txt | 4 ++-- module/block/ui/create.html.php | 8 ++++---- module/block/zen.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt index 60c38be90c..63ca473f46 100644 --- a/.scannerwork/report-task.txt +++ b/.scannerwork/report-task.txt @@ -2,5 +2,5 @@ projectKey=zentaopms serverUrl=http://10.0.1.249:6230 serverVersion=9.9.0.65466 dashboardUrl=http://10.0.1.249:6230/dashboard?id=zentaopms -ceTaskId=AYfmgmd5aBmpAvupYydG -ceTaskUrl=http://10.0.1.249:6230/api/ce/task?id=AYfmgmd5aBmpAvupYydG +ceTaskId=AYfppPP3aBmpAvupYyeE +ceTaskUrl=http://10.0.1.249:6230/api/ce/task?id=AYfppPP3aBmpAvupYyeE diff --git a/module/block/ui/create.html.php b/module/block/ui/create.html.php index 44d94ed86a..afdbc6863d 100644 --- a/module/block/ui/create.html.php +++ b/module/block/ui/create.html.php @@ -42,7 +42,7 @@ foreach($params as $key => $row) 'id' => "params$key", 'type' => $row['control'], 'items' => isset($row['options']) ? $row['options'] : null - )) + )) ); } @@ -61,7 +61,7 @@ form ( 'type' => 'select', 'items' => $modules - ) : 'input') + ) : 'input') ), div ( @@ -91,7 +91,7 @@ form set::name('title'), set::value($blockTitle), set::class('form-row'), - set::control('input') + set::control('input') ), $paramsRows, formGroup @@ -103,7 +103,7 @@ form ( 'type' => 'select', 'items' => $lang->block->gridOptions - )) + )) ) ) ) diff --git a/module/block/zen.php b/module/block/zen.php index 77987914d2..2180e4476c 100644 --- a/module/block/zen.php +++ b/module/block/zen.php @@ -4,14 +4,14 @@ class blockZen extends block /** * 添加或编辑区块时获取可使用的模块选项 * Get module options when adding or editing blocks. - * + * * @param string $dashboard * @access protected * @return string[] */ protected function getAvailableModules(string $dashboard): array { - if($dashboard != 'my') return array(); + if($dashboard != 'my') return array(); $modules = $this->lang->block->moduleList; unset($modules['doc']); From f76e521eca7e789f3cf35952efdefd2bdfb6da28 Mon Sep 17 00:00:00 2001 From: liuruogu Date: Fri, 5 May 2023 10:33:41 +0800 Subject: [PATCH 07/80] * Code review. --- .scannerwork/.sonar_lock | 0 .scannerwork/class-mapping.csv | 0 .scannerwork/report-task.txt | 6 ------ 3 files changed, 6 deletions(-) delete mode 100644 .scannerwork/.sonar_lock delete mode 100644 .scannerwork/class-mapping.csv delete mode 100644 .scannerwork/report-task.txt diff --git a/.scannerwork/.sonar_lock b/.scannerwork/.sonar_lock deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/.scannerwork/class-mapping.csv b/.scannerwork/class-mapping.csv deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt deleted file mode 100644 index 63ca473f46..0000000000 --- a/.scannerwork/report-task.txt +++ /dev/null @@ -1,6 +0,0 @@ -projectKey=zentaopms -serverUrl=http://10.0.1.249:6230 -serverVersion=9.9.0.65466 -dashboardUrl=http://10.0.1.249:6230/dashboard?id=zentaopms -ceTaskId=AYfppPP3aBmpAvupYyeE -ceTaskUrl=http://10.0.1.249:6230/api/ce/task?id=AYfppPP3aBmpAvupYyeE From e7a1048ab0e505a171a3c77638e472f71e73f102 Mon Sep 17 00:00:00 2001 From: dingguodong Date: Fri, 5 May 2023 10:39:57 +0800 Subject: [PATCH 08/80] * Fix undefined variable. --- lib/form/form.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/form/form.class.php b/lib/form/form.class.php index b1c8f96ee3..94e871c3ef 100644 --- a/lib/form/form.class.php +++ b/lib/form/form.class.php @@ -114,7 +114,7 @@ class form extends baseFixer { if(!isset($this->errors[$field])) $this->errors[$field] = array(); $fieldName = isset($app->lang->{$app->rawModule}->$field) ? $app->lang->{$app->rawModule}->$field : $field; - $this->errors[$field][] = sprintf($lang->error->notempty, $fieldName); + $this->errors[$field][] = sprintf($app->lang->error->notempty, $fieldName); } } From 564aa477643a97f8c7b49719cbac7e8ffb35321c Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Fri, 5 May 2023 10:45:43 +0800 Subject: [PATCH 09/80] * Modify unit test position. --- .../test/model/gettotalbugbyproject.php | 24 -------- .../test/model/gettotalstoriesbyproject.php | 24 -------- .../test/model/gettotaltaskbyproject.php | 26 --------- .../project/test/tao/gettotalbugbyproject.php | 49 +++++++++++++++++ .../test/tao/gettotalstoriesbyproject.php | 49 +++++++++++++++++ .../test/tao/gettotaltaskbyproject.php | 55 +++++++++++++++++++ test/data/story.yaml | 8 +-- 7 files changed, 156 insertions(+), 79 deletions(-) delete mode 100755 module/project/test/model/gettotalbugbyproject.php delete mode 100755 module/project/test/model/gettotalstoriesbyproject.php delete mode 100755 module/project/test/model/gettotaltaskbyproject.php create mode 100755 module/project/test/tao/gettotalbugbyproject.php create mode 100755 module/project/test/tao/gettotalstoriesbyproject.php create mode 100755 module/project/test/tao/gettotaltaskbyproject.php diff --git a/module/project/test/model/gettotalbugbyproject.php b/module/project/test/model/gettotalbugbyproject.php deleted file mode 100755 index afa2ad47f2..0000000000 --- a/module/project/test/model/gettotalbugbyproject.php +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env php -getTotalBugByProject(); -cid=1 -pid=1 - -获取id为11的项目下激活的bug数量 >> 4 -获取id为27的项目下激活的bug数量 >> 1 - -*/ - -global $tester; -$tester->loadModel('project'); - -$projectIdList = array(11, 12, 13, 14, 15, 16, 27); -$result = $tester->project->getTotalBugByProject($projectIdList, 'active'); - -r($result[11]) && p('allBugs') && e('4'); //获取id为11的项目下激活的bug数量 -r($result[27]) && p('allBugs') && e('1'); //获取id为27的项目下激活的bug数量 diff --git a/module/project/test/model/gettotalstoriesbyproject.php b/module/project/test/model/gettotalstoriesbyproject.php deleted file mode 100755 index ab928b35dc..0000000000 --- a/module/project/test/model/gettotalstoriesbyproject.php +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env php -> 4 -传入产品ID列表,获取项目11下的所有需求数量 >> 4;4 -*/ - -global $tester; -$tester->loadModel('project'); - -$projectIdList = array(12,13); -$stories1 = $tester->project->getTotalStoriesByProject(11); -$stories2 = $tester->project->getTotalStoriesByProject($projectIdList); - -r($stories1[11]) && p('allStories') && e('4'); // 不传入产品ID列表,获取项目11下的所有需求数量 -r($stories2) && p('12:allStories;13:allStories') && e('4;4'); // 传入产品ID列表,获取项目11下的所有需求数量 diff --git a/module/project/test/model/gettotaltaskbyproject.php b/module/project/test/model/gettotaltaskbyproject.php deleted file mode 100755 index e7dd6cb4c9..0000000000 --- a/module/project/test/model/gettotaltaskbyproject.php +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env php -getTotalTaskByProject(); -cid=1 -pid=1 - -获取id为11的项目下进行中的task数量 >> 4 -获取id为15的项目下完成的task数量 >> 2 -获取id为27的项目下激活的task数量 >> 8 - -*/ - -global $tester; -$tester->loadModel('project'); - -$projectIdList = array(11, 12, 13, 14, 15, 16, 27); -$result = $tester->project->getTotalTaskByProject($projectIdList); - -r($result[11]) && p('doingTasks') && e('4'); // 获取id为11的项目下进行中的task数量 -r($result[15]) && p('doneTasks') && e('2'); // 获取id为15的项目下完成的task数量 -r($result[27]) && p('leftTasks') && e('8'); // 获取id为27的项目下激活的task数量 diff --git a/module/project/test/tao/gettotalbugbyproject.php b/module/project/test/tao/gettotalbugbyproject.php new file mode 100755 index 0000000000..30fa1d3045 --- /dev/null +++ b/module/project/test/tao/gettotalbugbyproject.php @@ -0,0 +1,49 @@ +#!/usr/bin/env php +id->range('11-19'); + $project->project->range('11-19'); + $project->name->prefix("项目")->range('11-19'); + $project->code->prefix("project")->range('11-19'); + $project->model->range("scrum"); + $project->auth->range("[]"); + $project->path->range("[]"); + $project->type->range("project"); + $project->grade->range("1"); + $project->days->range("1"); + $project->status->range("wait,doing,suspended,closed"); + $project->desc->range("[]"); + $project->budget->range("100000,200000"); + $project->budgetUnit->range("CNY"); + $project->percent->range("0-0"); + $project->openedDate->range("`2023-05-01 10:00:10`"); + $project->gen(9); + + zdTable('bug')->gen(50); +} + +initData(); + +/** + +title=测试 projectModel->getTotalBugByProject(); +cid=1 + +*/ + +global $tester; +$tester->loadModel('project'); + + +$projectIdList = array(11, 12, 13, 14, 15, 16, 27); +$result = $tester->project->getTotalBugByProject($projectIdList); +$result2 = $tester->project->getTotalBugByProject(array()); + +r($result) && p('11:allBugs') && e('3'); //获取id为11的项目下bug数量 +r($result) && p('27:allBugs') && e('Error: Cannot get index 27.'); //获取id为27的项目下bug数量 +r($result2) && p() && e('0'); //获取项目为空时的bug数量 diff --git a/module/project/test/tao/gettotalstoriesbyproject.php b/module/project/test/tao/gettotalstoriesbyproject.php new file mode 100755 index 0000000000..6e822cb4c1 --- /dev/null +++ b/module/project/test/tao/gettotalstoriesbyproject.php @@ -0,0 +1,49 @@ +#!/usr/bin/env php +id->range('11-19'); + $project->project->range('11-19'); + $project->name->prefix("项目")->range('11-19'); + $project->code->prefix("project")->range('11-19'); + $project->model->range("scrum"); + $project->auth->range("[]"); + $project->path->range("[]"); + $project->type->range("project"); + $project->grade->range("1"); + $project->days->range("1"); + $project->status->range("wait,doing,suspended,closed"); + $project->desc->range("[]"); + $project->budget->range("100000,200000"); + $project->budgetUnit->range("CNY"); + $project->percent->range("0-0"); + $project->openedDate->range("`2023-05-01 10:00:10`"); + $project->gen(9); + + zdTable('story')->gen(50); + zdTable('projectstory')->gen(10); +} + +initData(); + +/** + +title=测试 projectModel::getTotalStoriesByProject; +cid=1 + +*/ + +global $tester; +$projectTester = $tester->loadModel('project'); + +$noneIdList = array(); +$notExistsIdList = array(1); +$realIdList = array(12, 13); + +r($projectTester->getTotalStoriesByProject($noneIdList)) && p() && e('0'); // 不传入项目ID列表,获取需求数量 +r($projectTester->getTotalStoriesByProject($notExistsIdList)) && p() && e('0'); // 传入错误的ID列表,获取需求数量 +r($projectTester->getTotalStoriesByProject($realIdList)) && p('12:allStories;13:allStories') && e('2,2'); // 传入正确的ID列表,获取需求数量 diff --git a/module/project/test/tao/gettotaltaskbyproject.php b/module/project/test/tao/gettotaltaskbyproject.php new file mode 100755 index 0000000000..67040f98e7 --- /dev/null +++ b/module/project/test/tao/gettotaltaskbyproject.php @@ -0,0 +1,55 @@ +#!/usr/bin/env php +id->range('11-19,101-109'); + $project->project->range('11-19'); + $project->name->setFields(array( + array('field' => 'name1', 'range' => '项目{9},迭代{9}'), + array('field' => 'name2', 'range' => '11-19,101-109') + )); + $project->code->setFields(array( + array('field' => 'name1', 'range' => 'project{9},execution{9}'), + array('field' => 'name2', 'range' => '11-19,101-109') + )); + $project->model->range("scrum{9},[]{9}"); + $project->auth->range("[]"); + $project->path->range("[]"); + $project->type->range("project{9},sprint{9}"); + $project->grade->range("1"); + $project->days->range("1"); + $project->status->range("wait,doing,suspended,closed"); + $project->desc->range("[]"); + $project->budget->range("100000,200000"); + $project->budgetUnit->range("CNY"); + $project->percent->range("0-0"); + $project->openedDate->range("`2023-05-01 10:00:10`"); + $project->gen(18); + + zdTable('task')->gen(10); +} + +initData(); + +/** + +title=测试 projectModel->getTotalTaskByProject(); +cid=1 + +*/ + +global $tester; +$tester->loadModel('project'); + +$projectIdList = array(11, 12, 13, 14, 15, 16, 27); +$result1 = $tester->project->getTotalTaskByProject($projectIdList); +$result2 = $tester->project->getTotalTaskByProject(array()); + +r($result1) && p('11:waitTasks') && e('1'); // 获取id为11的项目下未开始的task数量 +r($result1) && p('15:allTasks') && e('1'); // 获取id为15的项目下所有的task数量 +r($result1) && p('27:waitTasks') && e('Error: Cannot get index 27.'); // 获取id为27的项目下未开始的task数量 +r($result2) && p() && e('0'); // 获取项目为空的task数量 diff --git a/test/data/story.yaml b/test/data/story.yaml index 5bad0a6f55..d0d5bb9e06 100644 --- a/test/data/story.yaml +++ b/test/data/story.yaml @@ -63,7 +63,7 @@ fields: note: "需求名称" fields: - field: field1 - range: [用户需求,软件需求] + range: "[用户需求,软件需求]" - field: field2 range: 1-10000 prefix: "" @@ -146,7 +146,7 @@ fields: - field: openedBy1 range: admin,user,test,dev - field: openedBy2 - range: [],2-4 + range: "[],2-4" prefix: "" postfix: "" loop: 0 @@ -155,7 +155,6 @@ fields: note: "创建日期" range: "(M)-(w)" type: timestamp - prefix: "DateTime" postfix: "" format: "YY/MM/DD" - field: assignedTo @@ -164,7 +163,7 @@ fields: - field: openedBy1 range: admin,user,test,dev - field: openedBy2 - range: [],2-4 + range: "[],2-4" prefix: "" postfix: "" loop: 0 @@ -173,7 +172,6 @@ fields: note: "指派日期" range: "(M)-(w)" type: timestamp - prefix: "DateTime" postfix: "" format: "YY/MM/DD" - field: lastEditedBy From e09c830411ad2c371f2c5456b68b463379433c36 Mon Sep 17 00:00:00 2001 From: caoyanyi Date: Fri, 5 May 2023 10:46:10 +0800 Subject: [PATCH 10/80] * Split getOverviewList function. --- module/project/model.php | 87 +++++----------------------------------- module/project/tao.php | 64 +++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 80 deletions(-) diff --git a/module/project/model.php b/module/project/model.php index 0b6505660e..7773addd72 100755 --- a/module/project/model.php +++ b/module/project/model.php @@ -259,7 +259,7 @@ class projectModel extends model $orderBy = $project->model == 'waterfall' ? 'id_asc' : 'id_desc'; $pager = $project->model == 'waterfall' ? null : new pager(0, 1, 1); $project->executions = $this->loadModel('execution')->getStatData($projectID, 'undone', 0, 0, false, '', $orderBy, $pager); - $project->teamCount = isset($teams[$projectID]) ? $teams[$projectID]->count : 0; + $project->teamCount = isset($teams[$projectID]) ? $teams[$projectID] : 0; $project->estimate = isset($estimates[$projectID]) ? round($estimates[$projectID]->estimate, 2) : 0; $project->parentName = $project->parent ? $this->projectTao->getParentProgram($project->parent, $project->path, $project->grade) : ''; } @@ -279,6 +279,7 @@ class projectModel extends model */ public function getOverviewList($queryType = 'byStatus', $param = 'all', $orderBy = 'id_desc', $limit = 15, $excludedModel = '') { + /* */ $queryType = strtolower($queryType); $projects = $this->dao->select('*')->from(TABLE_PROJECT) ->where('type')->eq('project') @@ -294,32 +295,21 @@ class projectModel extends model ->fetchAll('id'); if(empty($projects)) return array(); + $projectIdList = array_keys($projects); + $teams = $this->projectTao->fetchMemberCountByIdList($projectIdList); - $teams = $this->dao->select('t1.root, count(t1.id) as teams')->from(TABLE_TEAM)->alias('t1') - ->leftJoin(TABLE_USER)->alias('t2')->on('t1.account=t2.account') - ->where('t1.root')->in($projectIdList) - ->andWhere('t1.type')->eq('project') - ->andWhere('t2.deleted')->eq(0) - ->groupBy('root')->fetchPairs(); + $fields = 't2.project, ROUND(SUM(t1.consumed), 1) AS consumed, ROUND(SUM(t1.estimate), 1) AS estimate'; + $hours = $this->projectTao->fetchTaskEstimateByIdList($projectIdList, $fields); - $hours = $this->dao->select('t2.project, ROUND(SUM(t1.consumed), 1) AS consumed, ROUND(SUM(t1.estimate), 1) AS estimate')->from(TABLE_TASK)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id') - ->where('t2.project')->in($projectIdList) - ->andWhere('t2.deleted')->eq(0) - ->andWhere('t1.deleted')->eq(0) - ->andWhere('t1.parent')->lt(1) - ->groupBy('t2.project') - ->fetchAll('project'); - - $storySummary = $this->getTotalStoriesByProject($projectIdList); - $taskSummary = $this->getTotalTaskByProject($projectIdList); - $bugSummary = $this->getTotalBugByProject($projectIdList); + $storySummary = $this->projectTao->getTotalStoriesByProject($projectIdList); + $taskSummary = $this->projectTao->getTotalTaskByProject($projectIdList); + $bugSummary = $this->projectTao->getTotalBugByProject($projectIdList); foreach($projects as $projectID => $project) { - $project->consumed = isset($hours[$projectID]) ? (float)$hours[$projectID]->consumed : 0; - $project->estimate = isset($hours[$projectID]) ? (float)$hours[$projectID]->estimate : 0; + $project->consumed = isset($hours[$projectID]) ? round((float)$hours[$projectID]->consumed, 1) : 0; + $project->estimate = isset($hours[$projectID]) ? round((float)$hours[$projectID]->estimate, 1) : 0; $project->teamCount = isset($teams[$projectID]) ? $teams[$projectID] : 0; $project->leftBugs = isset($bugSummary[$projectID]) ? $bugSummary[$projectID]->leftBugs : 0; $project->allBugs = isset($bugSummary[$projectID]) ? $bugSummary[$projectID]->allBugs : 0; @@ -333,66 +323,11 @@ class projectModel extends model $project->doingTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->doingTasks : 0; $project->rndDoneTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->doneTasks : 0; $project->liteDoneTasks = isset($taskSummary[$projectID]) ? $taskSummary[$projectID]->litedoneTasks : 0; - - if(is_float($project->consumed)) $project->consumed = round($project->consumed, 1); - if(is_float($project->estimate)) $project->estimate = round($project->estimate, 1); } return $projects; } - /** - * Get the number of stories associated with the project. - * - * @param array $projectIdList - * @access public - * @return int - */ - public function getTotalStoriesByProject($projectIdList = 0) - { - 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') - ->where('t1.project')->in($projectIdList) - ->andWhere('t2.type')->eq('story') - ->andWhere('deleted')->eq('0') - ->groupBy('project') - ->fetchAll('project'); - } - - /** - * Get associated bugs by project. - * - * @param array $projectIdList - * @access public - * @return array - */ - public function getTotalBugByProject($projectIdList) - { - 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) - ->andWhere('deleted')->eq(0) - ->groupBy('project') - ->fetchAll('project'); - } - - /** - * Get associated tasks by project. - * - * @param array $projectIdList - * @access public - * @return array - */ - public function getTotalTaskByProject($projectIdList) - { - 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') - ->where('t1.project')->in($projectIdList) - ->andWhere('t1.deleted')->eq(0) - ->andWhere('t2.deleted')->eq(0) - ->groupBy('t1.project') - ->fetchAll('project'); - } - /** * Get waterfall project progress. * diff --git a/module/project/tao.php b/module/project/tao.php index 07ee19fb5f..c4c1dc6179 100755 --- a/module/project/tao.php +++ b/module/project/tao.php @@ -587,20 +587,21 @@ class projectTao extends projectModel ->where('t1.root')->in($projectIdList) ->andWhere('t2.deleted')->eq(0) ->groupBy('t1.root') - ->fetchAll('root'); + ->fetchPairs(); } /** * 根据项目ID列表查询任务的总预计工时。 * Get task all estimate by project id list. * - * @param array $projectIdList + * @param array $projectIdList + * @param string $fields * @access protected * @return array */ - protected function fetchTaskEstimateByIdList(array $projectIdList): array + protected function fetchTaskEstimateByIdList(array $projectIdList, string $fields = 't2.project as project, sum(estimate) as estimate'): array { - return $this->dao->select("t2.project as project, sum(estimate) as estimate")->from(TABLE_TASK)->alias('t1') + return $this->dao->select($fields)->from(TABLE_TASK)->alias('t1') ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id') ->where('t1.parent')->lt(1) ->andWhere('t2.project')->in($projectIdList) @@ -609,4 +610,59 @@ class projectTao extends projectModel ->groupBy('t2.project') ->fetchAll('project'); } + + /** + * 通过项目ID列表查询需求的数量。 + * Get the number of stories associated with the project. + * + * @param array $projectIdList + * @access public + * @return array + */ + public 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') + ->where('t1.project')->in($projectIdList) + ->andWhere('t2.type')->eq('story') + ->andWhere('deleted')->eq('0') + ->groupBy('project') + ->fetchAll('project'); + } + + /** + * 通过项目ID获取任务数量统计。 + * Get the number of tasks associated with the project. + * + * @param array $projectIdList + * @access public + * @return array + */ + public 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') + ->where('t1.project')->in($projectIdList) + ->andWhere('t1.deleted')->eq(0) + ->andWhere('t2.deleted')->eq(0) + ->groupBy('t1.project') + ->fetchAll('project'); + } + + /** + * 通过项目ID获取Bug数量统计。 + * Get the number of bugs associated with the project. + * + * @param array $projectIdList + * @access public + * @return array + */ + public 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) + ->andWhere('deleted')->eq(0) + ->groupBy('project') + ->fetchAll('project'); + } } From d655873b6fd84e911d8a95bcc99b89c8175aef34 Mon Sep 17 00:00:00 2001 From: liyang Date: Fri, 5 May 2023 10:47:59 +0800 Subject: [PATCH 11/80] * Add build initial yaml file. --- test/lib/yaml.class.php | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/test/lib/yaml.class.php b/test/lib/yaml.class.php index 56cd39a8fd..cde84f8db7 100644 --- a/test/lib/yaml.class.php +++ b/test/lib/yaml.class.php @@ -243,7 +243,29 @@ class yaml $this->tableName = $tableName; $this->fields = new fields(); - $this->configFiles[] = dirname(dirname(__FILE__)) . "/data/{$this->tableName}.yaml"; + $yamlPath = dirname(dirname(__FILE__)) . "/data/{$this->tableName}.yaml"; + $this->configFiles[] = $yamlPath; + + if(!file_exists($yamlPath)) $this->buildYamlFile($this->tableName); + } + + /** + * Build the initial yaml file. + * + * @param string $tableName + * @access public + * @return viod + */ + public function buildYamlFile($tableName) + { + $yamlData['title'] = 'table zt_' . $tableName; + $yamlData['author'] = 'automated export'; + $yamlData['version'] = '1.0'; + $yamlData['fields'][0]['field'] = 'id'; + $yamlData['fields'][0]['range'] = '1-1000'; + + $yamlFile = dirname(dirname(__FILE__)) . "/data/{$this->tableName}.yaml"; + yaml_emit_file($yamlFile, $yamlData, YAML_UTF8_ENCODING); } /** @@ -386,7 +408,7 @@ class yaml system($execDump); $stderr = ''; $this->exec_with_stderr($execYaml, $stderr); - + if(empty($stderr)) return; $errors = explode(PHP_EOL, $stderr); @@ -394,7 +416,7 @@ class yaml { return !empty($error) && !strpos($error, 'Using a password on the command line interface can be insecure'); }); - + if(!empty($errors)) echo implode(PHP_EOL, $errors) . PHP_EOL; } @@ -407,11 +429,11 @@ class yaml * @access private * @return string */ - private function exec_with_stderr($cmd, &$stderr=null) + private function exec_with_stderr($cmd, &$stderr=null) { $proc = proc_open($cmd, array(2 => array('pipe', 'w')), $pipes); $stderr = stream_get_contents($pipes[2]); - + fclose($pipes[2]); proc_close($proc); } From 5d9560e4ea45ed4ded3a1a9e07598eed5ddcd7b4 Mon Sep 17 00:00:00 2001 From: lanzongjun Date: Fri, 5 May 2023 11:02:45 +0800 Subject: [PATCH 12/80] * fix bug. --- module/todo/control.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/module/todo/control.php b/module/todo/control.php index acdca87fd5..778864b7d8 100755 --- a/module/todo/control.php +++ b/module/todo/control.php @@ -11,10 +11,7 @@ declare(strict_types=1); */ class todo extends control { - sdasdasdasdasdas /** - * sadasdasd - * * Construct function, load model of task, bug, my. * * @access public @@ -24,6 +21,7 @@ class todo extends control { parent::__construct(); + $this->app->loadClass('date'); $this->app->loadLang('my'); } From da410be404362813498c9d3ba3fb52ad51438f6d Mon Sep 17 00:00:00 2001 From: wangyidong Date: Fri, 5 May 2023 11:04:10 +0800 Subject: [PATCH 13/80] * adjust code for product create. --- module/product/config/form.php | 17 +- module/product/control.php | 72 ++---- module/product/model.php | 75 +++--- module/product/tao.php | 67 ++++++ module/product/test/model/create.php | 23 +- .../test/model/getprojectlistbyproduct.php | 49 +++- module/product/test/product.class.php | 7 +- module/product/test/tao/createline.php | 2 +- module/product/test/tao/createmainlib.php | 7 +- .../test/tao/fetchallproductprojects.php | 53 +++++ .../test/tao/fetchinvolvedproductprojects.php | 93 ++++++++ module/product/ui/create.html.php | 195 +++------------- module/product/view/project.html.php | 6 +- module/product/zen.php | 214 ++++++++++-------- module/project/test/model/create.php | 6 +- test/data/stakeholder.yaml | 11 + test/lib/yaml.class.php | 8 +- 17 files changed, 508 insertions(+), 397 deletions(-) create mode 100755 module/product/test/tao/fetchallproductprojects.php create mode 100755 module/product/test/tao/fetchinvolvedproductprojects.php diff --git a/module/product/config/form.php b/module/product/config/form.php index 40fb2703ec..0e23310aa9 100644 --- a/module/product/config/form.php +++ b/module/product/config/form.php @@ -4,24 +4,24 @@ $config->product->form = new stdclass(); $config->product->form->create = array(); $config->product->form->create['program'] = array('type' => 'int', 'control' => 'select', 'required' => false, 'default' => 0, 'options' => array()); $config->product->form->create['line'] = array('type' => 'int', 'control' => 'select', 'required' => false, 'default' => 0, 'options' => array()); -$config->product->form->create['lineName'] = array('type' => 'string', 'control' => 'input', 'required' => false, 'default' => '', 'filter' => 'trim'); -$config->product->form->create['name'] = array('type' => 'string', 'control' => 'input', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->product->form->create['code'] = array('type' => 'string', 'control' => 'input', 'required' => true, 'default' => '', 'filter' => 'trim'); +$config->product->form->create['lineName'] = array('type' => 'string', 'control' => 'text', 'required' => false, 'default' => '', 'filter' => 'trim'); +$config->product->form->create['name'] = array('type' => 'string', 'control' => 'text', 'required' => true, 'default' => '', 'filter' => 'trim'); +$config->product->form->create['code'] = array('type' => 'string', 'control' => 'text', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->product->form->create['PO'] = array('type' => 'account', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array()); $config->product->form->create['QD'] = array('type' => 'account', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array()); $config->product->form->create['RD'] = array('type' => 'account', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array()); $config->product->form->create['reviewer'] = array('type' => 'array', 'control' => 'multi-select', 'required' => false, 'default' => '', 'filter' => 'join', 'options' => 'users'); $config->product->form->create['type'] = array('type' => 'string', 'control' => 'select', 'required' => false, 'default' => 'normal', 'options' => $lang->product->typeList); $config->product->form->create['status'] = array('type' => 'string', 'control' => 'hidden', 'required' => false, 'default' => 'normal'); -$config->product->form->create['desc'] = array('type' => 'string', 'control' => 'textarea', 'required' => false, 'default' => ''); -$config->product->form->create['acl'] = array('type' => 'string', 'control' => 'radio', 'required' => false, 'default' => 'private', 'options' => $lang->product->aclList); -$config->product->form->create['whitelist'] = array('type' => 'array', 'control' => 'multi-select', 'required' => false, 'default' => '', 'filter' => 'join', 'options' => 'users'); +$config->product->form->create['desc'] = array('type' => 'string', 'control' => 'editor', 'required' => false, 'default' => '', 'width' => 'full'); +$config->product->form->create['acl'] = array('type' => 'string', 'control' => 'radio', 'required' => false, 'default' => 'private', 'width' => 'full', 'options' => $lang->product->aclList); +$config->product->form->create['whitelist'] = array('type' => 'array', 'control' => 'multi-select', 'required' => false, 'default' => '', 'filter' => 'join', 'width' => 'full', 'options' => 'users'); $config->product->form->edit = array(); $config->product->form->edit['program'] = array('type' => 'int', 'control' => 'select', 'required' => false, 'default' => 0, 'options' => array()); $config->product->form->edit['line'] = array('type' => 'int', 'control' => 'select', 'required' => false, 'default' => 0, 'options' => array()); -$config->product->form->edit['name'] = array('type' => 'string', 'control' => 'input', 'required' => true, 'default' => '', 'filter' => 'trim'); -$config->product->form->edit['code'] = array('type' => 'string', 'control' => 'input', 'required' => true, 'default' => '', 'filter' => 'trim'); +$config->product->form->edit['name'] = array('type' => 'string', 'control' => 'text', 'required' => true, 'default' => '', 'filter' => 'trim'); +$config->product->form->edit['code'] = array('type' => 'string', 'control' => 'text', 'required' => true, 'default' => '', 'filter' => 'trim'); $config->product->form->edit['PO'] = array('type' => 'account', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array()); $config->product->form->edit['QD'] = array('type' => 'account', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array()); $config->product->form->edit['RD'] = array('type' => 'account', 'control' => 'select', 'required' => false, 'default' => '', 'options' => array()); @@ -31,4 +31,3 @@ $config->product->form->edit['status'] = array('type' => 'string', 'con $config->product->form->edit['desc'] = array('type' => 'string', 'control' => 'textarea', 'required' => false, 'default' => ''); $config->product->form->edit['acl'] = array('type' => 'string', 'control' => 'radio', 'required' => false, 'default' => 'private', 'options' => $lang->product->aclList); $config->product->form->edit['whitelist'] = array('type' => 'array', 'control' => 'multi-select', 'required' => false, 'default' => '', 'filter' => 'join', 'options' => 'users'); -$config->product->form->edit['changeProjects'] = array('type' => 'string', 'control' => 'hidden', 'required' => false, 'default' => ''); diff --git a/module/product/control.php b/module/product/control.php index 47da78d20f..dd64874844 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -73,56 +73,28 @@ class product extends control * The projects which linked the product. * * @param string $status - * @param int $productID - * @param int $branch - * @param int $involved + * @param string $productID + * @param string $branch + * @param string $involved * @param string $orderBy - * @param int $recTotal - * @param int $recPerPage - * @param int $pageID + * @param string $recTotal + * @param string $recPerPage + * @param string $pageID * @access public * @return void */ - public function project($status = 'all', $productID = 0, $branch = '', $involved = 0, $orderBy = 'order_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1) + public function project(string $status = 'all', string $productID = '0', string $branch = '', string $involved = '0', string $orderBy = 'order_desc', string $recTotal = '0', string $recPerPage = '20', string $pageID = '1') { - $this->app->loadLang('execution'); - $this->loadModel('project'); - - $branch = ($this->cookie->preBranch !== '' and $branch === '') ? $this->cookie->preBranch : $branch; - setcookie('preBranch', $branch, $this->config->cookieLife, $this->config->webRoot, '', $this->config->cookieSecure, true); - $this->session->set('createProjectLocate', $this->app->getURI(true), 'product'); - - $this->product->setMenu($productID, $branch); + $productID = (int)$productID; + $involved = ($this->cookie->involved or $involved); + $this->productZen->setProjectMenu($productID, $branch, $this->cookie->preBranch); /* Load pager. */ $this->app->loadClass('pager', $static = true); - $pager = new pager($recTotal, $recPerPage, $pageID); + $pager = new pager((int)$recTotal, (int)$recPerPage, (int)$pageID); - /* Get PM id list. */ - $accounts = array(); - $projectStats = $this->product->getProjectStatsByProduct($productID, $status, $branch, $involved, $orderBy, $pager); - $product = $this->product->getByID($productID); - $projects = $this->project->getPairsByProgram($product->program, 'all', false, 'order_asc', '', '', 'product'); - - foreach($projectStats as $project) - { - if(!empty($project->PM) and !in_array($project->PM, $accounts)) $accounts[] = $project->PM; - unset($projects[$project->id]); - } - $PMList = $this->user->getListByAccounts($accounts, 'account'); - - $this->view->title = $this->products[$productID] . $this->lang->colon . $this->lang->product->project; - $this->view->projectStats = $projectStats; - $this->view->PMList = $PMList; - $this->view->productID = $productID; - $this->view->product = $product; - $this->view->projects = $projects; - $this->view->status = $status; - $this->view->users = $this->loadModel('user')->getPairs('noletter'); - $this->view->branchID = $branch; - $this->view->branchStatus = $this->loadModel('branch')->getByID($branch, 0, 'status'); - $this->view->pager = $pager; - $this->display(); + /* Set view variables and display. */ + $this->productZen->displayProjectPage($productID, $branch, $status, $involved, $orderBy, $pager); } /** @@ -399,7 +371,7 @@ class product extends control * Create a product. * 创建产品。可以是顶级产品,也可以是项目集下的产品。 * - * @param int $programID + * @param string $programID * @param string $extra * @access public * @return void @@ -410,13 +382,14 @@ class product extends control if(!empty($_POST)) { - $data = form::data($this->config->product->form->create); - $data = $this->productZen->prepareCreateExtras($data, $this->post->acl, $this->post->uid); + $data = form::data($this->config->product->form->create); + $product = $this->productZen->prepareCreateExtras($data); - $productID = $this->product->create($data); - if(!$productID) return $this->productZen->sendDaoError(); + $productID = $this->product->create($product, $this->post->uid, zget($_POST, 'lineName', '')); + if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError())); - return $this->productZen->responseAfterCreate($productID, $data, $this->post->uid, zget($_POST, 'lineName', '')); + $response = $this->productZen->responseAfterCreate($productID, (int)$product->program); + $this->send($response); } $this->productZen->setCreateMenu($programID); @@ -447,7 +420,8 @@ class product extends control if(dao::isError()) return $this->productZen->sendDaoError(); if($action == 'undelete') $this->loadModel('action')->undelete((int)$extra); - return $this->productZen->responseAfterEdit($productID, $programID, $changes); + $response = $this->productZen->responseAfterEdit($productID, $programID, $changes); + $this->send($response); } $this->productZen->setEditMenu($productID, $programID); @@ -1215,7 +1189,7 @@ class product extends control } else { - return print(html::select('product', $products, empty($product) ? '' : $product->id, "onchange='loadBranches(this.value);' class='form-control chosen' required data-toggle='modal' data-type='iframe'")); + return print(html::select('product', $products, '', "onchange='loadBranches(this.value);' class='form-control chosen' required data-toggle='modal' data-type='iframe'")); } } diff --git a/module/product/model.php b/module/product/model.php index 9f076efcb1..0c2cf7f1d9 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -668,20 +668,39 @@ class productModel extends model * 直接用对象数据创建产品 * * @param object $product + * @param string $uid + * @param string $lineName * @access public * @return int|false */ - public function create(object $product): int|false + public function create(object $product, string $uid = '', string $lineName = ''): int|false { $this->lang->error->unique = $this->lang->error->repeat; $this->dao->insert(TABLE_PRODUCT)->data($product)->autoCheck() - ->batchCheck($this->config->product->create->requiredFields, 'notempty') ->checkIF(!empty($product->name), 'name', 'unique', "`program` = {$product->program} and `deleted` = '0'") ->checkIF(!empty($product->code), 'code', 'unique', "`deleted` = '0'") ->checkFlow() ->exec(); if(dao::isError()) return false; - return (int)$this->dao->lastInsertID(); + $productID = (int)$this->dao->lastInsertID(); + + /* Fix order and line fields for product. */ + $fixData = new stdclass(); + $fixData->order = $productID * 5; + if(!empty($lineName)) + { + $lineID = $this->productTao->createLine((int)$product->program, $lineName); + if($lineID) $fixData->line = $lineID; + } + $this->dao->update(TABLE_PRODUCT)->data($fixData)->where('id')->eq($productID)->exec(); + + /* Update and create linked data. */ + $this->loadModel('file')->updateObjectID($uid, $productID, 'product'); + $this->productTao->createMainLib($productID); + if($product->whitelist) $this->loadModel('personnel')->updateWhitelist(explode(',', $product->whitelist), 'product', $productID); + if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product'); + + return $productID; } /** @@ -699,7 +718,6 @@ class productModel extends model $this->lang->error->unique = $this->lang->error->repeat; $this->dao->update(TABLE_PRODUCT)->data($product, 'uid,changeProjects,contactListMenu')->autoCheck() - ->batchCheck($this->config->product->edit->requiredFields, 'notempty') ->checkIF(!empty($product->name), 'name', 'unique', "id != {$productID} and `program` = {$product->program} and `deleted` = '0'") ->checkIF(!empty($product->code), 'code', 'unique', "id != {$productID} and `deleted` = '0'") ->checkFlow() @@ -1158,49 +1176,26 @@ class productModel extends model /** * Get project list by product. * - * @param int $productID - * @param string $browseType - * @param int $branch - * @param int $involved - * @param string $orderBy - * @param object $pager + * @param int $productID + * @param string $browseType all|undone|wait|doing|done + * @param string $branch + * @param bool $involved $this->cookie->involved or $involved + * @param string $orderBy + * @param object|null $pager * @access public * @return array */ - public function getProjectListByProduct($productID, $browseType = 'all', $branch = 0, $involved = 0, $orderBy = 'order_desc', $pager = null) + public function getProjectListByProduct(int $productID, string $browseType = 'all', string $branch = '0', bool $involved = false, string $orderBy = 'order_desc', object|null $pager = null): array { - $projectList = $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->leftJoin(TABLE_TEAM)->alias('t3')->on('t2.id=t3.root') - ->leftJoin(TABLE_STAKEHOLDER)->alias('t4')->on('t2.id=t4.objectID') - ->where('t1.product')->eq($productID) - ->andWhere('t2.type')->eq('project') - ->beginIF($this->cookie->involved or $involved)->andWhere('t3.type')->eq('project')->fi() - ->beginIF($browseType == 'undone')->andWhere('t2.status')->in('wait,doing')->fi() - ->beginIF(strpos(",all,undone,", ",$browseType,") === false)->andWhere('t2.status')->eq($browseType)->fi() - ->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->projects)->fi() - ->beginIF($this->cookie->involved or $involved) - ->andWhere('t2.openedBy', true)->eq($this->app->user->account) - ->orWhere('t2.PM')->eq($this->app->user->account) - ->orWhere('t3.account')->eq($this->app->user->account) - ->orWhere('(t4.user')->eq($this->app->user->account) - ->andWhere('t4.deleted')->eq(0) - ->markRight(1) - ->orWhere("CONCAT(',', t2.whitelist, ',')")->like("%,{$this->app->user->account},%") - ->markRight(1) - ->fi() - ->beginIF($branch !== '' and $branch !== 'all')->andWhere('t1.branch')->in($branch)->fi() - ->andWhere('t2.deleted')->eq('0') - ->orderBy($orderBy) - ->page($pager, 't2.id') - ->fetchAll('id'); + if(!$involved) $projectList = $this->productTao->fetchAllProductProjects($productID, $browseType, $branch, $orderBy, $pager); + if($involved) $projectList = $this->productTao->fetchInvolvedProductProjects($productID, $browseType, $branch, $orderBy, $pager); /* Determine how to display the name of the program. */ $programList = $this->loadModel('program')->getParentPairs('', 'all'); foreach($projectList as $id => $project) { - $projectList[$id]->programName = $project->parent ? zget($programList, $project->parent, '') : ''; - $projectList[$id]->programName = preg_replace('/\//', '', $projectList[$id]->programName, 1); + $programName = $project->parent ? zget($programList, $project->parent, '') : ''; + $projectList[$id]->programName = preg_replace('/\//', '', $programName, 1); } return $projectList; @@ -1212,13 +1207,13 @@ class productModel extends model * @param int $productID * @param string $browseType * @param int $branch - * @param int $involved + * @param bool $involved $this->cookie->involved or $involved * @param string $orderBy * @param object $pager * @access public * @return array */ - public function getProjectStatsByProduct($productID, $browseType = 'all', $branch = 0, $involved = 0, $orderBy = 'order_desc', $pager = null) + public function getProjectStatsByProduct(int $productID, string $browseType = 'all', string $branch = '0', bool $involved = false, string $orderBy = 'order_desc', object|null $pager = null): array { $projects = $this->getProjectListByProduct($productID, $browseType, $branch, $involved, $orderBy, $pager); if(empty($projects)) return array(); diff --git a/module/product/tao.php b/module/product/tao.php index 0b0a5a8faf..bb04178ba9 100644 --- a/module/product/tao.php +++ b/module/product/tao.php @@ -64,6 +64,73 @@ class productTao extends productModel ->fetchPairs('id', 'name'); } + /** + * 获取该产品下,所有符合参数条件的关联项目。 + * Fetch all projects link this product. + * + * @param int $productID + * @param string $browseType all|undone|wait|doing|done + * @param string $branch + * @param string $orderBy + * @param object|null $pager + * @access protected + * @return array + */ + protected function fetchAllProductProjects(int $productID, string $browseType = 'all', string $branch = '0', string $orderBy = 'order_desc', object|null $pager = null): array + { + return $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t1.product')->eq($productID) + ->andWhere('t2.type')->eq('project') + ->beginIF($browseType == 'undone')->andWhere('t2.status')->in('wait,doing')->fi() + ->beginIF(strpos(",all,undone,", ",$browseType,") === false)->andWhere('t2.status')->eq($browseType)->fi() + ->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->projects)->fi() + ->beginIF($branch !== '' and $branch !== 'all')->andWhere('t1.branch')->in($branch)->fi() + ->andWhere('t2.deleted')->eq('0') + ->orderBy($orderBy) + ->page($pager, 't2.id') + ->fetchAll('id'); + } + + /** + * 只获取该产品下,我参与的,符合参数条件的关联项目。 + * Fetch involved projects link product. + * + * @param int $productID + * @param string $browseType all|undone|wait|doing|done + * @param string $branch + * @param string $orderBy + * @param object|null $pager + * @access protected + * @return array + */ + protected function fetchInvolvedProductProjects(int $productID, string $browseType = 'all', string $branch = '0', string $orderBy = 'order_desc', object|null $pager = null): array + { + return $this->dao->select('t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->leftJoin(TABLE_TEAM)->alias('t3')->on('t2.id=t3.root') + ->leftJoin(TABLE_STAKEHOLDER)->alias('t4')->on('t2.id=t4.objectID') + ->where('t1.product')->eq($productID) + ->andWhere('t2.type')->eq('project') + ->andWhere('t3.type')->eq('project') + ->beginIF($browseType == 'undone')->andWhere('t2.status')->in('wait,doing')->fi() + ->beginIF(strpos(",all,undone,", ",$browseType,") === false)->andWhere('t2.status')->eq($browseType)->fi() + ->beginIF(!$this->app->user->admin)->andWhere('t2.id')->in($this->app->user->view->projects)->fi() + ->andWhere('t2.openedBy', true)->eq($this->app->user->account) + ->orWhere('t2.PM')->eq($this->app->user->account) + ->orWhere('t3.account')->eq($this->app->user->account) + ->orWhere('(t4.user')->eq($this->app->user->account) + ->andWhere('t4.deleted')->eq(0) + ->markRight(1) + ->orWhere("CONCAT(',', t2.whitelist, ',')")->like("%,{$this->app->user->account},%") + ->markRight(1) + ->beginIF($branch !== '' and $branch !== 'all')->andWhere('t1.branch')->in($branch)->fi() + ->andWhere('t2.deleted')->eq('0') + ->orderBy($orderBy) + ->page($pager, 't2.id') + ->fetchAll('id'); + } + /** * 获取产品ID数组中带有项目集信息的产品分页列表。 * Get products with program data that in the ID list. diff --git a/module/product/test/model/create.php b/module/product/test/model/create.php index 26458b3d19..df3ce1af32 100755 --- a/module/product/test/model/create.php +++ b/module/product/test/model/create.php @@ -3,8 +3,8 @@ include dirname(__FILE__, 5) . "/test/lib/init.php"; include dirname(__FILE__, 2) . '/product.class.php'; -#su('admin'); -zdTable('product')->gen(0); +zdTable('product')->gen(1); +zdTable('module')->gen(1); /** @@ -12,15 +12,6 @@ title=测试productModel->create(); cid=1 pid=1 -测试正常的创建 >> case1 -测试不填产品代号的情况 >> 『产品代号』不能为空。 -测试创建重复的产品 >> 『产品代号』已经有『testcase1』这条记录了。 -测试不填产品名称的情况 >> 『产品名称』不能为空。 -测试传入name和code >> case3,testcase3 -测试传入program、name、code >> 3,case4,testcase4 -测试传入program、name、code、type、status >> 4,branch,closed -测试不填权限控制的情况 >> 『访问控制』不符合格式,应当为:『/open|private|custom/』。 - */ $product = new productTest('admin'); @@ -31,8 +22,8 @@ $namecode = array('name' => 'case3', 'code' => 'testcase3'); $pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4'); $intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed'); -r($product->createObject($create)) && p('name') && e('case1'); // 测试正常的创建 -r($product->createObject($repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品 -r($product->createObject($namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code -r($product->createObject($pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code -r($product->createObject($intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status +r($product->createObject($create)) && p('name') && e('case1'); // 测试正常的创建 +r($product->createObject($repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品 +r($product->createObject($namecode, 'test line')) && p('name,code,line') && e('case3,testcase3,2'); // 测试传入name和code +r($product->createObject($pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code +r($product->createObject($intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status diff --git a/module/product/test/model/getprojectlistbyproduct.php b/module/product/test/model/getprojectlistbyproduct.php index 4909502d10..a5f05cbf15 100755 --- a/module/product/test/model/getprojectlistbyproduct.php +++ b/module/product/test/model/getprojectlistbyproduct.php @@ -3,22 +3,51 @@ include dirname(__FILE__, 5) . "/test/lib/init.php"; include dirname(__FILE__, 2) . '/product.class.php'; +zdTable('product')->gen(50); +zdTable('user')->gen(50); + +$project = zdTable('project'); +$project->PM->range('user2,user3'); +$project->gen(50); + +$team = zdTable('team'); +$team->root->range('1-50'); +$team->type->range('project'); +$team->account->range('admin,admin,user1,user1'); +$team->days->range('5'); +$team->hours->range('6,7'); +$team->gen(50); + +$stakeholder = zdTable('stakeholder'); +$stakeholder->objectType->range('project'); +$stakeholder->objectID->range('1-50'); +$stakeholder->user->range('user4,user5'); +$stakeholder->type->range('inside'); +$stakeholder->from->range(''); +$stakeholder->gen(50); + +$projectproduct = zdTable('projectproduct'); +$projectproduct->product->range('1-2'); +$projectproduct->project->range('1-50'); +$projectproduct->gen(50); + /** title=productModel->getProjectListByProduct(); cid=1 pid=1 -返回产品1关联的项目11名字 >> 项目1 -返回产品1关联的项目21名字 >> 项目11 -传入不存在的产品 >> 没有数据 - */ -$product = new productTest('admin'); +global $tester; +$product = $tester->loadModel('product'); +su('admin'); +$product->app->user->admin = true; +$product->app->moduleName = 'product'; +$product->app->methodName = 'project'; -$t_retion = array('1', '1', '10001'); - -r($product->getAllProjectsByProduct($t_retion[0])) && p('11:name') && e('项目1'); // 返回产品1关联的项目11名字 -r($product->getAllProjectsByProduct($t_retion[1])) && p('21:name') && e('项目11'); // 返回产品1关联的项目21名字 -r($product->getAllProjectsByProduct($t_retion[2])) && p() && e('没有数据'); // 传入不存在的产品 \ No newline at end of file +r(count($product->getProjectListByProduct($productID = 0, 'all', '', 'order_desc'))) && p() && e('0'); +r(count($product->getProjectListByProduct($productID = 1, 'all', '', 'order_desc'))) && p() && e('20'); +r(count($product->getProjectListByProduct($productID = 1, 'all', '0', 'order_desc'))) && p() && e('17'); +r(count($product->getProjectListByProduct($productID = 1, 'undone', '', 'order_desc'))) && p() && e('15'); +r(count($product->getProjectListByProduct($productID = 1, 'wait', 'all', 'order_desc'))) && p() && e('5'); diff --git a/module/product/test/product.class.php b/module/product/test/product.class.php index 2b6fe5ba26..d84aff0887 100644 --- a/module/product/test/product.class.php +++ b/module/product/test/product.class.php @@ -25,11 +25,12 @@ class productTest /** * Test create a product. * - * @param array $param + * @param array $param + * @param string $lineName * @access public * @return object|array */ - public function createObject(array $param = array()): object|array + public function createObject(array $param = array(), string $lineName = ''): object|array { $createFields = array(); $createFields['program'] = 1; @@ -52,7 +53,7 @@ class productTest $data = new stdclass(); foreach($createFields as $field => $defaultValue) $data->$field = zget($param, $field, $defaultValue); - $objectID = $this->objectModel->create($data); + $objectID = $this->objectModel->create($data, '', $lineName); if(dao::isError()) { diff --git a/module/product/test/tao/createline.php b/module/product/test/tao/createline.php index 23362cb2fa..bc6bddf7cd 100755 --- a/module/product/test/tao/createline.php +++ b/module/product/test/tao/createline.php @@ -3,7 +3,7 @@ include dirname(__FILE__, 5) . "/test/lib/init.php"; include dirname(__FILE__, 2) . '/product.class.php'; -zdTable('module')->gen(0); +zdTable('module')->gen(1); /** diff --git a/module/product/test/tao/createmainlib.php b/module/product/test/tao/createmainlib.php index 25375620f2..d4f0e3a4fd 100755 --- a/module/product/test/tao/createmainlib.php +++ b/module/product/test/tao/createmainlib.php @@ -3,7 +3,10 @@ include dirname(__FILE__, 5) . "/test/lib/init.php"; include dirname(__FILE__, 2) . '/product.class.php'; -zdTable('doclib')->gen(0); +$doclib = zdTable('doclib'); +$doclib->addedBy->range('admin'); +$doclib->addedDate->range('`' . date('Y-m-d H:i:s') . '`'); +$doclib->gen(1); /** @@ -17,4 +20,4 @@ $product = new productTest('admin'); r($product->createMainLibTest('-1')) && p() && e('0'); r($product->createMainLibTest('0')) && p() && e('0'); -r($product->createMainLibTest('1')) && p('product,name,type,main') && e('1,产品主库,product,1'); +r($product->createMainLibTest('2')) && p('product,name,type,main') && e('2,产品主库,product,1'); diff --git a/module/product/test/tao/fetchallproductprojects.php b/module/product/test/tao/fetchallproductprojects.php new file mode 100755 index 0000000000..3afca1bd6c --- /dev/null +++ b/module/product/test/tao/fetchallproductprojects.php @@ -0,0 +1,53 @@ +#!/usr/bin/env php +gen(50); +zdTable('project')->gen(50); +$projectproduct = zdTable('projectproduct'); +$projectproduct->product->range('1-2'); +$projectproduct->project->range('1-50'); +$projectproduct->gen(50); + +/** + +title=测试productModel->fetchPairs(); +cid=1 +pid=1 + +*/ + +global $tester; +$product = $tester->loadModel('product'); +su('admin'); +$product->app->user->admin = true; +$product->app->moduleName = 'product'; +$product->app->methodName = 'project'; + +r(count($product->fetchAllProductProjects($productID = 0, 'all', '', 'order_desc'))) && p() && e('0'); +r(count($product->fetchAllProductProjects($productID = 1, 'all', '', 'order_desc'))) && p() && e('20'); +r(count($product->fetchAllProductProjects($productID = 1, 'all', '0', 'order_desc'))) && p() && e('17'); +r(count($product->fetchAllProductProjects($productID = 1, 'undone', '', 'order_desc'))) && p() && e('15'); +r(count($product->fetchAllProductProjects($productID = 1, 'wait', 'all', 'order_desc'))) && p() && e('5'); + +$product->app->loadClass('pager', $static = true); +$pager = new pager(0, 50, 1); +r(count($product->fetchAllProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('20'); + +$pager = new pager(0, 5, 1); +r(count($product->fetchAllProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('5'); + +$product->app->user->admin = false; +$product->app->user->view->projects = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,48,49,50'; +r(count($product->fetchAllProductProjects($productID = 1, 'all', '', 'order_desc'))) && p() && e('7'); +r(count($product->fetchAllProductProjects($productID = 1, 'all', '0', 'order_desc'))) && p() && e('7'); +r(count($product->fetchAllProductProjects($productID = 1, 'undone', '', 'order_desc'))) && p() && e('5'); +r(count($product->fetchAllProductProjects($productID = 1, 'wait', 'all', 'order_desc'))) && p() && e('2'); + +$product->app->loadClass('pager', $static = true); +$pager = new pager(0, 50, 1); +r(count($product->fetchAllProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('7'); + +$pager = new pager(0, 5, 1); +r(count($product->fetchAllProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('5'); diff --git a/module/product/test/tao/fetchinvolvedproductprojects.php b/module/product/test/tao/fetchinvolvedproductprojects.php new file mode 100755 index 0000000000..050a145d4e --- /dev/null +++ b/module/product/test/tao/fetchinvolvedproductprojects.php @@ -0,0 +1,93 @@ +#!/usr/bin/env php +gen(50); +zdTable('user')->gen(50); + +$project = zdTable('project'); +$project->PM->range('user2,user3'); +$project->gen(50); + +$team = zdTable('team'); +$team->root->range('1-50'); +$team->type->range('project'); +$team->account->range('admin,admin,user1,user1'); +$team->days->range('5'); +$team->hours->range('6,7'); +$team->gen(50); + +$stakeholder = zdTable('stakeholder'); +$stakeholder->objectType->range('project'); +$stakeholder->objectID->range('1-50'); +$stakeholder->user->range('user4,user5'); +$stakeholder->type->range('inside'); +$stakeholder->from->range(''); +$stakeholder->gen(50); + +$projectproduct = zdTable('projectproduct'); +$projectproduct->product->range('1-2'); +$projectproduct->project->range('1-50'); +$projectproduct->gen(50); + +/** + +title=测试productModel->fetchPairs(); +cid=1 +pid=1 + +*/ + +global $tester; +$product = $tester->loadModel('product'); +su('admin'); +$product->app->user->admin = true; +$product->app->moduleName = 'product'; +$product->app->methodName = 'project'; + +r(count($product->fetchInvolvedProductProjects($productID = 0, 'all', '', 'order_desc'))) && p() && e('0'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc'))) && p() && e('10'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '0', 'order_desc'))) && p() && e('8'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'undone', '', 'order_desc'))) && p() && e('5'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'wait', 'all', 'order_desc'))) && p() && e('0'); + +$product->app->loadClass('pager', $static = true); +$pager = new pager(0, 50, 1); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('10'); + +$pager = new pager(0, 5, 1); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('5'); + +su('user1'); +$product->app->user->view->projects = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,48,49,50'; +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc'))) && p() && e('3'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '0', 'order_desc'))) && p() && e('3'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'undone', '', 'order_desc'))) && p() && e('3'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'wait', 'all', 'order_desc'))) && p() && e('2'); + +$product->app->loadClass('pager', $static = true); +$pager = new pager(0, 50, 1); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('3'); + +su('user2'); +$product->app->user->view->projects = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,48,49,50'; +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc'))) && p() && e('7'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '0', 'order_desc'))) && p() && e('7'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'undone', '', 'order_desc'))) && p() && e('5'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'wait', 'all', 'order_desc'))) && p() && e('2'); + +$product->app->loadClass('pager', $static = true); +$pager = new pager(0, 50, 1); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('7'); + +su('user4'); +$product->app->user->view->projects = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,48,49,50'; +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc'))) && p() && e('7'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '0', 'order_desc'))) && p() && e('7'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'undone', '', 'order_desc'))) && p() && e('5'); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'wait', 'all', 'order_desc'))) && p() && e('2'); + +$product->app->loadClass('pager', $static = true); +$pager = new pager(0, 50, 1); +r(count($product->fetchInvolvedProductProjects($productID = 1, 'all', '', 'order_desc', $pager))) && p() && e('7'); diff --git a/module/product/ui/create.html.php b/module/product/ui/create.html.php index 057df83c4e..4995acb143 100644 --- a/module/product/ui/create.html.php +++ b/module/product/ui/create.html.php @@ -2,177 +2,40 @@ /** * The create view of product of ZenTaoPMS. */ - -/* - ======= Attention ====== - - This file is generated by zin-tool, you should check the following to-do list. - - + Familiar with the use of these widgets in zin: . - + Check the following variables which used in widgets: $programOptions, $lineOptions, $POOptions, $QDOptions, $RDOptions, $reviewerOptions, $typeOptions, $aclOptions, $whitelistOptions. - + Check the origin code in module/product/view/create.html.php, and ensure that all features have been implemented. - + Check the origin js code in module/product/js/common.js and module/product/js/create.js - + Check the origin css code in module/product/css/common.css and module/product/css/create.css - + Remove the comments which starts with "zin:" - + Test according to the new design draft and the original implementation - */ - namespace zin; -/* ====== Preparing and processing page data ====== */ - -/* zin: Set variables to define picker options for form */ -$programOptions = array(); -$lineOptions = array(); -$POOptions = array(); -$QDOptions = array(); -$RDOptions = array(); -$reviewerOptions = array(); -$typeOptions = array(array('value' => "normal", 'text' => "正常"), array('value' => "branch", 'text' => "多分支(适用于客户定制场景)"), array('value' => "platform", 'text' => "多平台(适用于跨平台应用开发,比如IOS、安卓、PC端等)")); -$aclOptions = array(array('checked' => true, 'value' => "private", 'disabled' => false, 'text' => "私有(产品相关负责人、所属项目集的负责人及干系人、相关联项目的团队成员和干系人可访问)"), array('checked' => false, 'value' => "open", 'disabled' => false, 'text' => "公开(有产品视图权限,即可访问)")); -$whitelistOptions = array(); - - -/* ====== Define the page structure with zin widgets ====== */ /* zin: Define the form in main content */ -formPanel -( - formGroup - ( - set::width("1/3"), - set::name("program"), - set::label("项目集"), - set::control("picker"), - set::items($programOptions) - ), - formRow - ( - set::hidden(true), - formGroup - ( - set::width("1/3"), - set::name("line"), - set::label("产品线"), - set::control("picker"), - set::items($lineOptions) - ) - ), - formGroup - ( - set::width("1/3"), - set::name("name"), - set::label("产品名称"), - set::required(true), - set::control("text") - ), - formGroup - ( - set::width("1/3"), - set::name("PO"), - set::label("产品负责人"), - set::control("picker"), - set::items($POOptions) - ), - formGroup - ( - set::width("1/3"), - set::name("QD"), - set::label("测试负责人"), - set::control("picker"), - set::items($QDOptions) - ), - formGroup - ( - set::width("1/3"), - set::name("RD"), - set::label("发布负责人"), - set::control("picker"), - set::items($RDOptions) - ), - formGroup - ( - set::width("1/3"), - set::name("reviewer[]"), - set::label("评审人"), - set::control(["type" =>"picker","multiple"=>true]), - set::id("reviewer"), - set::items($reviewerOptions) - ), - formGroup - ( - set::width("1/3"), - set::name("type"), - set::label("产品类型"), - set::value("normal"), - set::control("picker"), - set::items($typeOptions) - ), - formGroup - ( - set::width("2/3"), - set::label("产品描述"), - inputGroup - ( - control(set(array - ( - 'id' => "title", - 'value' => "", - 'disabled' => false, - 'type' => "text" - ))), - "公共", - btn(set(array - ( - 'type' => "btn", - 'text' => "保存", - 'class' => "input-group-btn" - ))) - ) - ), - formGroup - ( - set::width("2/3"), - set::name("acl"), - set::label("访问控制"), - set::control("radioList"), - set::items($aclOptions) - ), - formGroup - ( - set::width("1/3"), - set::label("白名单"), - inputGroup - ( - control(set(array - ( - 'name' => "whitelist[]", - 'id' => "whitelist", - 'value' => NULL, - 'disabled' => false, - 'type' => "picker", - 'items' => $whitelistOptions, - 'multiple' => true - ))), - btn(set(array - ( - 'type' => "btn", - 'icon' => "cog", - 'text' => "", - 'class' => "input-group-btn" - ))), - btn(set(array - ( - 'type' => "btn", - 'icon' => "refresh", - 'text' => "", - 'class' => "input-group-btn" - ))) - ) - ) -); +$formItems = array(); +foreach($fields as $field => $info) +{ + $width = zget($info, 'width', '1/3'); + $control['type'] = $info['control']; + if($control['type'] == 'select') $control['type'] = 'picker'; + if(!empty($info['options'])) $control['items'] = $info['options']; + if($info['control'] == 'multi-select') + { + $control['type'] = 'picker'; + $control['multiple'] = true; + $field .= '[]'; + } + if($info['control'] == 'radio') $control['type'] = 'radioList'; + + $formGroup = formGroup + ( + set::width($width), + set::name($field), + set::label($info['title']), + set::control($control), + set::value($info['default']), + set::required($info['required']) + ); + if($info['control'] == 'hidden') $formGroup = formRow(set::hidden(true), $formGroup); + $formItems[$field] = $formGroup; +} + +formPanel($formItems); /* ====== Render page ====== */ - render(); diff --git a/module/product/view/project.html.php b/module/product/view/project.html.php index 6ebdce6889..2f0e1de0bf 100644 --- a/module/product/view/project.html.php +++ b/module/product/view/project.html.php @@ -13,7 +13,7 @@