From ea394d68008ddce86bd72c8e10bb3de1d8ae4baf Mon Sep 17 00:00:00 2001 From: chentao Date: Tue, 9 May 2023 14:43:22 +0800 Subject: [PATCH] * product: refactor view function. --- module/product/control.php | 21 +-- module/product/model.php | 64 ++------ module/product/tao.php | 93 +++++++++++ module/product/test/tao/getlist.php | 2 +- .../product/test/tao/getpagerproductsin.php | 0 .../tao/getpagerproductswithprogramin.php | 0 module/product/test/tao/getstatcountbyid.php | 24 +++ .../test/tao/yaml/getstatcountbyid/bug.yaml | 129 ++++++++++++++++ .../test/tao/yaml/getstatcountbyid/case.yaml | 146 ++++++++++++++++++ .../yaml/getstatcountbyid/productplan.yaml | 46 ++++++ module/product/zen.php | 19 +++ 11 files changed, 482 insertions(+), 62 deletions(-) mode change 100644 => 100755 module/product/test/tao/getlist.php mode change 100644 => 100755 module/product/test/tao/getpagerproductsin.php mode change 100644 => 100755 module/product/test/tao/getpagerproductswithprogramin.php create mode 100755 module/product/test/tao/getstatcountbyid.php create mode 100644 module/product/test/tao/yaml/getstatcountbyid/bug.yaml create mode 100644 module/product/test/tao/yaml/getstatcountbyid/case.yaml create mode 100644 module/product/test/tao/yaml/getstatcountbyid/productplan.yaml diff --git a/module/product/control.php b/module/product/control.php index ff5a4b97e5..68d6690a22 100755 --- a/module/product/control.php +++ b/module/product/control.php @@ -348,36 +348,31 @@ class product extends control } /** + * 查看产品。 * View a product. * * @param int $productID * @access public * @return void */ - public function view($productID) + public function view(string $productID) { $productID = (int)$productID; - $product = $this->product->getStatByID($productID); - - if(!$product) - { - if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'fail', 'code' => 404, 'message' => '404 Not found')); - return print(js::error($this->lang->notFound) . js::locate($this->createLink('product', 'index'))); - } + /* Get product. */ + $product = $this->product->getStatByID($productID); + if(!$product) return $this->productZen->responseNotFound4View(); $product->desc = $this->loadModel('file')->setImgSize($product->desc); + + /* Set navigation menu. */ $this->product->setMenu($productID); - /* Load pager. */ - $this->app->loadClass('pager', $static = true); - $pager = new pager(0, 30, 1); - + /* Execute hooks. */ $this->executeHooks($productID); $this->view->title = $product->name . $this->lang->colon . $this->lang->product->view; $this->view->position[] = html::a($this->createLink($this->moduleName, 'browse'), $product->name); $this->view->position[] = $this->lang->product->view; - $this->view->product = $product; $this->view->actions = $this->loadModel('action')->getList('product', $productID); $this->view->users = $this->user->getPairs('noletter'); diff --git a/module/product/model.php b/module/product/model.php index 7e97b6984d..b81ef44f57 100755 --- a/module/product/model.php +++ b/module/product/model.php @@ -349,7 +349,7 @@ class productModel extends model */ public function getStatusGroups() { - $products = $this->dao->select('id, name, status')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchGroup('status'); + return $this->dao->select('id, name, status')->from(TABLE_PRODUCT)->where('deleted')->eq(0)->fetchGroup('status'); } /** @@ -1279,7 +1279,8 @@ class productModel extends model } /** - * Get product stat by id + * 使用产品ID获取产品统计信息。 + * Get product stat data by product ID. * * @param int $productID * @param string $storyType @@ -1288,57 +1289,24 @@ class productModel extends model */ public function getStatByID($productID, $storyType = 'story') { + /* Check privilege. */ if(!$this->checkPriv($productID)) return false; + /* Get product. */ $product = $this->getById($productID); if(empty($product)) return false; - $stories = $this->dao->select('product, status, count(status) AS count')->from(TABLE_STORY) - ->where('deleted')->eq(0) - ->andWhere('type')->eq($storyType) - ->andWhere('product')->eq($productID) - ->groupBy('product, status') - ->fetchAll('status'); - - /* Padding the stories to sure all status have records. */ - foreach(array_keys($this->lang->story->statusList) as $status) - { - $stories[$status] = isset($stories[$status]) ? $stories[$status]->count : 0; - } - - $plans = $this->dao->select('count(*) AS count')->from(TABLE_PRODUCTPLAN)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->andWhere('end')->gt(helper::now())->fetch(); - $builds = $this->dao->select('count(*) AS count')->from(TABLE_BUILD)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); - $cases = $this->dao->select('count(*) AS count')->from(TABLE_CASE)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); - $bugs = $this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); - $docs = $this->dao->select('count(*) AS count')->from(TABLE_DOC)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); - $releases = $this->dao->select('count(*) AS count')->from(TABLE_RELEASE)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); - $projects = $this->dao->select('count(*) AS count')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->where('t2.deleted')->eq(0) - ->andWhere('t1.product')->eq($productID) - ->andWhere('t2.type')->eq('project') - ->fetch(); - - $executions = $this->dao->select('count(*) AS count')->from(TABLE_PROJECTPRODUCT)->alias('t1') - ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') - ->where('t2.deleted')->eq(0) - ->andWhere('t1.product')->eq($productID) - ->andWhere('t2.type')->in('sprint,stage,kanban') - ->fetch(); - - $product->stories = $stories; - $product->plans = $plans ? $plans->count : 0; - $product->releases = $releases ? $releases->count : 0; - $product->builds = $builds ? $builds->count : 0; - $product->cases = $cases ? $cases->count : 0; - $product->projects = $projects ? $projects->count : 0; - $product->executions = $executions ? $executions->count : 0; - $product->bugs = $bugs ? $bugs->count : 0; - $product->docs = $docs ? $docs->count : 0; - - $closedTotal = $this->dao->select('count(id) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->andWhere('status')->eq('closed')->fetch('count'); - $allTotal = $this->dao->select('count(id) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch('count'); - $product->progress = empty($closedTotal) ? 0 : round($closedTotal / $allTotal * 100, 1); + /* Attach statistic data. */ + $product->stories = $this->productTao->getStoryStatusCountByID($productID, $storyType); + $product->plans = $this->productTao->getStatCountByID(TABLE_PRODUCTPLAN, $productID); + $product->releases = $this->productTao->getStatCountByID(TABLE_BUILD, $productID); + $product->builds = $this->productTao->getStatCountByID(TABLE_CASE, $productID); + $product->cases = $this->productTao->getStatCountByID(TABLE_BUG, $productID); + $product->projects = $this->productTao->getStatCountByID(TABLE_DOC, $productID); + $product->executions = $this->productTao->getStatCountByID(TABLE_RELEASE, $productID); + $product->bugs = $this->productTao->getStatCountByID(TABLE_PROJECTPRODUCT, $productID); + $product->docs = $this->productTao->getStatCountByID('executions', $productID); + $product->progress = $this->productTao->getStatCountByID('progress', $productID); return $product; } diff --git a/module/product/tao.php b/module/product/tao.php index 88666848ce..18f3addc40 100644 --- a/module/product/tao.php +++ b/module/product/tao.php @@ -918,4 +918,97 @@ class productTao extends productModel return array($roadmaps, $total, $return); } + + /** + * 通过产品ID查询产品关联需求的各状态统计总数。 + * Get stories total count of each status by product ID. + * + * @param int $productID + * @param string $storyType + * @access protected + * @return array + */ + protected function getStoryStatusCountByID(int $productID, string $storyType = 'story'): array + { + /* TODO move to story module. */ + $stories = $this->dao->select('product, status, count(status) AS count')->from(TABLE_STORY) + ->where('deleted')->eq(0) + ->andWhere('type')->eq($storyType) + ->andWhere('product')->eq($productID) + ->groupBy('product, status') + ->fetchAll('status'); + + /* Padding the stories to sure all status have records. */ + foreach(array_keys($this->lang->story->statusList) as $status) + { + $stories[$status] = isset($stories[$status]) ? $stories[$status]->count : 0; + } + + return $stories; + } + + /** + * 通过产品ID查询产品关联的统计数据。 + * Get stat count by product ID. + * + * @param int $productID + * @access protected + * @return int + */ + protected function getStatCountByID(string $tableName, int $productID): int + { + switch ($tableName) + { + case TABLE_PRODUCTPLAN: + /* Get unclosed plans count. */ + $record = $this->dao->select('count(*) AS count')->from(TABLE_PRODUCTPLAN)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->andWhere('end')->gt(helper::now())->fetch(); + break; + case TABLE_BUILD: + /* Get builds count. */ + $record = $this->dao->select('count(*) AS count')->from(TABLE_BUILD)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); + break; + case TABLE_CASE: + /* Get cases count. */ + $record = $this->dao->select('count(*) AS count')->from(TABLE_CASE)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); + break; + case TABLE_BUG: + /* Get bugs count. */ + $record = $this->dao->select('count(*) AS count')->from(TABLE_BUG)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); + break; + case TABLE_DOC: + /* Get docs count. */ + $record = $this->dao->select('count(*) AS count')->from(TABLE_DOC)->where('product')->eq($productID)->andWhere('deleted')->eq(0)->fetch(); + break; + case TABLE_RELEASE: + /* Get releases count. */ + $record = $this->dao->select('count(*) AS count')->from(TABLE_RELEASE)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch(); + break; + case TABLE_PROJECTPRODUCT: + $record = $this->dao->select('count(*) AS count')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t2.deleted')->eq(0) + ->andWhere('t1.product')->eq($productID) + ->andWhere('t2.type')->eq('project') + ->fetch(); + break; + case 'executions': + $record = $this->dao->select('count(*) AS count')->from(TABLE_PROJECTPRODUCT)->alias('t1') + ->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id') + ->where('t2.deleted')->eq(0) + ->andWhere('t1.product')->eq($productID) + ->andWhere('t2.type')->in('sprint,stage,kanban') + ->fetch(); + break; + case 'progress': + $closedTotal = $this->dao->select('count(id) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->andWhere('status')->eq('closed')->fetch('count'); + if(empty($closedTotal)) return 0; + + $allTotal = $this->dao->select('count(id) AS count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('product')->eq($productID)->fetch('count'); + return round($closedTotal / $allTotal * 100, 1); + default: + return 0; + } + + return $record ? $record->count : 0; + } } diff --git a/module/product/test/tao/getlist.php b/module/product/test/tao/getlist.php old mode 100644 new mode 100755 index a832ab4ec4..f8a9819bd8 --- a/module/product/test/tao/getlist.php +++ b/module/product/test/tao/getlist.php @@ -1,6 +1,6 @@ #!/usr/bin/env php config('productplan')->gen(100); + zdTable('case')->config('case')->gen(100); + zdTable('bug')->config('bug')->gen(100); +} +initData(); + +/** +title=productTao->getStatCountByID(); +cid=2 + + */ + +$product = new productTest('admin'); + +r($product->objectModel->getStatCountByID(TABLE_PRODUCTPLAN, 1)) && p('') && e('5'); +r($product->objectModel->getStatCountByID(TABLE_CASE, 1)) && p('') && e('4'); +r($product->objectModel->getStatCountByID(TABLE_BUG, 1)) && p('') && e('3'); diff --git a/module/product/test/tao/yaml/getstatcountbyid/bug.yaml b/module/product/test/tao/yaml/getstatcountbyid/bug.yaml new file mode 100644 index 0000000000..f80dfc3e5d --- /dev/null +++ b/module/product/test/tao/yaml/getstatcountbyid/bug.yaml @@ -0,0 +1,129 @@ +title: zt_bug +desc: "Bug表" +author: automated export +version: "1.0" +fields: + - field: id + range: 1-10000 + - field: project + range: 11-100{3},0{30} + - field: product + range: 1-100{3} + - field: branch + range: 0{120},0-2,0,3-4,0,5-6,0,7-8,0,9-10,0{100000000} + - field: module + range: 1821-1823,1825-1827,1831-1833,0{1000000} + - field: execution + range: 101-700{3} + - 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 + fields: + - field: title1 + range: BUG{6},`缺陷!@()[]{}|\+=%^&*$#测试bug名称到底可以有多长!@#¥%&*'":.<>。?/();`,bug + - field: title2 + range: 1-10000 + - field: keywords + range: "[]" + - field: severity + range: 1-4 + - field: pri + range: 1-4 + - field: type + range: "[codeerror,config,install,security,performance,standard,automation,designdefect,others]" + - field: os + range: "[]{2},[win10,windows,android,ios]" + - field: browser + range: "[]" + - field: hardware + range: "[]" + - field: found + range: "[]" + - field: steps + range: "[

【步骤】


【结果】


【期望】


,【步骤】进入成果展示
【结果】乱码
【期望】正常显示
]" + - field: status + range: active{50},resolved{30},closed{20} + - 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,0,1,trunk{97} + - 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: 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: deleted + range: 0{40},1{10},0{50} diff --git a/module/product/test/tao/yaml/getstatcountbyid/case.yaml b/module/product/test/tao/yaml/getstatcountbyid/case.yaml new file mode 100644 index 0000000000..b052944d97 --- /dev/null +++ b/module/product/test/tao/yaml/getstatcountbyid/case.yaml @@ -0,0 +1,146 @@ +title: table zt_case +desc: "测试用例" +author: automated export +version: "1.0" +fields: + - field: id + note: "ID" + range: 1-400 + - field: product + note: "产品ID" + range: 1-100{4} + - field: branch + note: "分支ID" + range: 0 + - field: execution + note: "执行ID" + range: 101-700{4} + - field: lib + note: "所属库" + range: 0 + - field: module + note: "所属模块" + range: 0 + - field: path + note: "" + range: "0" + - field: story + note: "相关需求" + range: 2-400:4{4} + - field: storyVersion + note: "需求版本" + range: "1" + - field: title + note: "用例标题" + range: "1-400" + prefix: "这个是测试用例" + - field: precondition + note: "前置条件" + range: "1-400" + prefix: "这是前置条件" + - field: keywords + note: "关键词" + range: "1-400" + prefix: "这是关键词" + - field: pri + note: "优先级" + range: 1-4 + - field: type + note: "用例类型" + range: feature,performance,config,install,security,interface,other + - field: auto + note: "是否是自动化测试用例" + range: "no" + - field: frame + note: "自动化测试框架" + range: "" + - field: stage + note: "适用阶段" + range: unittest,feature,intergrate,system,smoke,bvt + - field: howRun + note: "测试方式" + range: "" + - field: scriptedBy + note: "脚本由谁创建" + range: "" + - field: scriptedDate + note: "脚本创建日期" + range: "(M)-(w)" + type: timestamp + postfix: "" + format: "YY/MM/DD" + - field: scriptStatus + note: "脚本状态" + range: "" + - field: scriptLocation + note: "脚本地址" + range: "" + - field: status + note: "用例状态" + range: wait,normal,blocked,investigate + - field: subStatus + note: "子状态" + range: "" + - field: color + note: "标题颜色" + - field: frequency + note: "使用频率" + range: 1-3 + - field: order + note: "排序" + range: 1-500:5 + - field: openedBy + note: "由谁创建" + range: 1-100 + prefix: "test" + - field: openedDate + note: "创建日期" + range: "-:600" + type: timestamp + format: "YYYY-MM-DD hh:mm:ss" + - field: reviewedBy + note: "由谁评审" + range: admin + - field: reviewedDate + note: "评审时间" + range: "-:300" + type: timestamp + format: "YYYY-MM-DD hh:mm:ss" + - field: lastEditedBy + note: "最后修改者" + range: admin + - field: lastEditedDate + note: "修改日期" + range: "-:300" + type: timestamp + format: "YYYY-MM-DD hh:mm:ss" + - field: version + note: "用例版本" + range: "1" + - field: linkCase + note: "相关用例" + range: 0 + - field: fromBug + note: "来源Bug" + range: 0 + - field: fromCaseID + note: "" + range: 0 + - field: fromCaseVersion + note: "" + range: 1 + - field: deleted + note: "是否删除" + range: 0{9950},1{50} + - field: lastRunner + note: "执行人" + range: 1-100 + prefix: "test" + - field: lastRunDate + note: "执行时间" + range: "-:500" + type: timestamp + format: "YYYY-MM-DD hh:mm:ss" + - field: lastRunResult + note: "结果" + range: "[pass,fail]" diff --git a/module/product/test/tao/yaml/getstatcountbyid/productplan.yaml b/module/product/test/tao/yaml/getstatcountbyid/productplan.yaml new file mode 100644 index 0000000000..5136ec20ef --- /dev/null +++ b/module/product/test/tao/yaml/getstatcountbyid/productplan.yaml @@ -0,0 +1,46 @@ +title: table zt_productplan +desc: "产品计划" +author: sgm +version: "1.0" +fields: + - field: id + note: "ID" + range: 1-100 + - field: product + note: "所属产品" + range: 1-10 + - field: branch + note: "所属分支" + range: 0{30},1-40 + - field: parent + note: "父计划" + range: 0 + - field: title + note: "名称" + range: "[1.0,1.1,长名称好长好长好长好长好长好长好长好长好长好长好长好好长好长好长好长好长好好长好长好长好长好长好好长好长好长好长好长好的名字啊!@ase!!@#%@^&#!]" + - field: desc + note: "描述" + range:
+

asdxxxfa阿萨德开机as家世界发卡机发设计费啥登记卡设计费卡加斯加附件阿峰

+

123a阿士大夫姐姐姐经历过反对派呸呸呸史蒂夫接收到付款纪委第三方乐山大佛量减少地方

+

IU风格就叫阿萨德奥斯丁哦IG是DAU发加速度快哦哦阿萨德几年内发,,,奥斯丁,,,切,,,请问加十多年你

+

IUIG是DAU发加速度快哦哦阿萨德几年内发,,,奥斯丁,,,切,,,请问加十多年你

+

IU风格就叫阿萨德奥斯丁哦IG是DAU,,,奥斯丁,,,切,,,请问加十多年你

+
+ - field: begin + note: "开始日期" + range: "(-10M)-(-7M):7D" + type: timestamp + format: "YYYY-MM-DD" + - field: end + note: "结束日期" + range: "(-6M)-(+6M):7D" + type: timestamp + format: "YYYY-MM-DD" + - field: order + note: "排序" + value: "$id * 5" + - field: deleted + note: "是否删除" + range: 0,1 + diff --git a/module/product/zen.php b/module/product/zen.php index 3aed1c7b65..ae7f0df215 100644 --- a/module/product/zen.php +++ b/module/product/zen.php @@ -1311,4 +1311,23 @@ class productZen extends product $this->session->set('releaseList', $this->app->getURI(true), 'product'); $this->session->set('productPlanList', $this->app->getURI(true), 'product'); } + + /** + * 回复产品不存在提示消息。 + * Response product not found message. + * + * @access protected + * @return void + */ + protected function responseNotFound4View(): void + { + if(defined('RUN_MODE') && RUN_MODE == 'api') + { + $this->send(array('status' => 'fail', 'code' => 404, 'message' => '404 Not found')); + return; + } + + print(js::error($this->lang->notFound) . js::locate($this->createLink('product', 'index'))); + return; + } }