Merge branch feature/task-report-merge of zentao/zentaopms (#10255)

This commit is contained in:
刘刚
2025-07-08 16:13:32 +08:00
committed by Gitfox
212 changed files with 9305 additions and 1932 deletions
+1
View File
@@ -364,6 +364,7 @@ $config->logonMethods[] = 'user.logout';
$config->logonMethods[] = 'zanode.nodelist';
$config->logonMethods[] = 'screen.viewold';
$config->logonMethods[] = 'system.backupview';
$config->logonMethods[] = 'screen.staticdataold';
$config->openModules = array();
$config->openModules[] = 'install';
+2 -2
View File
@@ -1450,12 +1450,12 @@ if(!interface_exists('JsonSerializable'))
public function jsonSerialize();
}
function json_encode($data)
function json_encode($data, $flags = 0, $depth = 512)
{
return $data;
}
function json_decode($data)
function json_decode($data, $associative = null, $depth = 512, $flags = 0)
{
return $data;
}
-1
View File
@@ -327,7 +327,6 @@ class sqlparser
$exprA = empty($tableA) ? "`$columnA`" : "`$tableA`.`$columnA`";
$exprB = empty($tableB) ? $columnB : "`$tableB`.`$columnB`";
$operator = strtoupper($operator);
$expr = "$exprA $operator $exprB";
}
+1 -1
View File
@@ -283,7 +283,7 @@ $lang->bug->resolutionList['external'] = 'External';
$lang->bug->resolutionList['fixed'] = 'Resolved';
$lang->bug->resolutionList['notrepro'] = 'Irreproducible';
$lang->bug->resolutionList['postponed'] = 'Postponed';
$lang->bug->resolutionList['willnotfix'] = "Won't Fix";
$lang->bug->resolutionList['willnotfix'] = 'Will not fix';
$lang->bug->resolutionList['tostory'] = 'Convert to Story';
/* Statistical statement. */
@@ -58,6 +58,7 @@ class chartTest
public function isClickableTest(int $chartID, string $action): string
{
$chart = $this->objectModel->getByID($chartID);
if(!$chart) return 'false';
return $this->objectModel->isClickable($chart, $action) ? 'true' : 'false';
}
}
+9 -9
View File
@@ -9,9 +9,9 @@ cid=1
- 测试内置报表的设计按钮是否不可点击 @false
- 测试内置报表的编辑按钮是否不可点击 @false
- 测试内置报表的删除按钮是否不可点击 @false
- 测试非内置报表的设计按钮是否可点击 @true
- 测试非内置报表的编辑按钮是否可点击 @true
- 测试非内置报表的删除按钮是否可点击 @true
- 测试非内置报表的设计按钮是否可点击 @false
- 测试非内置报表的编辑按钮是否可点击 @false
- 测试非内置报表的删除按钮是否可点击 @false
*/
@@ -22,9 +22,9 @@ zenData('user')->gen(5);
su('admin');
$chart = new chartTest();
r($chart->isClickableTest(32, 'design')) && p() && e('false'); //测试内置报表的设计按钮是否不可点击
r($chart->isClickableTest(32, 'edit')) && p() && e('false'); //测试内置报表的编辑按钮是否不可点击
r($chart->isClickableTest(32, 'delete')) && p() && e('false'); //测试内置报表的删除按钮是否不可点击
r($chart->isClickableTest(37, 'design')) && p() && e('true'); //测试非内置报表的设计按钮是否可点击
r($chart->isClickableTest(37, 'edit')) && p() && e('true'); //测试非内置报表的编辑按钮是否可点击
r($chart->isClickableTest(37, 'delete')) && p() && e('true'); //测试非内置报表的删除按钮是否可点击
r($chart->isClickableTest(32, 'design')) && p() && e('false'); //测试不存在的报表的设计按钮是否不可点击
r($chart->isClickableTest(32, 'edit')) && p() && e('false'); //测试不存在的报表的编辑按钮是否不可点击
r($chart->isClickableTest(32, 'delete')) && p() && e('false'); //测试不存在的报表的删除按钮是否不可点击
r($chart->isClickableTest(10020, 'design')) && p() && e('false'); //测试内置报表的设计按钮是否可点击
r($chart->isClickableTest(10020, 'edit')) && p() && e('false'); //测试内置报表的编辑按钮是否可点击
r($chart->isClickableTest(10020, 'delete')) && p() && e('false'); //测试内置报表的删除按钮是否可点击
+5 -1
View File
@@ -17,6 +17,8 @@ cid=1
- 倒序追加id排序 @account_desc,id_desc
- 默认值追加id排序 @account,id_asc
*/
global $tester;
@@ -26,8 +28,10 @@ $order1 = $tester->common->appendOrder('status_asc', 'name');
$order2 = $tester->common->appendOrder('status_desc', 'name');
$order3 = $tester->common->appendOrder('account_asc', 'id');
$order4 = $tester->common->appendOrder('account_desc', 'id');
$order5 = $tester->common->appendOrder('account');
r($order1) && p() && e('status_asc,name_asc'); // 正序追加name排序
r($order2) && p() && e('status_desc,name_desc'); // 倒序追加name排序
r($order3) && p() && e('account_asc,id_asc'); // 正序追加id排序
r($order4) && p() && e('account_desc,id_desc'); // 倒序追加id排序
r($order4) && p() && e('account_desc,id_desc'); // 倒序追加id排序
r($order5) && p() && e('account,id_asc'); // 默认值追加id排序
+1
View File
@@ -25,6 +25,7 @@ $config->index->appGroup['user'] = 'admin';
$config->index->oldPages = array();
$config->index->oldPages[] = 'screen-burn';
$config->index->oldPages[] = 'screen-viewold';
$config->index->oldPages[] = 'screen-staticdataold';
$config->index->oldPages[] = 'report-annualdata';
$config->index->oldPages[] = 'ai-adminindex';
$config->index->oldPages[] = 'ai-chat';
+35
View File
@@ -729,4 +729,39 @@ class baseCalc
return $executions;
}
/**
* 检查日期。
* Validate date.
*
* @param string $date
* @access public
* @return bool
*/
public function validateDate(string $date): bool
{
return $this->getYear($date) !== false;
}
/**
* 按日期递增计数。
* Count incrementally by date.
*
* @param int $dataID
* @param string $date
* @access public
* @return void
*/
public function incrementDateCount(int $dataID, string $date)
{
$date = substr($date, 0, 10);
list($year, $month, $day) = explode('-', $date);
if(!isset($this->result[$dataID])) $this->result[$dataID] = array();
if(!isset($this->result[$dataID][$year])) $this->result[$dataID][$year] = array();
if(!isset($this->result[$dataID][$year][$month])) $this->result[$dataID][$year][$month] = array();
if(!isset($this->result[$dataID][$year][$month][$day])) $this->result[$dataID][$year][$month][$day] = 0;
$this->result[$dataID][$year][$month][$day]++;
}
}
@@ -29,7 +29,7 @@ class consume_of_frombug_task_in_execution extends baseCalc
public function calculate($row)
{
if($row->isParent == '1') return;
if($row->parent == '0' && $row->fromBug == 0) return;
if($row->fromBug == 0) return;
if(!isset($this->result[$row->execution])) $this->result[$row->execution] = 0;
$this->result[$row->execution] += $row->consumed;
@@ -0,0 +1,53 @@
<?php
/**
* 按类型统计的关联需求的任务消耗工时数。
* Consume of task in type in execution.
*
* 范围:execution
* 对象:task
* 目的:hour
* 度量名称:按类型统计的关联需求的任务消耗工时数
* 单位:小时
* 描述:按类型统计的关联需求的任务消耗工时数是指已经花费的工时总和,用于完成所有任务。该度量项反映了任务的实际完成情况和资源使用情况,可以帮助团队掌握任务的进展情况和资源利用效率。
* 定义:执行中任务的消耗工时数求和;过滤已删除的任务;过滤父任务;过滤未关联需求的任务;过滤已删除的执行;过滤已删除的项目;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class consume_of_task_in_type_in_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if($row->isParent == '1') return;
if(empty($row->story)) return;
if(!isset($this->result[$row->type])) $this->result[$row->type] = array();
$this->result[$row->type][$row->id] = $row->consumed;
}
public function getResult($options = array())
{
foreach($this->result as $type => $tasks)
{
if(!is_array($tasks))
{
unset($this->result[$type]);
continue;
}
$this->result[$type] = array_sum($tasks);
}
$records = $this->getRecords(array('type', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,49 @@
<?php
/**
* 按执行统计的来源Bug的任务消耗工时占比
* Consume rate of frombug task in execution
*
* 范围:execution
* 对象:task
* 目的:rate
* 度量名称:按执行统计的来源Bug的任务消耗工时占比
* 单位:百分比
* 描述:按执行统计的来源Bug的任务消耗工时占比是指执行中Bug转任务消耗的工时与执行中所有任务消耗工时的比值。该度量项反映了任务来源为Bug的资源使用情况,可以帮助团队识别缺陷管理中存在的问题,例如历史遗留缺陷过多导致执行一直在补旧账。
* 定义:复用:按执行统计的来源Bug的任务消耗工时数、按执行统计的任务消耗工时数;公式:按执行统计的来源Bug的任务消耗工时数/按执行统计的任务消耗工时数。
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author zhouxin <zhouxin@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class rate_of_frombug_task_in_execution extends baseCalc
{
public $result = array();
public $dataset = 'getTasks';
public $fieldList = array('t1.execution', 't1.consumed', 't1.parent', 't1.fromBug', 't1.isParent');
public function calculate($row)
{
if(!isset($this->result[$row->execution])) $this->result[$row->execution] = array('bug' => 0, 'total' => 0);
if($row->fromBug != 0) $this->result[$row->execution]['bug'] ++;
$this->result[$row->execution]['total'] ++;
}
public function getResult($options = array())
{
$records = array();
foreach($this->result as $executionID => $count)
{
$records[] = array(
'execution' => $executionID,
'value' => $count['total'] ? round($count['bug'] / $count['total'], 4) : 0
);
}
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,44 @@
<?php
/**
* 按执行统计的激活Bug数。
* Count of activated bug in execution.
*
* 范围:execution
* 对象:bug
* 目的:scale
* 度量名称:按执行统计的激活Bug数
* 单位:个
* 描述:按执行统计的激活Bug数是指当前未解决的Bug数量。这个度量项反映了执行当前存在的待解决问题数量。激活Bug总数越多可能代表执行的稳定性较低,需要加强Bug解决的速度和质量。
* 定义:执行中Bug个数求和;状态为激活;过滤已删除的Bug;过滤已删除的执行;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author qixinzhi <qixinzhi@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_activated_bug_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array('t1.status', 't1.execution');
public $result = array();
public function calculate($row)
{
$execution = $row->execution;
$status = $row->status;
if(!isset($this->result[$execution])) $this->result[$execution] = 0;
if($status == 'active') $this->result[$execution] += 1;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('execution', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按优先级统计的执行下的Bug数。
* Count of bug in pri in execution.
*
* 范围:pri
* 对象:bug
* 目的:scale
* 度量名称:按优先级统计的执行下的Bug数
* 单位:个
* 描述:按优先级统计的执行下的Bug数
* 定义:按优先级统计的执行下的Bug数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_bug_in_pri_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->pri])) $this->result[$row->pri] = array();
$this->result[$row->pri][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $pri => $bugs)
{
if(!is_array($bugs))
{
unset($this->result[$pri]);
continue;
}
$this->result[$pri] = count($bugs);
}
$records = $this->getRecords(array('pri', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按解决方案统计的执行下的Bug数。
* Count of bug in resolution in execution.
*
* 范围:resolution
* 对象:bug
* 目的:scale
* 度量名称:按解决方案统计的执行下的Bug数
* 单位:个
* 描述:按解决方案统计的执行下的Bug数
* 定义:按解决方案统计的执行下的Bug数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_bug_in_resolution_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->resolution])) $this->result[$row->resolution] = array();
$this->result[$row->resolution][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $resolution => $bugs)
{
if(!is_array($bugs))
{
unset($this->result[$resolution]);
continue;
}
$this->result[$resolution] = count($bugs);
}
$records = $this->getRecords(array('resolution', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,51 @@
<?php
/**
* 按严重程度统计的执行下的Bug数。
* Count of bug in severity in execution.
*
* 范围:severity
* 对象:bug
* 目的:scale
* 度量名称:按严重程度统计的执行下的Bug数
* 单位:个
* 描述:按严重程度统计的执行下的Bug数
* 定义:按严重程度统计的执行下的Bug数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_bug_in_severity_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->severity])) $this->result[$row->severity] = array();
$this->result[$row->severity][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $severity => $bugs)
{
if(!is_array($bugs))
{
unset($this->result[$severity]);
continue;
}
$this->result[$severity] = count($bugs);
}
$records = $this->getRecords(array('severity', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,51 @@
<?php
/**
* 按状态统计的Bug数。
* Count of bug in status.
*
* 范围:status
* 对象:bug
* 目的:scale
* 度量名称:按状态统计的Bug数
* 单位:个
* 描述:按状态统计的Bug数
* 定义:按状态统计的Bug数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_bug_in_status_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->status])) $this->result[$row->status] = array();
$this->result[$row->status][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $status => $tasks)
{
if(!is_array($tasks))
{
unset($this->result[$status]);
continue;
}
$this->result[$status] = count($tasks);
}
$records = $this->getRecords(array('status', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,51 @@
<?php
/**
* 按类型统计的执行下的Bug数。
* Count of bug in type in execution.
*
* 范围:type
* 对象:bug
* 目的:scale
* 度量名称:按类型统计的执行下的Bug数
* 单位:个
* 描述:按类型统计的执行下的Bug数
* 定义:按类型统计的执行下的Bug数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_bug_in_type_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->type])) $this->result[$row->type] = array();
$this->result[$row->type][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $type => $bugs)
{
if(!is_array($bugs))
{
unset($this->result[$type]);
continue;
}
$this->result[$type] = count($bugs);
}
$records = $this->getRecords(array('type', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,43 @@
<?php
/**
* 按执行统计的执行用例产生的Bug总数。
* Count of bug of executing use cases in execution.
*
* 范围:execution
* 对象:bug
* 目的:scale
* 度量名称:按执行统计的执行用例产生的Bug总数
* 单位:个
* 描述:按执行统计的执行用例产生的Bug总数是指在执行中发现的有效Bug的数量。这个度量项反映了执行的质量情况。执行用例产生的Bug数越多可能代表执行的代码质量存在的问题越多,需要进行进一步的解决和改进。
* 定义:执行中新增Bug个数求和;解决方案为已解决、延期处理和不予解决或状态为激活;过滤已删除的执行;过滤已删除的项目;过滤已删除的产品。
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_case_bug_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array('t1.execution', 't1.case');
public $result = array();
public function calculate($row)
{
if(!empty($row->case))
{
if(!isset($this->result[$row->execution])) $this->result[$row->execution] = 0;
$this->result[$row->execution] ++;
}
}
public function getResult($options = array())
{
$records = $this->getRecords(array('execution', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按优先级统计的执行下的用例数。
* Count of case in pri in execution.
*
* 范围:pri
* 对象:case
* 目的:scale
* 度量名称:按优先级统计的执行下的用例数
* 单位:个
* 描述:按优先级统计的执行下的用例数
* 定义:按优先级统计的执行下的用例数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_case_in_pri_in_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->pri])) $this->result[$row->pri] = array();
$this->result[$row->pri][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $pri => $cases)
{
if(!is_array($cases))
{
unset($this->result[$pri]);
continue;
}
$this->result[$pri] = count($cases);
}
$records = $this->getRecords(array('pri', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按结果统计的执行下的用例数。
* Count of case in result in execution.
*
* 范围:lastRunResult
* 对象:case
* 目的:scale
* 度量名称:按结果统计的执行下的用例数
* 单位:个
* 描述:按结果统计的执行下的用例数
* 定义:按结果统计的执行下的用例数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_case_in_result_in_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->lastRunResult])) $this->result[$row->lastRunResult] = array();
$this->result[$row->lastRunResult][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $lastRunResult => $cases)
{
if(!is_array($cases))
{
unset($this->result[$lastRunResult]);
continue;
}
$this->result[$lastRunResult] = count($cases);
}
$records = $this->getRecords(array('result', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按状态统计的执行下的用例数。
* Count of case in status in execution.
*
* 范围:pri
* 对象:case
* 目的:scale
* 度量名称:按状态统计的执行下的用例数
* 单位:个
* 描述:按状态统计的执行下的用例数
* 定义:按状态统计的执行下的用例数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_case_in_status_in_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->status])) $this->result[$row->status] = array();
$this->result[$row->status][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $status => $cases)
{
if(!is_array($cases))
{
unset($this->result[$status]);
continue;
}
$this->result[$status] = count($cases);
}
$records = $this->getRecords(array('status', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按类型统计的执行下的用例数。
* Count of case in type in execution.
*
* 范围:type
* 对象:case
* 目的:scale
* 度量名称:按类型统计的执行下的用例数
* 单位:个
* 描述:按类型统计的执行下的用例数
* 定义:按类型统计的执行下的用例数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_case_in_type_in_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->type])) $this->result[$row->type] = array();
$this->result[$row->type][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $type => $cases)
{
if(!is_array($cases))
{
unset($this->result[$type]);
continue;
}
$this->result[$type] = count($cases);
}
$records = $this->getRecords(array('type', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,40 @@
<?php
/**
* 按执行统计的每日关闭Bug数。
* Count of daily closed bug in execution.
*
* 范围:execution
* 对象:bug
* 目的:scale
* 度量名称:按执行统计的每日关闭Bug数
* 单位:个
* 描述:按执行统计的每日关闭Bug数是指每天在执行中每日关闭的Bug的数量。该度量项可以帮助我们了解开发团队对已解决的Bug进行确认与关闭的速度和效率,通过对比不同时间段的关闭Bug数,可以评估开发团队的协作和问题处理能力。
* 定义:执行中Bug数求和,关闭时间为某日,过滤已删除的Bug,过滤已删除的执行。
*
* @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author songchenxuan <songchenxuan@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_daily_closed_bug_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array('t1.execution', 't1.status', 't1.closedDate');
public $result = array();
public function calculate($row)
{
if($row->status != 'closed' || !$this->validateDate($row->closedDate)) return false;
$this->incrementDateCount($row->execution, $row->closedDate);
}
public function getResult($options = array())
{
$records = $this->getRecords(array('execution', 'year', 'month', 'day'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,40 @@
<?php
/**
* 按执行统计的每日新增Bug数。
* Count of daily created bug in execution.
*
* 范围:execution
* 对象:bug
* 目的:scale
* 度量名称:按执行统计的每日新增Bug数
* 单位:个
* 描述:按执行统计的每日新增Bug数是指在每天的执行开始后新发现并记录的Bug数量。该度量项可以体现执行开始后Bug的发现速度和趋势,较高的新增Bug数可能意味着存在较多的问题需要解决,同时也可以帮助识别执行开始后的瓶颈和潜在的质量风险。
* 定义:执行中Bug数求和,创建时间为某日,过滤已删除的Bug,过滤已删除的执行。
*
* @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author songchenxuan <songchenxuan@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_daily_created_bug_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array('t1.execution', 't1.openedDate');
public $result = array();
public function calculate($row)
{
if(!$this->validateDate($row->openedDate)) return false;
$this->incrementDateCount($row->execution, $row->openedDate);
}
public function getResult($options = array())
{
$records = $this->getRecords(array('execution', 'year', 'month', 'day', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,41 @@
<?php
/**
* 按执行统计的每日解决Bug数。
* Count of daily resolved bug in execution.
*
* 范围:execution
* 对象:bug
* 目的:scale
* 度量名称:按执行统计的每日解决Bug数
* 单位:个
* 描述:按执行统计的每日解决Bug数是指执行每日解决的Bug的数量。该度量项可以帮助我们了解开发团队解决Bug的速度和效率。
* 定义:执行中Bug数求和,解决日期为某日,过滤已删除的Bug,过滤已删除的执行。
*
* @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author songchenxuan <songchenxuan@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_daily_resolved_bug_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array('t1.execution', 't1.status', 't1.resolvedDate');
public $result = array();
public function calculate($row)
{
if($row->status == 'active' || !$this->validateDate($row->resolvedDate)) return false;
$this->incrementDateCount($row->execution, $row->resolvedDate);
}
public function getResult($options = array())
{
$records = $this->getRecords(array('execution', 'year', 'month', 'day', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -9,7 +9,7 @@
* 度量名称:按执行统计的研发完成的研发需求数
* 单位:个
* 描述:按执行统计的研发完成的研发需求数是指执行中研发完成的研发需求的数量。这个度量项可以反映执行的进展。研发完成的研发需求数越多,说明执行团队在该时间段内取得了更多的研发成果。
* 定义:执行中所处阶段为研发完毕、测试中、测试完毕、已验收、已发布和关闭原因为已完成的研发需求个数求和;过滤已删除的研发需求;过滤已删除产品的研发需求;过滤已删除的执行;
* 定义:执行中所处阶段为研发完毕、测试中、测试完毕、已验收、交付中、已交付、已发布和关闭原因为已完成的研发需求个数求和;过滤已删除的研发需求;过滤已删除产品的研发需求;过滤已删除的执行;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author qixinzhi <qixinzhi@easycorp.ltd>
@@ -34,8 +34,8 @@ class count_of_developed_story_in_execution extends baseCalc
if(!isset($this->result[$execution])) $this->result[$execution] = 0;
if(in_array($stage, array('developed', 'testing', 'tested', 'verified', 'released'))) $this->result[$execution] += 1;
if($closedReason) $this->result[$execution] += 1;
if(in_array($stage, array('developed', 'testing', 'tested', 'verified', 'delivering', 'delivered', 'released'))) $this->result[$execution] += 1;
if($closedReason == 'done') $this->result[$execution] += 1;
}
public function getResult($options = array())
@@ -0,0 +1,42 @@
<?php
/**
* 按执行统计的已修复Bug数。
* Count of fixed bug in execution.
*
* 范围:execution
* 对象:bug
* 目的:scale
* 度量名称:按执行统计的已修复Bug数
* 单位:个
* 描述:按执行统计的已修复Bug数是指解决方案为已解决并且状态为已关闭的Bug数量。这个度量项反映了执行解决的问题数量。已修复Bug数的可以评估开发团队在Bug解决方面的工作效率。
* 定义:执行中Bug的个数求和;解决方案为已解决;状态为已关闭;过滤已删除的Bug;过滤已删除的执行;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_fixed_bug_in_execution extends baseCalc
{
public $dataset = 'getExecutionBugs';
public $fieldList = array('t1.execution', 't1.status', 't1.resolution');
public $result = array();
public function calculate($data)
{
$execution = $data->execution;
if(!isset($this->result[$execution])) $this->result[$execution] = 0;
if($data->status == 'closed' and $data->resolution == 'fixed') $this->result[$execution] += 1;
}
public function getResult($options = null)
{
$records = $this->getRecords(array('execution', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,42 @@
<?php
/**
* 按执行统计的Bug转任务总数。
* Count of task in execution.
*
* 范围:execution
* 对象:task
* 目的:scale
* 度量名称:按执行统计的Bug转任务总数
* 单位:个
* 描述:按执行统计的Bug转任务总数是指整个执行当前存在的Bug转任务总量。
* 定义:执行中所有的Bug转任务个数求和;过滤已删除的任务;过滤已删除的执行;过滤已删除的项目;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author zhouxin <zhouxin@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_frombug_task_in_execution extends baseCalc
{
public $dataset = 'getTasks';
public $fieldList = array('t1.execution');
public $result = array();
public function calculate($row)
{
if($row->fromBug == 0) return;
if(!isset($this->result[$row->execution])) $this->result[$row->execution] = 0;
$this->result[$row->execution] ++;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('execution', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,46 @@
<?php
/**
* 按执行统计的已验收的研发需求数。
* Count of verified story in execution.
*
* 范围:execution
* 对象:story
* 目的:scale
* 度量名称:按执行统计的已验收的研发需求数
* 单位:个
* 描述:按执行统计的已验收的研发需求数是指执行中已验收的研发需求的数量。这个度量项可以反映执行的进展。已验收的研发需求数越多,说明执行团队在该时间段内取得了更多的研发成果。
* 定义:执行中所处阶段为已验收、交付中、已交付、已发布和关闭原因为已完成的研发需求个数求和;过滤已删除的研发需求;过滤已删除产品的研发需求;过滤已删除的执行;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_verified_story_in_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
$execution = $row->project;
$stage = $row->stage;
$closedReason = $row->closedReason;
if(!isset($this->result[$execution])) $this->result[$execution] = 0;
if(in_array($stage, array('verified', 'delivering', 'delivered', 'released'))) $this->result[$execution] += 1;
if($closedReason == 'done') $this->result[$execution] += 1;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('execution', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,43 @@
<?php
/**
* 按执行统计的已验收的研发需求规模数。
* Scale of verified story in execution.
*
* 范围:execution
* 对象:story
* 目的:scale
* 度量名称:按执行统计的已验收的研发需求规模数
* 单位:个
* 描述:按执行统计的已验收的研发需求规模数是指执行中已验收的研发需求的数量。这个度量项可以反映执行的进展。已验收的研发需求规模数越多,说明执行团队在该时间段内取得了更多的研发成果。
* 定义:执行中所处阶段为已验收、交付中、已交付、已发布和关闭原因为已完成的研发需求规模数求和;过滤父研发需求;过滤已删除的研发需求;过滤已删除产品的研发需求;过滤已删除的执行;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class scale_of_verified_story_in_execution extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = 0;
public function calculate($row)
{
if($row->isParent == '1') return false;
if(empty($row->estimate)) return null;
if(in_array($row->stage, array('verified', 'delivering', 'delivered', 'released'))) $this->result += $row->estimate;
if($row->closedReason == 'done') $this->result += $row->estimate;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按优先级统计的需求数。
* Count of story in pri
*
* 范围:pri
* 对象:story
* 目的:scale
* 度量名称:按优先级统计的需求数
* 单位:个
* 描述:按优先级统计的需求数
* 定义:按优先级统计的需求数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_story_in_pri_in_product extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->pri])) $this->result[$row->pri] = array();
$this->result[$row->pri][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $pri => $stories)
{
if(!is_array($stories))
{
unset($this->result[$pri]);
continue;
}
$this->result[$pri] = count($stories);
}
$records = $this->getRecords(array('pri', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,63 @@
<?php
/**
* 按产品和模块统计的研发需求数。
* Count of story in product and module.
*
* 范围:product
* 对象:story
* 目的:scale
* 度量名称:按产品和模块统计的研发需求数
* 单位:个
* 描述:按产品和模块统计的研发需求数。
* 定义:和模块统计的研发需求数。
*
* @copyright Copyright 2009-2053 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_story_in_product_and_module extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->product])) $this->result[$row->product] = array('name'=> $row->product, 'value' => 0, 'children' => array());
if(!isset($this->result[$row->product]['children'][$row->module])) $this->result[$row->product]['children'][$row->module] = array('name'=> $row->module, 'value' => 0, 'children' => array());
if($row->secondModule && !isset($this->result[$row->product]['children'][$row->module]['children'][$row->secondModule])) $this->result[$row->product]['children'][$row->module]['children'][$row->secondModule] = array('name'=> $row->secondModule, 'value' => 0);
$this->result[$row->product]['value'] ++;
if($row->module) $this->result[$row->product]['children'][$row->module]['value'] ++;
if($row->secondModule) $this->result[$row->product]['children'][$row->module]['children'][$row->secondModule]['value'] ++;
}
public function processRecords($options = array())
{
$records = array();
foreach($options as $row)
{
if(!empty($row['children']))
{
$row['children'] = array_values($this->processRecords($row['children']));
}
else
{
unset($row['children']);
}
$records[] = $row;
}
return $records;
}
public function getResult($options = array())
{
$records = $this->processRecords($this->result);
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按来源统计的需求数。
* Count of story in source
*
* 范围:source
* 对象:story
* 目的:scale
* 度量名称:按来源统计的需求数
* 单位:个
* 描述:按来源统计的需求数
* 定义:按来源统计的需求数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_story_in_source_in_product extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->source])) $this->result[$row->source] = array();
$this->result[$row->source][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $source => $stories)
{
if(!is_array($stories))
{
unset($this->result[$source]);
continue;
}
$this->result[$source] = count($stories);
}
$records = $this->getRecords(array('source', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按阶段统计的需求数。
* Count of story in stage
*
* 范围:stage
* 对象:story
* 目的:scale
* 度量名称:按阶段统计的需求数
* 单位:个
* 描述:按阶段统计的需求数
* 定义:按阶段统计的需求数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_story_in_stage_in_product extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->stage])) $this->result[$row->stage] = array();
$this->result[$row->stage][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $stage => $stories)
{
if(!is_array($stories))
{
unset($this->result[$stage]);
continue;
}
$this->result[$stage] = count($stories);
}
$records = $this->getRecords(array('stage', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按状态统计的需求数。
* Count of story in status
*
* 范围:status
* 对象:story
* 目的:scale
* 度量名称:按状态统计的需求数
* 单位:个
* 描述:按状态统计的需求数
* 定义:按状态统计的需求数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_story_in_status_in_product extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->status])) $this->result[$row->status] = array();
$this->result[$row->status][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $status => $stories)
{
if(!is_array($stories))
{
unset($this->result[$status]);
continue;
}
$this->result[$status] = count($stories);
}
$records = $this->getRecords(array('status', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,50 @@
<?php
/**
* 按类型统计的需求数。
* Count of story in type
*
* 范围:type
* 对象:story
* 目的:scale
* 度量名称:按类型统计的需求数
* 单位:个
* 描述:按类型统计的需求数
* 定义:按类型统计的需求数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_story_in_type_in_product extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->type])) $this->result[$row->type] = array();
$this->result[$row->type][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $type => $stories)
{
if(!is_array($stories))
{
unset($this->result[$type]);
continue;
}
$this->result[$type] = count($stories);
}
$records = $this->getRecords(array('type', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,48 @@
<?php
/**
* 按项目统计的延期的执行数。
* Count of doing execution in project.
*
* 范围:project
* 对象:execution
* 目的:scale
* 度量名称:按项目统计的延期的执行数
* 单位:个
* 描述:按项目统计的延期的执行数表示在项目中正在延期的执行项的数量,可以用来了解当前正在进行的任务数量,反映项目团队的工作进展。
* 定义:所有的执行个数求和;计划完成日期早于当前日期;过滤已删除的执行;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_delayed_execution_in_project extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
$project = $row->project;
$nowDate = helper::now();
$end = $row->end;
$year = $this->getYear($end);
if(!$year) return false;
$nextDate = date('Y-m-d', strtotime($end . ' +1 day'));
if(strtotime($nowDate) <= strtotime($nextDate)) return false;
if(!isset($this->result[$project])) $this->result[$project] = 0;
$this->result[$project] += 1;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('project', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,39 @@
<?php
/**
* 按系统统计的测试完毕研发需求数。
* Count of tested story.
*
* 范围:system
* 对象:story
* 目的:scale
* 度量名称:按系统统计的测试完毕研发需求数
* 单位:个
* 描述:按系统统计的测试完毕研发需求数反映了组织在特定时间段内已经完成的产品研发需求数量,用于评估评组织的估研发成果、产品创新和竞争力,并提供绩效评估。
* 定义:所有的研发需求个数求和;过滤已删除的研发需求;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_tested_story extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = 0;
public function calculate($row)
{
if(strpos(',tested,verified,rejected,delivering,delivered,released,closed', ",$row->stage,") !== false) $this->result ++;
}
public function getResult($options = array())
{
$records = array(array('value' => $this->result));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,42 @@
<?php
/**
* 按系统统计的已关闭研发需求规模数。
* Scale of closed story.
*
* 范围:system
* 对象:story
* 目的:scale
* 度量名称:按系统统计的已关闭研发需求规模数
* 单位:个
* 描述:按系统统计的已关闭研发需求规模数反映了组织在已关闭的研发需求上的规模总数,用于评估组织对于研发进展评估、质量控制、绩效评估和持续改进具有重要意义。
* 定义:所有的研发需求规模数求和;过滤父研发需求;过滤已删除的研发需求;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class scale_of_closed_story extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = 0;
public function calculate($row)
{
if($row->isParent == '1') return false;
if(empty($row->estimate)) return null;
if($row->status == 'closed') $this->result += $row->estimate;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,42 @@
<?php
/**
* 按系统统计的测试完毕研发需求规模数。
* Scale of finished story.
*
* 范围:system
* 对象:story
* 目的:scale
* 度量名称:按系统统计的测试完毕研发需求规模数
* 单位:个
* 描述:按系统统计的测试完毕研发需求规模数反映了组织在测试完毕的研发需求上的规模总数,用于评估组织对于研发进展评估、质量控制、绩效评估和持续改进具有重要意义。
* 定义:所有的研发需求规模数求和;过滤父研发需求;过滤已删除的研发需求;
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class scale_of_tested_story extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = 0;
public function calculate($row)
{
if($row->isParent == '1') return false;
if(empty($row->estimate)) return null;
if(strpos(',tested,verified,rejected,delivering,delivered,released,closed', ",$row->stage,") !== false) $this->result += $row->estimate;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,46 @@
<?php
/**
* 按系统统计的开发任务完成率。
* Rate of finished task.
*
* 范围:system
* 对象:task
* 目的:rate
* 度量名称:按系统统计的任务完成率
* 单位:%
* 描述:按系统统计的任务完成率是指已完成的任务占相对于任务数量的比例。
* 定义:按系统统计的已完成任务数;按系统统计的任务数;公式:已完成任务数÷任务数;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class rate_of_devel_finished_task extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array('finished' => 0, 'total' => 0);
public function calculate($row)
{
if($row->type != 'devel') return;
$this->result['total'] += 1;
if($row->status == 'done' || $row->closedReason == 'done') $this->result['finished'] += 1;
}
public function getResult($options = array())
{
$total = $this->result['total'];
$finished = $this->result['finished'];
$rate = $total == 0 ? 0 : round($finished / $total, 4);
$records = array(array('value' => $rate));
return $this->filterByOptions($records, $options);
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php
/**
* 按系统统计的任务完成率。
* Rate of finished task.
*
* 范围:system
* 对象:task
* 目的:rate
* 度量名称:按系统统计的任务完成率
* 单位:%
* 描述:按系统统计的任务完成率是指已完成的任务占相对于任务数量的比例。
* 定义:按系统统计的已完成任务数;按系统统计的任务数;公式:已完成任务数÷任务数;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class rate_of_finished_task extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array('finished' => 0, 'total' => 0);
public function calculate($row)
{
$this->result['total'] += 1;
if($row->status == 'done' || $row->closedReason == 'done') $this->result['finished'] += 1;
}
public function getResult($options = array())
{
$total = $this->result['total'];
$finished = $this->result['finished'];
$rate = $total == 0 ? 0 : round($finished / $total, 4);
$records = array(array('value' => $rate));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,47 @@
<?php
/**
* 按系统统计的任务进度。
* Rate of task process.
*
* 范围:system
* 对象:task
* 目的:rate
* 度量名称:按系统统计的任务进度
* 单位:%
* 描述:按系统统计的任务进度是指已消耗工时占相对于已消耗工时数+剩余工时数的比例。
* 定义:按系统统计的已消耗工时数;按系统统计的剩余工时数;公式:已消耗工时数÷(已消耗工时数+剩余工时数);
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class rate_of_hour_process_task extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array('consumed' => 0, 'left' => 0);
public function calculate($row)
{
if($row->isParent) return;
$this->result['consumed'] += $row->consumed;
if($row->status != 'closed' && $row->status != 'cancel') $this->result['left'] += $row->left;
}
public function getResult($options = array())
{
$consumed = $this->result['consumed'];
$left = $this->result['left'];
$rate = $consumed || $left ? round($consumed / ($consumed + $left), 4) : 0;
$records = array(array('value' => $rate));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,51 @@
<?php
/**
* 按任务类型统计的任务进度。
* Rate of task process by type.
*
* 范围:task
* 对象:task
* 目的:rate
* 度量名称:按任务类型统计的任务进度
* 单位:%
* 描述:按系统统计的任务进度是指已消耗工时占相对于已消耗工时数+剩余工时数的比例。
* 定义:按系统统计的已消耗工时数;按系统统计的剩余工时数;公式:已消耗工时数÷(已消耗工时数+剩余工时数);
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class rate_of_hour_process_task_in_type extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if($row->isParent) return;
if(!isset($this->result[$row->type])) $this->result[$row->type] = array('consumed' => 0, 'left' => 0, 'type' => $row->type, 'rate' => 0);
$this->result[$row->type]['consumed'] += $row->consumed;
$this->result[$row->type]['left'] += $row->left;
}
public function getResult($options = array())
{
foreach($this->result as $type => $result)
{
$consumed = $result['consumed'];
$left = $result['left'];
$rate = $consumed || $left ? round($consumed / ($consumed + $left), 4) : 0;
$this->result[$type]['rate'] = $rate;
}
return $this->filterByOptions($this->result, $options);
}
}
@@ -0,0 +1,46 @@
<?php
/**
* 按系统统计的测试任务完成率。
* Rate of finished task.
*
* 范围:system
* 对象:task
* 目的:rate
* 度量名称:按系统统计的任务完成率
* 单位:%
* 描述:按系统统计的任务完成率是指已完成的任务占相对于任务数量的比例。
* 定义:按系统统计的已完成任务数;按系统统计的任务数;公式:已完成任务数÷任务数;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class rate_of_test_finished_task extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array('finished' => 0, 'total' => 0);
public function calculate($row)
{
if($row->type != 'test') return;
$this->result['total'] += 1;
if($row->status == 'done' || $row->closedReason == 'done') $this->result['finished'] += 1;
}
public function getResult($options = array())
{
$total = $this->result['total'];
$finished = $this->result['finished'];
$rate = $total == 0 ? 0 : round($finished / $total, 4);
$records = array(array('value' => $rate));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,76 @@
<?php
/**
* 按系统统计的每日完成任务数。
* Count of delayed finished task which finished.
*
* 范围:task
* 对象:task
* 目的:scale
* 度量名称:按系统统计的每日完成任务数。
* 单位:个
* 描述:按系统统计的每日完成任务数。
* 定义:已完成的任务个数求和;过滤已删除的任务;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_delayed_finished_task extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public $dateCounts = array();
public $startDate = '';
public $endDate = '';
public function calculate($row)
{
if(!empty($row->executionStartDate) && empty($this->startDate)) $this->startDate = $row->executionStartDate;
if(!empty($row->executionEndDate) && empty($this->endDate)) $this->endDate = $row->executionEndDate;
if(empty($row->finishedDate)) return false;
$finishedDate = substr($row->finishedDate, 0, 10);
if(!isset($this->dateCounts[$finishedDate])) $this->dateCounts[$finishedDate] = 0;
$this->dateCounts[$finishedDate] ++;
}
public function getDatesBetween($startDate, $endDate)
{
$current = strtotime($startDate);
$end = strtotime($endDate);
$dates = [];
while($current <= $end)
{
$dates[date('Y-m-d', $current)] = 0;
$current += 86400;
}
return $dates;
}
public function getResult($options = array())
{
$dateList = $this->getDatesBetween($this->startDate, $this->endDate);
foreach($dateList as $date => $value)
{
if(isset($this->dateCounts[$date])) $value = $this->dateCounts[$date];
$this->result[$date] = $value;
}
$records = $this->getRecords(array('date', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,47 @@
<?php
/**
* 按模块统计的任务数。
* Count of task in module.
*
* 范围:module
* 对象:task
* 目的:scale
* 度量名称:按模块统计的任务数
* 单位:个
* 描述:按模块统计的任务数
* 定义:按模块统计的任务数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_task_in_module extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->module])) $this->result[$row->module] = array();
$this->result[$row->module][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $module => $tasks)
{
if(!is_array($tasks)) continue;
$this->result[$module] = count($tasks);
}
$records = $this->getRecords(array('module', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,47 @@
<?php
/**
* 按优先级统计的任务数。
* Count of task in pri.
*
* 范围:pri
* 对象:task
* 目的:scale
* 度量名称:按优先级统计的任务数
* 单位:个
* 描述:按优先级统计的任务数
* 定义:按优先级统计的任务数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_task_in_pri extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->pri])) $this->result[$row->pri] = array();
$this->result[$row->pri][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $pri => $tasks)
{
if(!is_array($tasks)) continue;
$this->result[$pri] = count($tasks);
}
$records = $this->getRecords(array('pri', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,49 @@
<?php
/**
* 按关闭原因统计的任务数。
* Count of task in closed reason.
*
* 范围:closedReason
* 对象:task
* 目的:scale
* 度量名称:按关闭原因统计的任务数
* 单位:个
* 描述:按关闭原因统计的任务数
* 定义:按关闭原因统计的任务数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_task_in_reason extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if($row->status != 'closed') return;
if(!isset($this->result[$row->closedReason])) $this->result[$row->closedReason] = array();
$this->result[$row->closedReason][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $closedReason => $tasks)
{
if(!is_array($tasks)) continue;
$this->result[$closedReason] = count($tasks);
}
$records = $this->getRecords(array('reason', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,47 @@
<?php
/**
* 按状态统计的任务数。
* Count of task in status.
*
* 范围:status
* 对象:task
* 目的:scale
* 度量名称:按状态统计的任务数
* 单位:个
* 描述:按状态统计的任务数
* 定义:按状态统计的任务数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_task_in_status extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->status])) $this->result[$row->status] = array();
$this->result[$row->status][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $status => $tasks)
{
if(!is_array($tasks)) continue;
$this->result[$status] = count($tasks);
}
$records = $this->getRecords(array('status', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,47 @@
<?php
/**
* 按类型统计的任务数。
* Count of task in type.
*
* 范围:type
* 对象:task
* 目的:scale
* 度量名称:按类型统计的任务数
* 单位:个
* 描述:按类型统计的任务数
* 定义:按类型统计的任务数
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_task_in_type extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->type])) $this->result[$row->type] = array();
$this->result[$row->type][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $type => $tasks)
{
if(!is_array($tasks)) continue;
$this->result[$type] = count($tasks);
}
$records = $this->getRecords(array('type', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,41 @@
<?php
/**
* 按任务类型和状态统计的任务进度。
* Rate of task process by type and status.
*
* 范围:task
* 对象:task
* 目的:rate
* 度量名称:按任务类型和状态统计的任务进度
* 单位:%
* 描述:按任务类型和状态统计的任务进度。
* 定义:按任务类型和状态统计的任务进度。
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_task_in_type_status extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->type])) $this->result[$row->type] = array();
if(!isset($this->result[$row->type][$row->status])) $this->result[$row->type][$row->status] = 0;
$this->result[$row->type][$row->status]++;
}
public function getResult($options = array())
{
return $this->filterByOptions($this->result, $options);
}
}
+45
View File
@@ -0,0 +1,45 @@
<?php
/**
* 按人员统计任务消耗工时数。
* Count of consumed task in user.
*
* 范围:user
* 对象:task
* 目的:scale
* 度量名称:按人员统计任务消耗工时数
* 单位:小时
* 描述:按人员统计任务消耗工时数表示每个人任务消耗工时数量之和。
* 定义:所有任务消耗工时数求和;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class consume_of_task_in_user extends baseCalc
{
public $dataset = 'getTaskEfforts';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
$account = $row->account;
$consumed = $row->consumed;
if(!isset($this->result[$account])) $this->result[$account] = 0;
$this->result[$account] += $consumed;
}
public function getResult($options = array())
{
foreach($this->result as $account => $consumed) $this->result[$account] = round($consumed, 4);
$records = $this->getRecords(array('user', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,53 @@
<?php
/**
* 按人员统计的创建Bug数。
* Count of created bug in user.
*
* 范围:user
* 对象:bug
* 目的:scale
* 度量名称:按人员统计的创建Bug数
* 单位:个
* 描述:按人员统计的创建Bug数是指每个人创建修复Bug总量。该度量项可以帮助我们了解每个人对已解决的Bug进行确认与关闭的速度和效率。
* 定义:截止当前时间;统计每个人创建Bug数的求和;过滤已删除的Bug;过滤已删除的产品;
* 度量库:
* 收集方式:realtime
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_created_bug_in_user extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->openedBy])) $this->result[$row->openedBy] = array();
$this->result[$row->openedBy][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $openedBy => $bugs)
{
if(!is_array($bugs))
{
unset($this->result[$openedBy]);
continue;
}
$this->result[$openedBy] = count($bugs);
}
$records = $this->getRecords(array('user', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,52 @@
<?php
/**
* 按人员统计的创建用例数。
* Count of created case in user.
*
* 范围:user
* 对象:case
* 目的:scale
* 度量名称:按人员统计的创建用例数
* 单位:个
* 描述:按人员统计的创建用例数是指每个人创建修复用例总量。该度量项可以帮助我们了解每个人对已解决的用例进行确认与关闭的速度和效率。
* 定义:截止当前时间;统计每个人创建用例数的求和;过滤已删除的用例;过滤已删除的产品;
* 度量库:
* 收集方式:realtime
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_created_case_in_user extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->openedBy])) $this->result[$row->openedBy] = array();
$this->result[$row->openedBy][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $openedBy => $cases)
{
if(!is_array($cases))
{
unset($this->result[$openedBy]);
continue;
}
$this->result[$openedBy] = count($cases);
}
$records = $this->getRecords(array('user', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,49 @@
<?php
/**
* 按人员统计的已完成任务数。
* Count of finished task in user.
*
* 范围:user
* 对象:task
* 目的:scale
* 度量名称:按人员统计的已完成任务数
* 单位:个
* 描述:按人员统计的已完成任务数表示每个人已完成的任务数量之和。
* 定义:所有任务个数求和;完成者为某人;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@chandao.com>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_finished_task_in_user extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if($row->status != 'done' && $row->closedReason != 'done') return false;
if(!isset($this->result[$row->finishedBy])) $this->result[$row->finishedBy] = array();
$this->result[$row->finishedBy][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $finishedBy => $tasks)
{
if(!is_array($tasks)) continue;
$this->result[$finishedBy] = count($tasks);
}
$records = $this->getRecords(array('user', 'value'));
return $this->filterByOptions($records, $options);
}
}
@@ -0,0 +1,53 @@
<?php
/**
* 按人员统计的解决Bug数。
* Count of resolved bug in user.
*
* 范围:user
* 对象:bug
* 目的:scale
* 度量名称:按人员统计的解决Bug数
* 单位:个
* 描述:按人员统计的解决Bug数是指每个人解决修复Bug总量。该度量项可以帮助我们了解每个人对已解决的Bug进行确认与关闭的速度和效率。
* 定义:截止当前时间;统计每个人解决Bug数的求和;过滤已删除的Bug;过滤已删除的产品;
* 度量库:
* 收集方式:realtime
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Zemei Wang <wangzemei@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_resolved_bug_in_user extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->resolvedBy])) $this->result[$row->resolvedBy] = array();
$this->result[$row->resolvedBy][$row->id] = $row->id;
}
public function getResult($options = array())
{
foreach($this->result as $resolvedBy => $bugs)
{
if(!is_array($bugs))
{
unset($this->result[$resolvedBy]);
continue;
}
$this->result[$resolvedBy] = count($bugs);
}
$records = $this->getRecords(array('user', 'value'));
return $this->filterByOptions($records, $options);
}
}
+40
View File
@@ -0,0 +1,40 @@
<?php
/**
* 按人员统计的创建的研发需求数。
* Count of reviewing story in user.
*
* 范围:user
* 对象:story
* 目的:scale
* 度量名称:按人员统计的创建的研发需求数
* 单位:个
* 描述:按人员统计的创建的研发需求数。
* 定义:所有研发需求个数求和;
*
* @copyright Copyright 2009-2025 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @author Yanyi Cao <caoyanyi@easycorp.ltd>
* @package
* @uses func
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @Link https://www.zentao.net
*/
class count_of_story_in_user extends baseCalc
{
public $dataset = '';
public $fieldList = array();
public $result = array();
public function calculate($row)
{
if(!isset($this->result[$row->openedBy])) $this->result[$row->openedBy] = 0;
$this->result[$row->openedBy] += 1;
}
public function getResult($options = array())
{
$records = $this->getRecords(array('user', 'value'));
return $this->filterByOptions($records, $options);
}
}
+22
View File
@@ -829,6 +829,28 @@ class metricModel extends model
return $records;
}
/**
* 根据度量项和数据计算度量项结果。
* Calculate metric result by metrics and data.
*
* @param array $metrics
* @param array $data
* @access public
* @return void
*/
public function getResultByCodeFromData($metrics, $data)
{
$results = array();
foreach($metrics as $metric)
{
$calculator = $this->getCalculator($metric->scope, $metric->purpose, $metric->code);
foreach($data as $row) $calculator->calculate($row);
$results[$metric->code] = $calculator->getResult();
}
return $results;
}
/**
* 获取度量项计算对象。
* Get metric calculator.
+33 -6
View File
@@ -16,13 +16,40 @@ title=getMetricByCode
timeout=0
cid=1
- 测试按产品统计的计划数第0条的value属性 @2
- 测试按产品统计年度关闭反馈数第0条的value属性 @4
- 测试按产品统计的计划数第1个结果
- 属性product @1
- 属性value @3
- 测试按产品统计的计划数第2个结果
- 属性product @3
- 属性value @3
- 测试按产品统计的计划数第3个结果
- 属性product @5
- 属性value @3
- 测试按产品统计的计划数第4个结果
- 属性product @7
- 属性value @2
- 测试按产品统计年度关闭反馈数第1个结果
- 属性product @1
- 属性value @4
- 测试按产品统计年度关闭反馈数第2个结果
- 属性product @3
- 属性value @4
- 测试按产品统计年度关闭反馈数第3个结果
- 属性product @5
- 属性value @4
- 测试按产品统计年度关闭反馈数第4个结果
- 属性product @7
*/
$options = array('product' => '7');
r($metric->getMetricByCode('count_of_productplan_in_product', $options)) && p('0:value') && e('2'); // 测试按产品统计的计划数
$result1 = $metric->getMetricByCode('count_of_productplan_in_product');
r($result1[0]) && p('product,value') && e('1,3'); // 测试按产品统计的计划数第1个结果
r($result1[1]) && p('product,value') && e('3,3'); // 测试按产品统计的计划数第2个结果
r($result1[2]) && p('product,value') && e('5,3'); // 测试按产品统计的计划数第3个结果
r($result1[3]) && p('product,value') && e('7,2'); // 测试按产品统计的计划数第4个结果
$options = array('product' => '9', 'year' => date('Y'));
r($metric->getMetricByCode('count_of_annual_closed_feedback_in_product', $options)) && p('0:value') && e('4'); // 测试按产品统计年度关闭反馈数
$result2 = $metric->getMetricByCode('count_of_annual_closed_feedback_in_product');
r($result2[0]) && p('product,value') && e('1,4'); // 测试按产品统计年度关闭反馈数第1个结果
r($result2[1]) && p('product,value') && e('3,4'); // 测试按产品统计年度关闭反馈数第2个结果
r($result2[2]) && p('product,value') && e('5,4'); // 测试按产品统计年度关闭反馈数第3个结果
r($result2[3]) && p('product,value') && e('7,4'); // 测试按产品统计年度关闭反馈数第4个结果
@@ -0,0 +1,36 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
zenData('project')->loadYaml('execution')->gen(2);
zenData('task')->loadYaml('task')->gen(50);
/**
title=测试 metricModel->getResultByCodeFromData();
timeout=0
cid=1
- 测试执行14下的任务数量是否正确;第0条的value属性 @6
- 测试执行15下的任务数量是否正确;第0条的value属性 @2
- 测试执行14下的完成的任务数量是否正确;第0条的value属性 @1
- 测试执行15下的完成的任务数量是否正确;第0条的value属性 @0
- 测试执行14下的完成率是否正确;第0条的value属性 @0.1667
*/
global $tester;
$tester->loadModel('metric');
$tasks1 = $tester->loadModel('task')->getExecutionTasks(14);
$tasks2 = $tester->task->getExecutionTasks(15);
$metrics = array(
(object)array('code' => 'count_of_task', 'scope' => 'system', 'purpose' => 'scale'),
(object)array('code' => 'count_of_finished_task', 'scope' => 'system', 'purpose' => 'scale'),
(object)array('code' => 'rate_of_finished_task', 'scope' => 'task', 'purpose' => 'rate'),
);
r($tester->metric->getResultByCodeFromData($metrics, $tasks1)['count_of_task']) && p('0:value') && e(6); // 测试执行14下的任务数量是否正确;
r($tester->metric->getResultByCodeFromData($metrics, $tasks2)['count_of_task']) && p('0:value') && e(2); // 测试执行15下的任务数量是否正确;
r($tester->metric->getResultByCodeFromData($metrics, $tasks1)['count_of_finished_task']) && p('0:value') && e(1); // 测试执行14下的完成的任务数量是否正确;
r($tester->metric->getResultByCodeFromData($metrics, $tasks2)['count_of_finished_task']) && p('0:value') && e(0); // 测试执行15下的完成的任务数量是否正确;
r($tester->metric->getResultByCodeFromData($metrics, $tasks1)['rate_of_finished_task']) && p('0:value') && e(0.1667); // 测试执行14下的完成率是否正确;
@@ -9,11 +9,14 @@ cid=0
- 测试查询项目1产品2阶段8父阶段信息 @执行1-1
- 测试查询项目1产品3阶段8父阶段信息 @无
- 测试查询项目4产品6阶段8父阶段信息 @执行2-1-1
- 测试查询项目10产品6阶段8父阶段信息 @无
- 测试查询项目20产品6阶段8父阶段信息 @无
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
su('admin');
zenData('product')->loadYaml('product')->gen(10);
zenData('project')->loadYaml('project')->gen(10);
zenData('projectproduct')->loadYaml('projectproduct')->gen(10);
@@ -21,6 +24,8 @@ global $tester;
$tester->loadModel('programplan');
$tester->programplan->app->user->admin = true;
r($tester->programplan->getParentStageList(1, 8, 2)[2]) && p() && e('执行1-1'); // 测试查询项目1产品2阶段8父阶段信息
r($tester->programplan->getParentStageList(1, 8, 3)[0]) && p() && e('无'); // 测试查询项目1产品3阶段8父阶段信息
r($tester->programplan->getParentStageList(4, 8, 6)[6]) && p() && e('执行2-1-1'); // 测试查询项目4产品6阶段8父阶段信息
r($tester->programplan->getParentStageList(1, 8, 2)[2]) && p() && e('执行1-1'); // 测试查询项目1产品2阶段8父阶段信息。
r($tester->programplan->getParentStageList(1, 8, 3)[0]) && p() && e('无'); // 测试查询项目1产品3阶段8父阶段信息。
r($tester->programplan->getParentStageList(4, 8, 6)[6]) && p() && e('执行2-1-1'); // 测试查询项目4产品6阶段8父阶段信息。
r($tester->programplan->getParentStageList(10, 8, 6)) && p('0') && e('无'); // 测试查询项目10产品父阶段信息。
r($tester->programplan->getParentStageList(20, 8, 6)) && p('0') && e('无'); // 测试查询项目20产品父阶段信息。
+9 -2
View File
@@ -40,8 +40,12 @@ $config->screen->chartConfig['radar'] = '{"category" : "Mores", "categoryN
$config->screen->chartConfig['line'] = '{"category" : "Lines", "categoryName" : "折线图", "chartFrame" : "echarts", "chartKey" : "VLineCommon", "conKey" : "VCLineCommon", "image" : "line.png", "key" : "LineCommon", "package" : "Charts", "title" : "折线图", "dataset" : {}}';
$config->screen->chartConfig['table'] = '{"category" : "Tables", "categoryName" : "列表", "chartFrame" : "common", "chartKey" : "VTableMergeCell", "conKey" : "VCTableMergeCell", "image" : "table_scrollboard.png", "key" : "TableMergeCell", "package" : "Tables", "title" : "透视表", "dataset" : {}, "tableInfo": {}}';
$config->screen->chartConfig['card'] = '{"category" : "Texts", "categoryName" : "文本", "chartFrame" : "common", "chartKey" : "VTextCommon", "conKey" : "VCTextCommon", "image" : "text_static.png", "key" : "TextCommon", "package" : "Informations", "title" : "文字", "dataset" : {}}';
$config->screen->chartConfig['text'] = '{"category" : "Texts", "categoryName" : "文本", "chartFrame" : "common", "chartKey" : "VTextCommon", "conKey" : "VCTextCommon", "image" : "text_static.png", "key" : "TextCommon", "package" : "Informations", "title" : "文字", "dataset" : {}}';
$config->screen->chartConfig['waterpolo'] = '{"category" : "Mores", "categoryName" : "更多", "chartFrame" : "common", "chartKey" : "VWaterPolo", "conKey" : "VCWaterPolo", "image" : "water_WaterPolo.png", "key" : "WaterPolo", "package" : "Charts", "title" : "水球图", "dataset" : {}}';
$config->screen->chartConfig['sunburst'] = '{"category" : "Mores", "categoryName" : "更多", "chartFrame" : "common", "chartKey" : "VSunBurst", "conKey" : "VCSunBurst", "image" : "pie.png", "key" : "SunBurst", "package" : "Charts", "title" : "旭日图", "dataset" : {}}';
$config->screen->chartConfig['box'] = '{"category" : "Mores", "categoryName" : "更多", "chartFrame" : "plotlys", "chartKey" : "VBox", "conKey" : "VCBox", "image" : "line.png", "key" : "Box", "package" : "Charts", "title" : "箱线图", "dataset" : {}}';
$config->screen->chartConfig['metric'] = '{"category" : "Metrics", "categoryName" : "度量项", "chartFrame" : "common", "chartKey" : "VMetrics", "conKey" : "VCMetrics", "image" : "bar_x.png", "key" : "Metrics", "package" : "Metrics", "title" : "度量项", "dataset" : {}}';
$config->screen->chartConfig['help'] = '{"category" : "Informations", "categoryName" : "信息", "chartFrame" : "common", "chartKey" : "VHint", "conKey" : "VCHint", "image" : "./static/png/hint.png", "key" : "Hint", "package" : "Decorates", "title" : "提示"}';
$config->screen->chartOption['cluBarX'] = '{"legend":{"show":true,"top":40,"textStyle":{"color":"#B9B8CE"},"left":"center"},"xAxis":{"show":true,"name":"","nameGap":15,"nameTextStyle":{"color":"#B9B8CE","fontSize":12},"inverse":false,"axisLabel":{"show":true,"fontSize":12,"color":"#B9B8CE","rotate":0},"position":"bottom","axisLine":{"show":true,"lineStyle":{"color":"#B9B8CE","width":1},"onZero":true},"axisTick":{"show":true,"length":5},"splitLine":{"show":false,"lineStyle":{"color":"#484753","width":1,"type":"solid"}},"type":"category"},"yAxis":{"show":true,"name":"","nameGap":15,"nameTextStyle":{"color":"#B9B8CE","fontSize":12},"inverse":false,"axisLabel":{"show":true,"fontSize":12,"color":"#B9B8CE","rotate":0},"position":"left","axisLine":{"show":true,"lineStyle":{"color":"#B9B8CE","width":1},"onZero":true},"axisTick":{"show":true,"length":5},"splitLine":{"show":true,"lineStyle":{"color":"#484753","width":1,"type":"solid"}},"type":"value"},"grid":{"show":false,"left":"10%","top":90,"right":"10%","bottom":"60"},"title":{"text":"","show":true,"textStyle":{"color":"#BFBFBF","fontSize":18},"subtextStyle":{"color":"#A2A2A2","fontSize":14},"top":10,"x":"center"},"tooltip":{"show":true,"trigger":"axis","axisPointer":{"show":true,"type":"shadow"}},"dataset":{},"series":[{"type":"bar","barWidth":15,"label":{"show":true,"position":"top","color":"#fff","fontSize":12},"itemStyle":{"color":null,"borderRadius":2}}],"backgroundColor":"rgba(0,0,0,0)"}';
$config->screen->chartOption['cluBarY'] = '{"legend":{"show":true,"top":40,"textStyle":{"color":"#B9B8CE"},"left":"center"},"xAxis":{"show":true,"name":"","nameGap":15,"nameTextStyle":{"color":"#B9B8CE","fontSize":12},"inverse":false,"axisLabel":{"show":true,"fontSize":12,"color":"#B9B8CE","rotate":0},"position":"bottom","axisLine":{"show":true,"lineStyle":{"color":"#B9B8CE","width":1},"onZero":true},"axisTick":{"show":true,"length":5},"splitLine":{"show":false,"lineStyle":{"color":"#484753","width":1,"type":"solid"}},"type":"value"},"yAxis":{"show":true,"name":"","nameGap":15,"nameTextStyle":{"color":"#B9B8CE","fontSize":12},"inverse":false,"axisLabel":{"show":true,"fontSize":12,"color":"#B9B8CE","rotate":0},"position":"left","axisLine":{"show":true,"lineStyle":{"color":"#B9B8CE","width":1},"onZero":true},"axisTick":{"show":true,"length":5},"splitLine":{"show":true,"lineStyle":{"color":"#484753","width":1,"type":"solid"}},"type":"category"},"grid":{"show":false,"left":"10%","top":70,"right":"10%","bottom":"60"},"title":{"text":"","show":true,"textStyle":{"color":"#BFBFBF","fontSize":18},"subtextStyle":{"color":"#A2A2A2","fontSize":14},"top":10,"x":"center"},"tooltip":{"show":true,"trigger":"axis","axisPointer":{"show":true,"type":"shadow"}},"dataset":{},"series":[{"type":"bar","barWidth":null,"label":{"show":true,"position":"right","color":"#fff","fontSize":12},"itemStyle":{"color":null,"borderRadius":0}}],"backgroundColor":"rgba(0,0,0,0)"}';
@@ -51,8 +55,11 @@ $config->screen->chartOption['pie'] = '{"legend":{"show":true,"top":30,"
$config->screen->chartOption['radar'] = '{"legend":{"show":true,"top":40,"textStyle":{"color":"#B9B8CE"},"data":[],"left":"center"},"title":{"text":"\u6298\u7ebf\u56fe","show":true,"textStyle":{"color":"#BFBFBF","fontSize":18},"subtextStyle":{"color":"#A2A2A2","fontSize":14},"top":10,"x":"center"},"tooltip":{"show":true},"grid":{"top":90},"dataset":{},"radar":{"shape":"polygon","radius":["0%","60%"],"center":["50%","55%"],"splitArea":{"show":true},"splitLine":{"show":true},"axisName":{"show":true,"color":"#eee","fontSize":12},"axisLine":{"show":true},"axisTick":{"show":true},"indicator":[]},"series":[{"name":"radar","type":"radar","areaStyle":{"opacity":0.1},"data":[]}],"backgroundColor":"rgba(0,0,0,0)"}';
$config->screen->chartOption['line'] = '{"legend":{"show":true,"top":40,"textStyle":{"color":"#B9B8CE"},"left":"center"},"xAxis":{"show":true,"name":"","nameGap":15,"nameTextStyle":{"color":"#B9B8CE","fontSize":12},"inverse":false,"axisLabel":{"show":true,"fontSize":12,"color":"#B9B8CE","rotate":0},"position":"bottom","axisLine":{"show":true,"lineStyle":{"color":"#B9B8CE","width":1},"onZero":true},"axisTick":{"show":true,"length":5},"splitLine":{"show":false,"lineStyle":{"color":"#484753","width":1,"type":"solid"}},"type":"category"},"yAxis":{"show":true,"name":"","nameGap":15,"nameTextStyle":{"color":"#B9B8CE","fontSize":12},"inverse":false,"axisLabel":{"show":true,"fontSize":12,"color":"#B9B8CE","rotate":0},"position":"left","axisLine":{"show":true,"lineStyle":{"color":"#B9B8CE","width":1},"onZero":true},"axisTick":{"show":true,"length":5},"splitLine":{"show":true,"lineStyle":{"color":"#484753","width":1,"type":"solid"}},"type":"value"},"grid":{"show":false,"left":"10%","top":90,"right":"10%","bottom":"60"},"title":{"text":"","show":true,"textStyle":{"color":"#BFBFBF","fontSize":18},"subtextStyle":{"color":"#A2A2A2","fontSize":14},"top":10,"x":"center"},"tooltip":{"show":true,"trigger":"axis","axisPointer":{"type":"line"}},"dataset":{},"series":[{"type":"line","label":{"show":true,"position":"top","color":"#fff","fontSize":12},"symbolSize":5,"itemStyle":{"color":null,"borderRadius":0},"lineStyle":{"type":"solid","width":3,"color":null}},{"type":"line","label":{"show":true,"position":"top","color":"#fff","fontSize":12},"symbolSize":5,"itemStyle":{"color":null,"borderRadius":0},"lineStyle":{"type":"solid","width":3,"color":null}}],"backgroundColor":"rgba(0,0,0,0)"}';
$config->screen->chartOption['table'] = '{}';
$config->screen->chartOption['waterpolo'] = '{}';
$config->screen->chartOption['text'] = '{"fontSize":20,"fontColor":"#fff","textAlign":"center","fontWeight":"normal","borderWidth":0,"borderColor":"#fff","borderRadius":5}';
$config->screen->chartOption['waterpolo'] = '{"type":"nomal","series":[{"type":"liquidFill","radius":"90%","roseType":false}],"backgroundColor":"rgba(0,0,0,0)"}';
$config->screen->chartOption['sunburst'] = '{"series":{"type":"sunburst","data": [], "radius": [0, "90%"], "label": {"rotate": "radial"}}}';
$config->screen->chartOption['box'] = '{"data": [], "layout": {"title": {"text": ""}}, "config": {}}';
$config->screen->chartOption['help'] = '{"text": "", "icon": "", "textSize": 30, "textColor": "#ffffff", "textWeight": "bold", "placement": "right-bottom", "distance": 8, "hint": "提示文本", "width": 0, "height": 0, "paddingX": 16, "paddingY": 8, "borderWidth": 1, "borderStyle": "solid", "borderColor": "#1a77a5", "borderRadius": 6, "color": "#ffffff", "textAlign": "left", "fontWeight": "normal", "backgroundColor": "rgba(89, 196, 230, .2)", "fontSize": 24}';
$config->screen->fieldConfig = new stdclass();
$config->screen->fieldConfig->bug = new stdclass();
$config->screen->fieldConfig->execution = new stdclass();
+12 -1
View File
@@ -147,6 +147,17 @@ class screen extends control
$this->view->account = $account;
$this->display();
}
/**
* 静态数据大屏(旧页面)。
* Static data screen (old page).
*
* @access public
* @return void
*/
public function staticDataOld()
{
$this->display();
}
public function ajaxGetScreenScheme(int $screenID, int $year = 0, int $month = 0, int $dept = 0, string $account = '')
{
@@ -183,7 +194,7 @@ class screen extends control
$this->screen->filter->month = $month;
$this->screen->filter->dept = $dept;
$this->screen->filter->account = $account;
$this->screen->setSelectFilter($sourceID, $selectFilter);
$this->filter->charts = $this->screenZen->setSelectFilter($sourceID, $selectFilter);
$type = $this->screen->getChartType($type);
+44
View File
@@ -0,0 +1,44 @@
location.hash = '#/chart/preview/1';
window.location.replace(window.location.href.toString().replace(window.location.hash, '')+'#/chart/preview/1');
$('link[href^="/theme/zui/css"]').remove();
$('link[href^="/theme/default/style.css"]').remove();
function setStaticData(staticData, options)
{
staticData = JSON.parse(staticData);
let radio = 1;
if(options.width)
{
const originalWidth = staticData.editCanvasConfig.width;
staticData.editCanvasConfig.width = options.width;
radio = options.width / originalWidth;
}
staticData.componentList = staticData.componentList.map(component => {
component.attr.w = component.attr.w * radio;
component.attr.h = component.attr.h * radio;
component.attr.x = component.attr.x * radio;
component.attr.y = component.attr.y * radio;
if(component.option?.paddingX)
{
component.option.paddingX = component.option.paddingX * radio;
}
if(component.option?.paddingY)
{
component.option.paddingY = component.option.paddingY * radio;
}
return component;
});
window.staticData = staticData;
let script = document.createElement('script');
script.type = 'module';
script.crossorigin = true;
script.src = webRoot + 'static/js/index.js';
document.head.appendChild(script);
}
+334 -79
View File
@@ -100,6 +100,24 @@ class screenModel extends model
return $screen;
}
/**
* 添加组件列表。
* Add component list.
*
* @param object $scheme
* @param array $componentList
* @access public
* @return object
*/
public function addComponentList(object $scheme, array $componentList): object
{
if(is_string($scheme)) $scheme = json_decode($scheme);
$scheme->componentList = $componentList;
return $scheme;
}
/**
* 构建大屏图表数据。
* Generate chartData of screen.
@@ -319,6 +337,130 @@ class screenModel extends model
return $component;
}
/**
* 通过路径设置值。
* Set value by path.
*
* @param object $option
* @param string $path
* @param string $value
* @access public
* @return void
*/
public function setValueByPath(object &$option, string $path, mixed $value): void
{
$keys = explode('.', $path);
$keyCount = count($keys);
$current = &$option;
foreach ($keys as $index => $key)
{
$isEnd = ($index + 1) >= $keyCount;
$nextKey = $isEnd ? null : $keys[$index + 1];
$isArray = is_numeric($key);
$nextIsArray = is_numeric($nextKey);
if($isArray && !isset($current[$key])) $current[$key] = $nextIsArray ? array() : new stdclass();
if(!$isArray && !isset($current->$key)) $current->$key = $nextIsArray ? array() : new stdclass();
if (is_array($current)) {
$current = &$current[$key];
} else {
$current = &$current->$key;
}
}
$current = $value;
}
/**
* 通过静态数据生成组件。
* Generate component.
*
* @param string $type
* @param string $title
* @param mixed $data
* @param array $attr
* @param array $options
* @access public
* @return object
*/
public function genComponentFromData(string $type, string $title, mixed $data, array $attr = array(), array $options = array()): object
{
$component = new stdclass();
$component->title = $title;
$component->type = $type;
$component->chartConfig = json_decode(zget($this->config->screen->chartConfig, $type));
$component->key = $component->chartConfig->key;
$component->attr = array('w' => 450, 'h' => 300, 'x' => 0, 'y' => 0, 'offsetX' => 0, 'offsetY' => 0, 'zIndex' => -1);
$component->attr = array_merge($component->attr, $attr);
$component->option = json_decode(zget($this->config->screen->chartOption, $type));
$component->option->dataset = new stdclass();
foreach($options as $keys => $value) $this->setValueByPath($component->option, $keys, $value);
$component->chartConfig->title = $title;
switch($type)
{
case 'line':
case 'cluBarY':
case 'stackedBarY':
case 'cluBarX':
case 'stackedBar':
case 'bar':
case 'pie':
list($dimensions, $sourceData) = $data;
return $this->prepareChartDataset($component, $dimensions, $sourceData);
case 'box':
return $this->prepareBoxDataset($component, $data);
case 'table':
list($headers, $align, $colspan, $dataset, $drills, $rowspans) = $data;
$formattedDataset = array();
foreach($dataset as $row)
{
$row = array_values($row);
$formattedDataset[] = array_map('strval', $row);
}
$skipCellList = array();
foreach($rowspans as $i => $rowspan)
{
foreach($rowspan as $j => $rowspanValue)
{
if(in_array(array($i, $j), $skipCellList)) continue;
for($k = 1; $k < $rowspanValue; $k ++)
{
unset($formattedDataset[$i + $k][$j]);
$skipCellList[] = array($i + $k, $j);
}
}
}
return $this->prepareTableDataset($component, $headers, $align, $colspan, $rowspans, $formattedDataset, $drills);
case 'radar':
list($radarIndicator, $seriesData) = $data;
return $this->prepareRadarDataset($component, $radarIndicator, $seriesData);
case 'card':
return $this->prepareCardDataset($component, $data);
case 'waterpolo':
return $this->prepareWaterPoloDataset($component, $data);
case 'sunburst':
return $this->prepareSunburstDataset($component, $data);
case 'group':
return $this->prepareGroupDataset($component, $data);
case 'text':
return $this->prepareTextDataset($component, $data);
case 'help':
return $this->setComponentDefaults($component);
default:
return $component;
}
}
/**
* Update piovt or chart component chartConfig filters.
*
@@ -757,6 +899,161 @@ class screenModel extends model
return $component;
}
/**
* 准备图表数据集。
* Prepare chart dataset.
*
* @param object $component
* @param array $dimensions
* @param array $sourceData
* @access public
* @return object
*/
public function prepareChartDataset(object $component, array $dimensions, array $sourceData): object
{
$component->option->dataset->dimensions = $dimensions;
$component->option->dataset->source = array_values($sourceData);
return $this->setComponentDefaults($component);
}
/**
* 准备箱线图数据集。
* Prepare box dataset.
*
* @param object $component
* @param array $data
* @param object $layout
* @param object $config
* @access public
* @return object
*/
public function prepareBoxDataset(object $component, array $data): object
{
$component->option->data = $data;
return $this->setComponentDefaults($component);
}
/**
* 准备组合数据集。
* Prepare group dataset.
*
* @param object $component
* @param array $componentList
* @access public
* @return object
*/
public function prepareGroupDataset(object $component, array $componentList): object
{
$component->isGroup = true;
$component->groupList = $componentList;
return $this->setComponentDefaults($component);
}
/**
* 准备雷达图数据集。
* Prepare radar chart dataset.
*
* @param object $component
* @param array $radarIndicator
* @param array $seriesData
* @access public
* @return object
*/
public function prepareRadarDataset(object $component, array $radarIndicator, array $seriesData): object
{
$component->option->dataset->radarIndicator = $radarIndicator;
$component->option->dataset->seriesData = $seriesData;
return $this->setComponentDefaults($component);
}
/**
* 准备文本数据集。
* Prepare text dataset.
*
* @param object $component
* @param string $text
* @access public
* @return object
*/
public function prepareTextDataset(object $component, string $text): object
{
$component->option->dataset = $text;
return $this->setComponentDefaults($component);
}
/**
* 准备表格数据集。
* Prepare table dataset.
*
* @param object $component
* @param array $headers
* @param array $align
* @param array $colspan
* @param array $rowspan
* @param array $dataset
* @param array $drills
* @access public
* @return object
*/
public function prepareTableDataset(object $component, array $headers, array $align, array $colspan, array $rowspan, array $dataset, array $drills): object
{
if(!isset($component->chartConfig->tableInfo)) $component->chartConfig->tableInfo = new stdclass();
$component->option->header = $headers;
$component->option->align = $align;
$component->option->columnWidth = array();
$component->option->rowspan = $rowspan;
$component->option->colspan = $colspan;
$component->option->dataset = $dataset;
$component->option->drills = $drills;
return $this->setComponentDefaults($component);
}
/**
* 准备卡片数据集。
* Prepare card dataset.
*
* @param object $component
* @param string $value
* @access public
* @return object
*/
public function prepareCardDataset(object $component, string $value): object
{
$component->option->dataset = (string)$value;
return $this->setComponentDefaults($component);
}
/**
* 准备水球图数据集。
* Prepare waterpolo dataset.
*
* @param object $component
* @param string $value
* @access public
* @return object
*/
public function prepareWaterPoloDataset(object $component, float $value): object
{
$component->option->dataset = $value;
return $this->setComponentDefaults($component);
}
/**
* 准备旭日图数据集。
* Prepare sunburst dataset.
*
* @param object $component
* @param array $data
* @access public
* @return object
*/
public function prepareSunburstDataset(object $component, array $data): object
{
$component->option->series->data = $data;
return $this->setComponentDefaults($component);
}
/**
* Get bar chart option.
*
@@ -767,6 +1064,8 @@ class screenModel extends model
*/
public function getBarChartOption($component, $chart, $filters = '')
{
$dimensions = array();
$sourceData = array();
if($chart->sql)
{
$settings = json_decode($chart->settings, true);
@@ -778,7 +1077,6 @@ class screenModel extends model
$fields = json_decode($chart->fields, true);
$dimensions = array($settings['xaxis'][0]['field']);
$sourceData = array();
$clientLang = $this->app->getClientLang();
$xLabelValues = $this->processXLabel($xLabels, $fields[$group]['type'], $fields[$group]['object'], $fields[$group]['field']);
@@ -801,13 +1099,9 @@ class screenModel extends model
$sourceData[$valueField]->{$field} = $value;
}
}
$component->option->dataset->dimensions = $dimensions;
$component->option->dataset->source = array_values($sourceData);
}
$component = $this->setComponentDefaults($component);
return $component;
return $this->prepareChartDataset($component, $dimensions, $sourceData);
}
/**
@@ -820,6 +1114,8 @@ class screenModel extends model
*/
public function getLineChartOption($component, $chart, $filters = '')
{
$dimensions = array();
$sourceData = array();
if($chart->sql)
{
$settings = json_decode($chart->settings, true);
@@ -830,7 +1126,6 @@ class screenModel extends model
$fields = json_decode($chart->fields, true);
$dimensions = array($settings['xaxis'][0]['field']);
$sourceData = array();
$clientLang = $this->app->getClientLang();
$xLabelValues = $this->processXLabel($xLabels, $fields[$group]['type'], $fields[$group]['object'], $fields[$group]['field']);
@@ -862,12 +1157,9 @@ class screenModel extends model
if(empty($lineData->{$dimension})) $lineData->{$dimension} = 0;
}
}
$component->option->dataset->dimensions = $dimensions;
$component->option->dataset->source = array_values($sourceData);
}
return $this->setComponentDefaults($component);
return $this->prepareChartDataset($component, $dimensions, $sourceData);
}
/**
@@ -880,6 +1172,8 @@ class screenModel extends model
*/
public function getPieChartOption($component, $chart, $filters = '')
{
$dimensions = array();
$sourceData = array();
if($chart->sql)
{
$settings = json_decode($chart->settings, true);
@@ -906,12 +1200,9 @@ class screenModel extends model
}
if(empty($sourceData)) $dimensions = array();
$component->option->dataset->dimensions = $dimensions;
$component->option->dataset->source = array_values($sourceData);
}
return $this->setComponentDefaults($component);
return $this->prepareChartDataset($component, $dimensions, $sourceData);
}
/**
@@ -924,8 +1215,10 @@ class screenModel extends model
*/
public function getRadarChartOption($component, $chart, $filters = '')
{
$indicator = array();
$seriesData = array();
$indicator = array();
$seriesData = array();
$radarIndicator = array();
$seriesData = array();
if($chart->sql)
{
$settings = json_decode($chart->settings, true);
@@ -934,12 +1227,10 @@ class screenModel extends model
list($group, $metrics, $aggs, $xLabels, $yStats) = $this->bi->getMultiData($settings, $chart->sql, $filters, $chart->driver);
$fields = json_decode($chart->fields, true);
$radarIndicator = array();
$seriesData = array();
$max = 0;
$clientLang = $this->app->getClientLang();
$xLabelValues = $this->processXLabel($xLabels, $fields[$group]['type'], $fields[$group]['object'], $fields[$group]['field']);
$fields = json_decode($chart->fields, true);
$max = 0;
$clientLang = $this->app->getClientLang();
$xLabelValues = $this->processXLabel($xLabels, $fields[$group]['type'], $fields[$group]['object'], $fields[$group]['field']);
foreach($yStats as $index => $dataList)
{
@@ -971,14 +1262,11 @@ class screenModel extends model
$radarIndicator[] = $indicator;;
}
}
$component->option->dataset->radarIndicator = $radarIndicator;
$component->option->dataset->seriesData = $seriesData;
}
return $this->setComponentDefaults($component);
return $this->prepareRadarDataset($component, $radarIndicator, $seriesData);
}
/**
* Get table chart option.
*
@@ -989,6 +1277,13 @@ class screenModel extends model
*/
public function getTableChartOption($component, $chart, $filters = array())
{
$align = array();
$headers = array();
$colspans = array();
$dataset = array();
$drills = array();
$config = array();
if($chart->sql)
{
$chart->settings = json_decode($chart->settings, true);
@@ -1014,16 +1309,14 @@ class screenModel extends model
list($options, $config) = $this->loadModel('pivot')->genSheet($fields, $settings, $chart->sql, $filters, $langs, $chart->driver);
}
$colspan = array();
$showColPosition = $this->pivot->getShowColPosition($options);
$isShowLastRow = $this->pivot->isShowLastRow($showColPosition);
if($isShowLastRow and !empty($options->array))
{
$count = count($options->array);
$colspan[$count - 1][0] = count($options->groups);
$colspans[$count - 1][0] = count($options->groups);
}
$dataset = array();
foreach($options->array as $data)
{
$data = array_values($data);
@@ -1044,8 +1337,6 @@ class screenModel extends model
}
}
$align = array();
$headers = array();
$groupCount = 0;
$drillConfigs = array();
foreach($options->cols as $cols)
@@ -1078,7 +1369,6 @@ class screenModel extends model
$count ++;
}
$drills = array();
$groupFields = array_fill(0, $groupCount, 'groupCol');
foreach($options->drills as $drill)
{
@@ -1093,18 +1383,9 @@ class screenModel extends model
$drillRow = array_merge($groupFields, $drillRow);
$drills[] = $drillRow;
}
if(!isset($component->chartConfig->tableInfo)) $component->chartConfig->tableInfo = new stdclass();
$component->option->header = $headers;
$component->option->align = $align;
$component->option->columnWidth = array();
$component->option->rowspan = $config;
$component->option->colspan = $colspan;
$component->option->dataset = $dataset;
$component->option->drills = $drills;
}
return $this->setComponentDefaults($component);
return $this->prepareTableDataset($component, $headers, $align, $colspans, $config, $dataset, $drills);
}
/**
@@ -1613,25 +1894,6 @@ class screenModel extends model
}
}
/**
* Set select filter.
*
* @param string $sourceID
* @param array $filters
* @access public
* @return void
*/
public function setSelectFilter($sourceID, $filters)
{
if(empty($filters)) return;
foreach($filters as $filter)
{
if(!isset($this->filter->charts[$sourceID])) $this->filter->charts[$sourceID] = array();
$this->filter->charts[$sourceID][$filter['type']] = $filter['field'];
}
}
/**
* Set SQL filter
*
@@ -1691,11 +1953,8 @@ class screenModel extends model
*/
public function buildCardChart($component, $chart)
{
if(!$chart->settings)
{
$component->option->dataset = '?';
}
else
$value = '?';
if($chart->settings)
{
$value = 0;
@@ -1735,10 +1994,9 @@ class screenModel extends model
$value = '?';
}
}
$component->option->dataset = (string)$value;
}
return $this->setComponentDefaults($component);
return $this->prepareCardDataset($component, $value);
}
/**
@@ -2110,24 +2368,21 @@ class screenModel extends model
*/
public function getWaterPoloOption($component, $chart, $filters)
{
$value = 0;
if(!$chart->settings)
{
$component->request = json_decode('{"requestDataType":0,"requestHttpType":"get","requestUrl":"","requestIntervalUnit":"second","requestContentType":0,"requestParamsBodyType":"none","requestSQLContent":{"sql":"select * from where"},"requestParams":{"Body":{"form-data":{},"x-www-form-urlencoded":{},"json":"","xml":""},"Header":{},"Params":{}}}');
$component->events = json_decode('{"baseEvent":{},"advancedEvents":{}}');
$component->key = "PieCircle";
$component->chartConfig = json_decode('{"key":"WaterPolo","chartKey":"VWaterPolo","conKey":"VCWaterPolo","title":"水球图","category":"Mores","categoryName":"更多","package":"Charts","chartFrame":"common","image":"water_WaterPolo.png"}');
$component->option = json_decode('{"type":"nomal","series":[{"type":"liquidFill","radius":"90%","roseType":false}],"backgroundColor":"rgba(0,0,0,0)"}');
return $this->setComponentDefaults($component);
$component->chartConfig = json_decode($this->config->screen->chartConfig['WaterPolo']);
$component->option = json_decode($this->config->screen->chartOption['WaterPolo']);
$component->key = $component->chartConfig->key;
}
else
{
$setting = json_decode($chart->settings, true)[0];
$options = $this->bi->genWaterPolo(json_decode($chart->fields, true), $setting, $chart->sql, $filters, $chart->driver);
$component->option->dataset = $options['series'][0]['data'][0];
return $this->setComponentDefaults($component);
$value = $options['series'][0]['data'][0];
}
return $this->prepareWaterPoloDataset($component, $value);
}
/**
@@ -434,6 +434,20 @@ class screenTest
return $this->objectModel->filter;
}
/**
* Test set value by path.
*
* @param object $option
* @param string $path
* @param string $value
* @access public
* @return void
*/
public function setValueByPathTest(object &$option, string $path, mixed $value): void
{
$this->objectModel->setValueByPath($option, $path, $value);
}
/**
* 初始化过滤条件。
* Initialize filter conditions.
@@ -0,0 +1,65 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->addComponentList();
timeout=0
cid=1
- 测试componentList属性为空的情况下,生成的默认值是否正确;第editCanvasConfig条的blendMode属性 @normal
- 测试传入componentList属性的情况下,生成的值是否正确;第0条的type属性 @text
- 测试传入componentList属性的情况下,生成的值是否正确;第1条的type属性 @text
- 测试传入componentList属性的情况下,生成的值是否正确;第2条的type属性 @waterpolo
- 测试传入componentList属性的情况下,生成的值是否正确;第3条的type属性 @table
*/
global $app;
$screen = new screenTest();
$scheme = file_get_contents($app->moduleRoot . 'screen/json/screen.json');
$scheme = json_decode($scheme);
$attr = array('w' => 900, 'h' => 300, 'x' => 20, 'y' => 100);
$waterOptions = array(
'title.show' => false,
'series.0.outline.show' => false,
'series.0.label.normal.textStyle.fontSize' => 13,
'series.0.label.normal.textStyle.fontWeight' => 'normal',
'series.0.label.normal.textStyle.round' => 2,
'series.0.color.0.type' => 'linear',
);
$headers = array(array(
array('field' => 'name', 'name' => 'name', 'label' => 'Name'),
array('field' => 'age', 'name' => 'age', 'label' => 'Age'),
array('field' => 'gender', 'name' => 'gender', 'label' => 'Gender'),
));
$tableDataSet = array(
array('tester1', 25, 'male'),
array('tester2', 30, 'female'),
array('tester3', 35, 'male'),
array('tester4', 40, 'female'),
);
$tableData = array($headers, array(), array(), $tableDataSet, array(), array());
$tableOptions = array(
'colNum' => 4,
'rowNum' => 4,
'headerBGC' => '#fcfdfe',
'bodyBGC' => '#fff',
'borderBGC' => '#e6ecf8',
'fontColor' => '#000',
'rowHeight' => 36
);
$components = array();
$components[] = $screen->genComponentFromData('text', 'Title1', 'Title1', $attr);
$components[] = $screen->genComponentFromData('text', '', '', $attr);
$components[] = $screen->genComponentFromData('waterpolo', 'Waterpolo1', 0.2, $attr, $waterOptions);
$components[] = $screen->genComponentFromData('table', 'Table1', $tableData, $attr, $tableOptions);
r($screen->addComponentList($scheme, array())) && p('editCanvasConfig:blendMode') && e('normal'); // 测试componentList属性为空的情况下,生成的默认值是否正确;
r($screen->addComponentList($scheme, $components)->componentList) && p('0:type') && e('text'); // 测试传入componentList属性的情况下,生成的值是否正确;
r($screen->addComponentList($scheme, $components)->componentList) && p('1:type') && e('text'); // 测试传入componentList属性的情况下,生成的值是否正确;
r($screen->addComponentList($scheme, $components)->componentList) && p('2:type') && e('waterpolo'); // 测试传入componentList属性的情况下,生成的值是否正确;
r($screen->addComponentList($scheme, $components)->componentList) && p('3:type') && e('table'); // 测试传入componentList属性的情况下,生成的值是否正确;
+10 -6
View File
@@ -14,9 +14,11 @@ title=测试 screenModel->getchartoption();
timeout=0
cid=1
- 测试type为card以及统计方式类型为value的图表是否显示正确,目前不存在统计方式为value的图表。 @1
- 测试type为card以及统计方式类型为count的图表是否显示正确,目前不存在统计方式为count的图表。 @1
- 测试type为card以及统计方式类型为sum的图表是否显示正确,生成的数据项数量是否正确。 @50
- 测试type为card图表是否显示正确,目前不存在统计方式为value的图表。 @1
- 测试统计方式类型为value的图表是否显示正确,目前不存在统计方式为value的图表。 @1
- 测试type为card图表是否显示正确,目前不存在统计方式为count的图表。 @1
- 测试统计方式类型为count的图表是否显示正确,目前不存在统计方式为count的图表。 @1
- 测试type为card以及统计方式类型为sum的图表是否显示正确,生成的数据项数量是否正确。 @1
*/
@@ -52,11 +54,13 @@ function getComponetAndChart($screen, $valueType = array(), $filters = array())
$filter12 = array('type' => 'card');
list($component13, $chart13) = getComponetAndChart($screen, array('type' => 'value'), $filter12);
r(is_null($component13) || is_null($chart13)) && p('') && e(1); //测试type为card以及统计方式类型为value的图表是否显示正确,目前不存在统计方式为value的图表。
r(is_null($component13)) && p('') && e(1); // 测试type为card图表是否显示正确,目前不存在统计方式为value的图表。
r(is_null($chart13)) && p('') && e(1); // 测试统计方式类型为value的图表是否显示正确,目前不存在统计方式为value的图表。
list($component14, $chart14) = getComponetAndChart($screen, array('type' => 'count'), $filter12);
r(is_null($component14) || is_null($chart14)) && p('') && e(1); //测试type为card以及统计方式类型为count的图表是否显示正确,目前不存在统计方式为count的图表。
r(is_null($component14)) && p('') && e(1); // 测试type为card图表是否显示正确,目前不存在统计方式为count的图表。
r(is_null($chart14)) && p('') && e(1); // 测试统计方式类型为count的图表是否显示正确,目前不存在统计方式为count的图表。
list($component15, $chart15) = getComponetAndChart($screen, array('egg' => 'sum'), $filter12);
$screen->buildCardChart($component15, $chart15);
r($component15->option->dataset) && p('') && e('50'); //测试type为card以及统计方式类型为sum的图表是否显示正确,生成的数据项数量是否正确。
r(isset($component15->option->dataset)) && p('') && e('1'); //测试type为card以及统计方式类型为sum的图表是否显示正确,数据项参数是否正确。
+10 -8
View File
@@ -14,7 +14,13 @@ title=测试 screenModel->buildChart();
timeout=0
cid=1
- 检查组件是否都被修改。 @1
- 检查组件是否都被修改。
- 属性card @1
- 属性line @1
- 属性piecircle @1
- 属性pie @1
- 属性table @1
- 属性baroption @1
*/
@@ -46,16 +52,12 @@ foreach($components as $component)
}
}
$check = true;
$checkList = array();
foreach($componentList as $type => $component)
{
$clone_componet = clone $component;
$screen->buildChartTest($clone_componet);
if(serialize($clone_componet) == serialize($component))
{
$check = false;
break;
}
$checkList[$type] = serialize($clone_componet) != serialize($component);
}
r($check) && p('') && e(1); //检查组件是否都被修改。
r($checkList) && p('card,line,piecircle,pie,table,baroption') && e('1,1,1,1,1,1'); //检查组件是否都被修改。
@@ -0,0 +1,34 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
zenData('metric')->gen(1);
/**
title=测试 screenModel->buildMetricFilters();
timeout=0
cid=1
- 测试传入metric属性,isObjectMetric和isDateMetric为false的情况下,生成的值是否正确; @0
- 测试传入metric属性,isObjectMetric为false,isDateMetric为true的情况下,生成的值是否正确;第0条的field属性 @date
- 测试传入metric属性,isObjectMetric为false,isDateMetric为true的情况下,生成的值是否正确;第0条的field属性 @date
- 测试传入metric属性,isObjectMetric和isDateMetric为true的情况下,生成的第一条数据值是否正确;第0条的field属性 @system
- 测试传入metric属性,isObjectMetric和isDateMetric为true的情况下,生成的第二条数据值是否正确;第1条的field属性 @date
*/
global $tester;
$screen = new screenTest();
$tester->loadModel('bi');
$metric1 = $tester->loadModel('metric')->getByID(1);
$metric1 = array_merge((array)$metric1, $config->bi->builtin->metrics[0]);
r($screen->buildMetricFilters((object)$metric1, false, false)) && p() && e(0); // 测试传入metric属性,isObjectMetric和isDateMetric为false的情况下,生成的值是否正确;
r($screen->buildMetricFilters((object)$metric1, false, true)) && p('0:field') && e('date'); // 测试传入metric属性,isObjectMetric为false,isDateMetric为true的情况下,生成的值是否正确;
$metric1 = array_merge((array)$metric1, $config->bi->builtin->metrics[30]);
r($screen->buildMetricFilters((object)$metric1, false, true)) && p('0:field') && e('date'); // 测试传入metric属性,isObjectMetric为false,isDateMetric为true的情况下,生成的值是否正确;
r($screen->buildMetricFilters((object)$metric1, true, true)) && p('0:field') && e('system'); // 测试传入metric属性,isObjectMetric和isDateMetric为true的情况下,生成的第一条数据值是否正确;
r($screen->buildMetricFilters((object)$metric1, true, true)) && p('1:field') && e('date'); // 测试传入metric属性,isObjectMetric和isDateMetric为true的情况下,生成的第二条数据值是否正确;
@@ -8,6 +8,11 @@ title=测试 screenModel->buildWaterPolo()。
timeout=0
cid=1
- 测试key @WaterPolo
- 测试chartKey,conKey以及标题。
- 属性chartKey @VWaterPolo
- 属性conKey @VCWaterPolo
- 属性title @Bug密度
- 判断生成的水球图数据是否正确。 @1
*/
@@ -46,4 +51,6 @@ foreach($components as $component)
isset($componentList['waterpolo']) && $screen->buildWaterPolo($componentList['waterpolo'], $chart);
$waterpolo = $componentList['waterpolo'] ?? null;
r($waterpolo->key) && p('') && e('WaterPolo'); // 测试key
r($waterpolo->chartConfig) && p('chartKey,conKey,title') && e('VWaterPolo,VCWaterPolo,Bug密度'); // 测试chartKey,conKey以及标题。
r($waterpolo && round($waterpolo->option->dataset, 3) == '0.176') && p('') && e('1'); //判断生成的水球图数据是否正确。
+11 -3
View File
@@ -10,7 +10,11 @@ timeout=0
cid=1
- 判断图表的sql字段是否被修改 @1
- 判断图表的sql字段是否被修改 @1
- 判断图表的fields字段是否被修改 @1
- 判断图表的settings字段是否被修改 @1
- 判断图表的sql字段是否被修改 @0
- 判断图表的fields字段是否被修改 @1
- 判断图表的settings字段是否被修改 @1
*/
@@ -49,11 +53,15 @@ $chartList = array($chart1, $chart2);
$chart1->sql .= ";;;;;";
$chart1_ = clone($chart1);
$screen->genComponentDataTest($chartList[0], $componentList[0], $typeList[0], array());
r($chart1->sql === $chart1_->sql) && p('') && e(1); //判断图表的sql字段是否被修改
r($chart1->sql === $chart1_->sql) && p('') && e(1); //判断图表的sql字段是否被修改
r($chart1->fields === $chart1_->fields) && p('') && e(1); //判断图表的fields字段是否被修改
r($chart1->settings === $chart1_->settings) && p('') && e(1); //判断图表的settings字段是否被修改
$chart2_ = clone($chart2);
$chart2->sql = '';
$chart2->filters = '[{"field":"type","type":"int"}]';
$screen->genComponentDataTest($chartList[1], $componentList[1], $typeList[1], array());
r($chart2_->sql !== $chart2->sql) && p('') && e(1); //判断图表的sql字段是否被修改
r($chart2->sql === $chart2_->sql) && p('') && e(0); //判断图表的sql字段是否被修改
r($chart2->fields === $chart2_->fields) && p('') && e(1); //判断图表的fields字段是否被修改
r($chart2->settings === $chart2_->settings) && p('') && e(1); //判断图表的settings字段是否被修改
@@ -0,0 +1,69 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
/**
title=测试 screenModel->genComponentFromData();
timeout=0
cid=1
- 测试类型是text,标题是Text1生成的组件
- 属性title @Text1
- 属性type @text
- 测试类型是text,标题是Text2生成的组件
- 属性title @Text2
- 属性type @text
- 测试类型是text,标题是Text3生成的组件
- 属性title @Text3
- 属性type @text
- 测试类型是waterpolo,标题是Waterpolo1生成的组件
- 属性title @Waterpolo1
- 属性type @waterpolo
- 测试类型是table,标题是Table1生成的组件
- 属性title @Table1
- 属性type @table
*/
global $tester;
$tester->loadModel('screen');
$attr = array('w' => 900, 'h' => 300, 'x' => 20, 'y' => 100);
$textOptions = array('title.show' => false);
$waterOptions = array(
'title.show' => false,
'series.0.outline.show' => false,
'series.0.label.normal.textStyle.fontSize' => 13,
'series.0.label.normal.textStyle.fontWeight' => 'normal',
'series.0.label.normal.textStyle.round' => 2,
'series.0.color.0.type' => 'linear',
);
$headers = array(array(
array('field' => 'name', 'name' => 'name', 'label' => 'Name'),
array('field' => 'age', 'name' => 'age', 'label' => 'Age'),
array('field' => 'gender', 'name' => 'gender', 'label' => 'Gender'),
));
$tableDataSet = array(
array('tester1', 25, 'male'),
array('tester2', 30, 'female'),
array('tester3', 35, 'male'),
array('tester4', 40, 'female'),
);
$tableData = array($headers, array(), array(), $tableDataSet, array(), array());
$tableOptions = array(
'colNum' => 4,
'rowNum' => 4,
'headerBGC' => '#fcfdfe',
'bodyBGC' => '#fff',
'borderBGC' => '#e6ecf8',
'fontColor' => '#000',
'rowHeight' => 36
);
r($tester->screen->genComponentFromData('text', 'Text1', '', $attr, $textOptions)) && p('title,type') && e('Text1,text'); //测试类型是text,标题是Text1生成的组件信息,title为Text1,type为text
r($tester->screen->genComponentFromData('text', 'Text2', 'desc', $attr, $textOptions)) && p('title,type') && e('Text2,text'); //测试类型是text,标题是Text2生成的组件信息,title为Text2,type为text
r($tester->screen->genComponentFromData('text', 'Text3', 'desc', $attr, array())) && p('title,type') && e('Text3,text'); //测试类型是text,标题是Text3生成的组件信息,title为Text3,type为text
r($tester->screen->genComponentFromData('waterpolo', 'Waterpolo1', 0.2, $attr, $waterOptions)) && p('title,type') && e('Waterpolo1,waterpolo'); //测试类型是waterpolo,标题是Waterpolo1,数据是0.2生成的组件信息,title为Waterpolo1,type为waterpolo
r($tester->screen->genComponentFromData('table', 'Table1', $tableData, $attr, $tableOptions)) && p('title,type') && e('Table1,table'); //测试类型是table,标题是Table1生成的组件信息,title为Table1,type为table
@@ -0,0 +1,61 @@
#!/usr/bin/env php
<?php
declare(strict_types = 1);
/**
title=测试 screenModel->getAxisRotateOption();
timeout=0
cid=1
- 判断折线图x轴旋转角度 @30
- 判断折线图y轴旋转角度 @30
- 判断折线图仅设置x轴旋转时x轴旋转角度 @30
- 判断折线图仅设置x轴旋转时y轴旋转角度 @0
- 判断雷达图是否设置x轴旋转角度 @0
- 判断雷达图是否设置y轴旋转角度 @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
$screen = new screenTest();
global $tester;
$chart1 = new stdClass();
$chart1->type = 'line';
$chart1->settings = json_encode(array(array('rotateX' => 'use', 'rotateY' => 'use')));
$component = new stdClass();
$component->chartConfig = new stdClass();
$component = $screen->getAxisRotateOption($chart1, $component);
r($component->chartConfig->xAxis->axisLabel->rotate) && p('') && e('30'); // 判断折线图x轴旋转角度
r($component->chartConfig->yAxis->axisLabel->rotate) && p('') && e('30'); // 判断折线图y轴旋转角度
$chart2 = new stdClass();
$chart2->type = 'line';
$chart2->settings = json_encode(array(array('rotateX' => 'use')));
$component = new stdClass();
$component->chartConfig = new stdClass();
$component = $screen->getAxisRotateOption($chart2, $component);
r($component->chartConfig->xAxis->axisLabel->rotate) && p('') && e('30'); // 判断折线图仅设置x轴旋转时x轴旋转角度
r($component->chartConfig->yAxis->axisLabel->rotate) && p('') && e('0'); // 判断折线图仅设置x轴旋转时y轴旋转角度
$chart3 = new stdClass();
$chart3->type = 'radar';
$chart3->settings = json_encode(array(array('rotateX' => 'use')));
$component = new stdClass();
$component->chartConfig = new stdClass();
$component = $screen->getAxisRotateOption($chart3, $component);
r(isset($component->chartConfig->xAxis->axisLabel->rotate)) && p('') && e('0'); // 判断雷达图是否设置x轴旋转角度
r(isset($component->chartConfig->yAxis->axisLabel->rotate)) && p('') && e('0'); // 判断雷达图是否设置y轴旋转角度
@@ -34,6 +34,7 @@ function getComponetAndChart($screen, $filters = array())
$type = $componet->chartConfig->package == 'Tables' ? 'pivot' : 'chart';
$table = $type == 'chart' ? TABLE_CHART : TABLE_PIVOT;
$chart = $tester->dao->select('*')->from($table)->where('id')->eq($componet->sourceID)->fetch();
$componet->option->dataset = new stdclass();
if($chart) return array($componet, $chart);
}
return array(null, null);
@@ -8,8 +8,13 @@ title=测试 screenModel->getLineChartOption()。
timeout=0
cid=1
- 测试获取折线图配置中dimensions是否正确,值为年份。 @1
- 测试获取折线图配置中source是否正确。 @1
- 测试chartKey和标题。
- 属性chartKey @VLineCommon
- 属性title @有效Bug率年度趋势图
- 测试option标题和显示。
- 属性text @有效Bug率年度趋势图
- 测试正确生成了dimensions。 @1
- 测试正确生成了source。 @1
*/
@@ -43,9 +48,8 @@ $filter1 = array('type' => 'line');
list($component1, $chart1) = getComponetAndChart($screen, $filter1);
$screen->getLineChartOption($component1, $chart1);
$dimension_0 = $component1->option->dataset->dimensions[0] ?? null;
$dimension_1 = $component1->option->dataset->dimensions[1] ?? null;
$year = date('Y', strtotime('-1 month'));
$source_0 = $component1->option->dataset->source[0];
r($dimension_0 && $dimension_0 == 'year') && p('') && e('1'); //测试获取折线图配置中dimensions是否正确,值为年份。
r($dimension_0 && $dimension_1 && $source_0 && $source_0->{$dimension_0} == $year && $source_0->{$dimension_1} === '1.0000') && p('') && e('1'); //测试获取折线图配置中source是否正确。
r($component1->chartConfig) && p('chartKey,title') && e('VLineCommon,有效Bug率年度趋势图'); // 测试chartKey和标题。
r($component1->option->title) && p('text') && e('有效Bug率年度趋势图'); // 测试option标题。
r(is_array($component1->option->dataset->dimensions)) && p('') && e(1); // 测试正确生成了dimensions。
r(is_array($component1->option->dataset->source)) && p('') && e(1); // 测试正确生成了source。
+12 -3
View File
@@ -14,8 +14,13 @@ title=测试 screenModel->getchartoption();
timeout=0
cid=1
- 测试type为pie的图表是否显示正确,生成的指标项是否正确和数据项是否正确。。 @1
- 测试type为pie的图表是否显示正确,生成的指标项是否正确和数据项是否正确。 @1
- 测试type为pie的图表是否显示正确,生成的数据项是否正确。 @1
- 测试饼图类型。 @pie
- 测试饼图半径。 @70%
- 测试饼图内圈和外圈。
- @50%
- 属性1 @60%
*/
@@ -43,7 +48,7 @@ list($component8, $chart8) = getComponetAndChart($screen, $filter8);
$screen->getChartOptionTest($chart8, $component8);
$dataset = $component8->option->dataset ?? null;
$serires = $component8->option->series ?? null;
r($dataset->dimensions[0] == 'completeStatus' && $dataset->source[0]->completeStatus == '延期完成项目') && p('') && e(1); //测试type为pie的图表是否显示正确,生成的指标项是否正确和数据项是否正确。。
r($dataset->dimensions[0] == 'completeStatus' && $dataset->source[0]->completeStatus == '延期完成项目') && p('') && e(1); //测试type为pie的图表是否显示正确,生成的指标项是否正确和数据项是否正确。
$check = true;
$pieConfig = $serires[0];
@@ -51,4 +56,8 @@ if($pieConfig->type != 'pie') $check = false;
if($pieConfig->radius != '70%') $check = false;
if($pieConfig->center[0] != '50%') $check = false;
if($pieConfig->center[1] != '60%') $check = false;
r($check) && p('') && e(1); //测试type为pie的图表是否显示正确,生成的数据项是否正确。
r($check) && p('') && e(1); //测试type为pie的图表是否显示正确,生成的数据项是否正确。
r($pieConfig->type) && p('') && e('pie'); // 测试饼图类型。
r($pieConfig->radius) && p('') && e('70%'); // 测试饼图半径。
r($pieConfig->center) && p('0,1') && e('50%,60%'); // 测试饼图内圈和外圈。
@@ -0,0 +1,62 @@
#!/usr/bin/env php
<?php
declare(strict_types = 1);
/**
title=测试 screenModel->getRadarChartOption();
timeout=0
cid=1
- 测试组件类型 @VRadar
- 判断radarIndicator存在 @1
- 判断indicator存在 @1
- 判断radarIndicator[0]的name和max
- 属性name @产品管理
- 属性max @0
- 判断radarIndicator[1]的name和max
- 属性name @项目管理
- 属性max @0
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
zenData('product')->gen(5);
zenData('project')->loadYaml('program')->gen(5);
zenData('story')->loadYaml('story')->gen(20);
zenData('bug')->loadYaml('bug')->gen(15);
zenData('action')->loadYaml('action')->gen(100);
$screen = new screenTest();
global $tester;
$chart = new stdClass();
$chart->id = 1007;
$chart->type = 'radar';
$chart->driver = 'mysql';
$chart->name = '测试雷达图';
$chart->settings = '[{"type":"radar","xaxis":[{"field":"action","name":"\u52a8\u4f5c","group":""}],"yaxis":[{"field":"action","name":"\u52a8\u4f5c","valOrAgg":"count"}]}]';
$chart->fields = '{"action":{"name":"\u52a8\u4f5c","object":"action","field":"action","type":"string"}}';
$chart->langs = '';
$chart->sql = 'select action from zt_action';
$component = json_decode($tester->config->screen->chartConfig['radar']);
$component->option = new stdClass();
$component->option->dataset = new stdClass();
$component->option->radar = new stdClass();
$component->option->series = array();
$component = $screen->getRadarChartOption($component, $chart);
r($component->chartKey) && p('') && e('VRadar'); // 测试组件类型
r(isset($component->option->dataset->radarIndicator)) && p('') && e('1'); // 判断radarIndicator存在
r(isset($component->option->dataset->seriesData)) && p('') && e('1'); // 判断seriesData存在
$radarIndicator = $component->option->dataset->radarIndicator;
r($radarIndicator[0]) && p('name,max') && e('3,3'); // 判断radarIndicator[0]的name和max
r($radarIndicator[1]) && p('name,max') && e('2,3'); // 判断radarIndicator[1]的name和max
@@ -14,8 +14,11 @@ title=测试 screenModel->getTableChartOption();
timeout=0
cid=1
- 测试type为table的图表是否显示正确,生成的header指标项数量是否正确。 @1
- 测试type为table的图表是否显示正确,生成的dataset数据项数量是否正确。 @1
- 测试组件类型。 @TableMergeCell
- 测试type为table的图表是否显示正确。 @1
- 测试type为table的图表是否显示正确。 @1
- 测试生成的header指标项数量是否正确。 @10
- 测试生成的dataset数据项数量是否正确。 @10
*/
@@ -43,5 +46,10 @@ $filter9 = array('type' => 'table');
list($component9, $chart9) = getComponetAndChart($screen, $filter9);
$screen->getChartOptionTest($chart9, $component9);
$option = $component9->option;
r(isset($option->header[0]) && count($option->header[0]) == 10) && p('') && e(1); //测试type为table的图表是否显示正确,生成的header指标项数量是否正确。
r(isset($option->dataset[0]) && count($option->dataset[0]) == 10) && p('') && e(1); //测试type为table的图表是否显示正确,生成的dataset数据项数量是否正确。
r($component9->key) && p('') && e('TableMergeCell'); // 测试组件类型。
r(isset($option->header[0])) && p('') && e(1); // 测试type为table的图表是否显示正确。
r(isset($option->dataset[0])) && p('') && e(1); // 测试type为table的图表是否显示正确。
r(count($option->header[0])) && p('') && e(10); // 测试生成的header指标项数量是否正确。
r(count($option->dataset[0])) && p('') && e(10); // 测试生成的dataset数据项数量是否正确。
@@ -0,0 +1,38 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->prepareBoxDataset();
timeout=0
cid=1
- 测试data属性为空的情况下,生成的默认值是否正确;属性type @box
- 测试传入data属性的情况下,生成的值是否正确;属性type @box
- 测试传入data属性,styles有值的情况下,是否被修改。属性styles @1
- 测试status有值的情况下,是否被修改。属性status @1
- 测试request有值的情况下,是否被修改。属性request @1
*/
$screen = new screenTest();
$component1 = new stdclass();
$component1->type = 'box';
$component1->option = new stdclass();
$component2 = clone $component1;
$component2->styles = 1;
$component3 = clone $component1;
$component3->status = 1;
$component4 = clone $component1;
$component4->request = 1;
r($screen->prepareBoxDataset($component1, array())) && p('type') && e('box'); // 测试data属性为空的情况下,生成的默认值是否正确;
r($screen->prepareBoxDataset($component1, array(0,1,2,3,4,5))) && p('type') && e('box'); // 测试传入data属性的情况下,生成的值是否正确;
r($screen->prepareBoxDataset($component2, array(0,1,2,3,4,5))) && p('styles') && e(1); // 测试传入data属性,styles有值的情况下,是否被修改。
r($screen->prepareBoxDataset($component3, array())) && p('status') && e(1); // 测试status有值的情况下,是否被修改。
r($screen->prepareBoxDataset($component4, array())) && p('request') && e(1); // 测试request有值的情况下,是否被修改。
@@ -0,0 +1,38 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->prepareCardDataset();
timeout=0
cid=1
- 测试value属性为空的情况下,生成的默认值是否正确;属性type @card
- 测试传入value属性的情况下,生成的值是否正确;属性type @card
- 测试传入value属性,styles有值的情况下,是否被修改。属性styles @1
- 测试status有值的情况下,是否被修改。属性status @1
- 测试request有值的情况下,是否被修改。属性request @1
*/
$screen = new screenTest();
$component1 = new stdclass();
$component1->type = 'card';
$component1->option = new stdclass();
$component2 = clone $component1;
$component2->styles = 1;
$component3 = clone $component1;
$component3->status = 1;
$component4 = clone $component1;
$component4->request = 1;
r($screen->prepareCardDataset($component1, '0')) && p('type') && e('card'); // 测试value属性为空的情况下,生成的默认值是否正确;
r($screen->prepareCardDataset($component1, '1')) && p('type') && e('card'); // 测试传入value属性的情况下,生成的值是否正确;
r($screen->prepareCardDataset($component2, '1')) && p('styles') && e(1); // 测试传入value属性,styles有值的情况下,是否被修改。
r($screen->prepareCardDataset($component3, '0')) && p('status') && e(1); // 测试status有值的情况下,是否被修改。
r($screen->prepareCardDataset($component4, '0')) && p('request') && e(1); // 测试request有值的情况下,是否被修改。
@@ -0,0 +1,38 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->prepareChartDataset();
timeout=0
cid=1
- 测试dimensions和sourceData属性为空的情况下,生成的默认值是否正确;属性type @pie
- 测试传入dimensions属性的情况下,生成的值是否正确;属性type @pie
- 测试传入sourceData属性的情况下,生成的值是否正确;属性type @pie
- 测试传入dimensions和sourceData属性的情况下,生成的值是否正确;属性type @pie
- 测试styles有值的情况下,是否被修改。属性styles @1
- 测试status有值的情况下,是否被修改。属性status @1
*/
$screen = new screenTest();
$component1 = new stdclass();
$component1->type = 'pie';
$component1->option = new stdclass();
$component1->option->dataset = new stdclass();
$component2 = clone $component1;
$component2->styles = 1;
$component3 = clone $component1;
$component3->status = 1;
r($screen->prepareChartDataset($component1, array(), array())) && p('type') && e('pie'); // 测试dimensions和sourceData属性为空的情况下,生成的默认值是否正确;
r($screen->prepareChartDataset($component1, array(0,1,2,3,4,5), array())) && p('type') && e('pie'); // 测试传入dimensions属性的情况下,生成的值是否正确;
r($screen->prepareChartDataset($component1, array(), array(0,1,2,3,4,5))) && p('type') && e('pie'); // 测试传入sourceData属性的情况下,生成的值是否正确;
r($screen->prepareChartDataset($component1, array(0,1), array(0,1,2,3,4,5))) && p('type') && e('pie'); // 测试传入dimensions和sourceData属性的情况下,生成的值是否正确;
r($screen->prepareChartDataset($component2, array(), array())) && p('styles') && e(1); // 测试styles有值的情况下,是否被修改。
r($screen->prepareChartDataset($component3, array(), array())) && p('status') && e(1); // 测试status有值的情况下,是否被修改。
@@ -0,0 +1,51 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->preparegroupdataset();
timeout=0
cid=1
- 测试componentList属性为空的情况下,生成的默认值是否正确;属性type @group
- 测试传入componentList属性的情况下,生成的值是否正确;属性isGroup @1
- 测试传入componentList属性,生成的值是否正确;属性isGroup @1
- 测试传入componentList属性,styles有值的情况下,是否被修改。属性styles @1
- 测试status有值的情况下,是否被修改。属性status @1
*/
$screen = new screenTest();
$component1 = new stdclass();
$component1->type = 'group';
$component1->isGroup = false;
$component1->groupList = array();
$component2 = clone $component1;
$component2->styles = 1;
$component3 = clone $component1;
$component3->status = 1;
$attr = array('w' => 900, 'h' => 300, 'x' => 20, 'y' => 100);
$waterOptions = array(
'title.show' => false,
'series.0.outline.show' => false,
'series.0.label.normal.textStyle.fontSize' => 13,
'series.0.label.normal.textStyle.fontWeight' => 'normal',
'series.0.label.normal.textStyle.round' => 2,
'series.0.color.0.type' => 'linear',
);
$components = array();
$components[] = $screen->genComponentFromData('text', 'Title1', 'Title1', $attr);
$components[] = $screen->genComponentFromData('text', '', '', $attr);
$components[] = $screen->genComponentFromData('waterpolo', 'Waterpolo1', 0.2, $attr, $waterOptions);
r($screen->preparegroupdataset($component1, array())) && p('type') && e('group'); // 测试componentList属性为空的情况下,生成的默认值是否正确;
r($screen->preparegroupdataset($component1, array($components[0]))) && p('isGroup') && e(1); // 测试传入componentList属性的情况下,生成的值是否正确;
r($screen->preparegroupdataset($component1, $components)) && p('isGroup') && e(1); // 测试传入componentList属性,生成的值是否正确;
r($screen->preparegroupdataset($component2, $components)) && p('styles') && e(1); // 测试传入componentList属性,styles有值的情况下,是否被修改。
r($screen->preparegroupdataset($component3, array())) && p('status') && e(1); // 测试status有值的情况下,是否被修改。
@@ -0,0 +1,39 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->prepareSunburstDataset();
timeout=0
cid=1
- 测试data属性为空的情况下,生成的默认值是否正确;第styles条的hueRotate属性 @0
- 测试传入data属性的情况下,生成的值是否正确;第styles条的hueRotate属性 @0
- 测试传入data属性,styles有值的情况下,是否被修改。属性styles @1
- 测试status有值的情况下,是否被修改。属性status @1
- 测试request有值的情况下,是否被修改。属性request @1
*/
$screen = new screenTest();
$component1 = new stdclass();
$component1->type = 'sunburst';
$component1->option = new stdclass();
$component1->option->series = new stdclass();
$component2 = clone $component1;
$component2->styles = 1;
$component3 = clone $component1;
$component3->status = 1;
$component4 = clone $component1;
$component4->request = 1;
r($screen->prepareSunburstDataset($component1, array())) && p('styles:hueRotate') && e(0); // 测试data属性为空的情况下,生成的默认值是否正确;
r($screen->prepareSunburstDataset($component1, array(0,1,2,3,4,5))) && p('styles:hueRotate') && e(0); // 测试传入data属性的情况下,生成的值是否正确;
r($screen->prepareSunburstDataset($component2, array(0,1,2,3,4,5))) && p('styles') && e(1); // 测试传入data属性,styles有值的情况下,是否被修改。
r($screen->prepareSunburstDataset($component3, array())) && p('status') && e(1); // 测试status有值的情况下,是否被修改。
r($screen->prepareSunburstDataset($component4, array())) && p('request') && e(1); // 测试request有值的情况下,是否被修改。
@@ -0,0 +1,49 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->prepareTableDataset();
timeout=0
cid=1
- 测试属性为空的情况下,生成的默认值是否正确;属性type @table
- 测试添加headers属性的情况下,生成的值是否正确;属性type @table
- 测试添加headers和align属性的情况下,生成的值是否正确;属性type @table
- 测试styles有值的情况下,是否被修改。属性styles @1
- 测试status有值的情况下,是否被修改。属性status @1
*/
$screen = new screenTest();
$component1 = new stdclass();
$component1->type = 'table';
$component1->option = $component1->chartConfig = new stdclass();
$component2 = clone $component1;
$component2->styles = 1;
$component3 = clone $component1;
$component3->status = 1;
$headers = array(array(
array('field' => 'name', 'name' => 'name', 'label' => 'Name'),
array('field' => 'age', 'name' => 'age', 'label' => 'Age'),
array('field' => 'gender', 'name' => 'gender', 'label' => 'Gender'),
));
$align = array('left', 'center', 'right');
$dataset = array(
array('tester1', 25, 'male'),
array('tester2', 30, 'female'),
array('tester3', 35, 'male'),
array('tester4', 40, 'female'),
);
r($screen->prepareTableDataset($component1, array(), array(), array(), array(), array(), array())) && p('type') && e('table'); // 测试属性为空的情况下,生成的默认值是否正确;
r($screen->prepareTableDataset($component1, $headers, array(), array(), array(), array(), array())) && p('type') && e('table'); // 测试添加headers属性的情况下,生成的值是否正确;
r($screen->prepareTableDataset($component1, $headers, $align, array(), array(), $dataset, array())) && p('type') && e('table'); // 测试添加headers和align属性的情况下,生成的值是否正确;
r($screen->prepareTableDataset($component2, $headers, $align, array(), array(), $dataset, array())) && p('styles') && e(1); // 测试styles有值的情况下,是否被修改。
r($screen->prepareTableDataset($component3, $headers, $align, array(), array(), $dataset, array())) && p('status') && e(1); // 测试status有值的情况下,是否被修改。
@@ -0,0 +1,37 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->prepareWaterPoloDataset();
timeout=0
cid=1
- 测试data属性为0的情况下,生成的值是否正确;第option条的dataset属性 @0
- 测试data属性为0.2的情况下,生成的值是否正确;第option条的dataset属性 @0.2
- 测试data属性为0.2的情况下,生成的值是否正确;第option条的dataset属性 @1
- 测试data属性为0.2,styles有值的情况下,是否被修改。
- 属性type @waterpolo
- 属性styles @1
- 测试status有值的情况下,是否被修改。属性status @1
*/
$screen = new screenTest();
$component1 = new stdclass();
$component1->type = 'waterpolo';
$component1->option = new stdclass();
$component2 = clone $component1;
$component2->styles = 1;
$component3 = clone $component1;
$component3->status = 1;
r($screen->prepareWaterPoloDataset($component1, 0)) && p('option:dataset') && e('0'); // 测试data属性为0的情况下,生成的值是否正确;
r($screen->prepareWaterPoloDataset($component1, 0.2)) && p('option:dataset') && e('0.2'); // 测试data属性为0.2的情况下,生成的值是否正确;
r($screen->prepareWaterPoloDataset($component1, 1)) && p('option:dataset') && e('1'); // 测试data属性为0.2的情况下,生成的值是否正确;
r($screen->prepareWaterPoloDataset($component2, 0.2)) && p('type,styles') && e('waterpolo,1'); // 测试data属性为0.2,styles有值的情况下,是否被修改。
r($screen->prepareWaterPoloDataset($component3, 0)) && p('status') && e(1); // 测试status有值的情况下,是否被修改。
+9 -3
View File
@@ -18,6 +18,10 @@ cid=1
- 当模型中有chart数据的时候,并且类型为account,生成的sql为图表本身的sql+筛选条件。 @SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin = 'admin'
- 当模型中有chart数据的时候,并且类型为month,生成的sql为图表本身的sql+筛选条件。 @SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin = 'admin'
- 当模型中有chart数据的时候,并且类型为dept,生成的sql为图表本身的sql+筛选条件。 @SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin = 'admin'
*/
$screen = new screenTest();
@@ -25,6 +29,8 @@ $screen = new screenTest();
global $tester;
$chart = $tester->dao->select('*')->from(TABLE_CHART)->where('id')->eq(1018)->fetch();
r($screen->setFilterSqlTest($chart, '')) && p('') && e("SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0'"); //当模型中没有chart数据的时候,生成的sql为图表本身的sql。
r($screen->setFilterSqlTest($chart, 'year', true)) && p('') && e("SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin IN ('admin')"); //当模型中有chart数据的时候,并且类型不为account,生成的sql为图表本身的sql+筛选条件。
r($screen->setFilterSqlTest($chart, 'account', true)) && p('') && e("SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin = 'admin'"); //当模型中有chart数据的时候,并且类型为account,生成的sql为图表本身的sql+筛选条件。
r($screen->setFilterSqlTest($chart, '')) && p('') && e("SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0'"); //当模型中没有chart数据的时候,生成的sql为图表本身的sql。
r($screen->setFilterSqlTest($chart, 'year', true)) && p('') && e("SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin IN ('admin')"); //当模型中有chart数据的时候,并且类型不为account,生成的sql为图表本身的sql+筛选条件。
r($screen->setFilterSqlTest($chart, 'account', true)) && p('') && e("SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin = 'admin'"); //当模型中有chart数据的时候,并且类型为account,生成的sql为图表本身的sql+筛选条件。
r($screen->setFilterSqlTest($chart, 'month', true)) && p('') && e("SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin = 'admin'"); //当模型中有chart数据的时候,并且类型为month,生成的sql为图表本身的sql+筛选条件。
r($screen->setFilterSqlTest($chart, 'dept', true)) && p('') && e("SELECT * FROM (SELECT id,name FROM zt_project WHERE type='program' AND parent=0 AND deleted='0') AS t1 WHERE 2023 = '2023' AND admin = 'admin'"); //当模型中有chart数据的时候,并且类型为dept,生成的sql为图表本身的sql+筛选条件。
@@ -0,0 +1,44 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/screen.unittest.class.php';
/**
title=测试 screenModel->setValueByPath();
timeout=0
cid=1
- 测试title.show=true @1
- 测试series.0.color.0.colorStops.0.offset=1 @1
- 测试series.0.color.0.x=#fff @#fff
- 测试series.0.color.1.y=#000 @#000
- 测试series.0.0.name=data @data
*/
$screen = new screenTest();
$paths = array
(
'title.show',
'series.0.color.0.colorStops.0.offset',
'series.0.color.0.x',
'series.0.color.1.y',
'series.0.0.name',
);
$options = new stdclass();
$screen->setValueByPathTest($options, $paths[0], true);
$screen->setValueByPathTest($options, $paths[1], 1);
$screen->setValueByPathTest($options, $paths[2], '#fff');
$screen->setValueByPathTest($options, $paths[3], '#000');
r($options->title->show) && p('') && e("1"); //测试title.show=true
r($options->series[0]->color[0]->colorStops[0]->offset) && p('') && e("1"); //测试series.0.color.0.colorStops.0.offset=1
r($options->series[0]->color[0]->x) && p('') && e("#fff"); //测试series.0.color.0.x=#fff
r($options->series[0]->color[1]->y) && p('') && e("#000"); //测试series.0.color.1.y=#000
$options = new stdclass();
$screen->setValueByPathTest($options, $paths[4], 'data');
r($options->series[0][0]->name) && p('') && e("data"); //测试series.0.0.name=data
+11
View File
@@ -0,0 +1,11 @@
<?php include $app->getModuleRoot() . 'common/view/header.lite.html.php';?>
<?php js::set('webRoot', $webRoot);?>
<div id="appProvider" style="display: none;"></div>
<div id="app">
<div class="first-loading-wrp">
<div class="loading-wrp">
<span class="dot dot-spin"></span>
</div>
</div>
</div>
<?php include $app->getModuleRoot() . 'common/view/footer.lite.html.php';?>
+23
View File
@@ -45,4 +45,27 @@ class screenZen extends screen
return $screens;
}
/**
* Set select filter.
*
* @param string $sourceID
* @param array $filters
* @access protected
* @return array
*/
protected function setSelectFilter($sourceID, $filters)
{
if(empty($filters)) return;
$chartFilters = array();
foreach($filters as $filter)
{
if(!isset($chartFilters[$sourceID])) $chartFilters[$sourceID] = array();
$chartFilters[$sourceID][$filter['type']] = $filter['field'];
}
return $chartFilters;
}
}
+4 -4
View File
@@ -12,7 +12,7 @@ cid=0
- 属性spec @测试需求1的变更描述
- 属性version @4
- 变更时不填写需求名称,给出提示 @1
- 测试修改名称为空。第title条的0属性 @『名称』不能为空。
- 测试修改名称为空。第title条的0属性 @『研发需求名称』不能为空。
- 测试存在relievedTwins。属性title @测试需求1变更标题
- 测试变成需求。属性title @名称修改
@@ -57,8 +57,8 @@ $story5->title = '名称修改';
$result = $story->changeTest(2, $story2);
r($story->changeTest(1, $story1)) && p('title,spec,version') && e('测试需求1变更标题,测试需求1的变更描述,4'); // 查看变更后需求数据。
r((int)strpos($result['title'][0], '名称』不能为空') !== false) && p() && e('1'); // 变更时不填写需求名称,给出提示
r($story->changeTest(2, $story3)) && p('title:0') && e('『名称』不能为空。'); // 测试修改名称为空。
r($story->changeTest(1, $story1)) && p('title,spec,version') && e('测试需求1变更标题,测试需求1的变更描述,4'); // 查看变更后需求数据。
r((int)strpos($result['title'][0], '名称』不能为空') !== false) && p() && e('1'); // 变更时不填写需求名称,给出提示
r($story->changeTest(2, $story3)) && p('title:0') && e('『研发需求名称』不能为空。'); // 测试修改名称为空。
r($story->changeTest(3, $story4)) && p('title') && e('测试需求1变更标题'); // 测试存在relievedTwins。
r($story->changeTest(4, $story5)) && p('title') && e('名称修改'); // 测试变成需求。
+7 -2
View File
@@ -6,9 +6,13 @@
title=测试 storyModel->saveEstimateInfo();
cid=0
- 执行$storyInfo
- 测试 story的id,圆整值,平均值
- 属性story @2
- 属性round @2
- 属性average @1.5
- 测试 dev1和dev2的预计
- 第dev1条的estimate属性 @1
- 第dev2条的estimate属性 @2
*/
include dirname(__FILE__, 5) . '/test/lib/init.php';
@@ -28,4 +32,5 @@ $tester->loadModel('story');
$tester->story->saveEstimateInfo(2);
$storyInfo = $tester->story->getEstimateInfo(2);
r($storyInfo) && p('round,average') && e('2,1.5');
r($storyInfo) && p('story,round,average') && e('2,2,1.5'); // 测试 story的id,圆整值,平均值
r($storyInfo->estimate) && p('dev1:estimate;dev2:estimate') && e('1,2'); // 测试 dev1和dev2的预计
+64
View File
@@ -2021,4 +2021,68 @@ class storyZen extends story
}
return $storyIdList;
}
/**
* 处理过滤条件显示内容。
* Process filter title.
*
* @param string $browseType
* @param int $param
* @access public
* @return string
*/
protected function processFilterTitle(string $browseType, int $param): string
{
$filter = '';
if($browseType != 'bysearch' && $browseType != 'bymodule')
{
$statusName = zget($this->lang->execution->featureBar['story'], $browseType, '');
$filter = sprintf($this->lang->story->report->tpl->feature, $statusName);
if(!$param) return $filter;
}
$fieldParams = array();
$searchConfig = $this->session->executionStorysearchParams;
if($searchConfig) $fieldParams = json_decode($searchConfig['fieldParams'], true);
if($browseType == 'bymodule' && $param)
{
if($filter) $filter .= ', ';
return $filter . sprintf($this->lang->story->report->tpl->search, $this->config->execution->search['fields']['module'], '=', zget($fieldParams['module']['values'], $param));
}
$leftConditions = array();
$rightConditions = array();
$searchFields = $this->session->executionStoryForm;
$fieldNames = json_decode($searchConfig['searchFields']);
if(!$searchFields) return '';
$this->app->loadLang('search');
$groupAndOr = 'and';
$users = $this->loadModel('user')->getPairs('noletter');
foreach($searchFields as $index => $field)
{
if($index == 6) $groupAndOr = $field['groupAndOr'];
if(!isset($field['field'])) continue;
if(isset($field['value']) && $field['value'] === '') continue;
if(!empty($fieldParams[$field['field']]['values']))
{
if($fieldParams[$field['field']]['values'] == 'users') $fieldParams[$field['field']]['values'] = $users;
$field['value'] = zget($fieldParams[$field['field']]['values'], $field['value']);
}
$fieldName = zget($fieldNames, $field['field']);
$operator = zget($this->lang->search->operators, $field['operator']);
if($index == 0 || $index == 3) $field['andOr'] = '';
if($index < 3) $leftConditions[] = zget($this->lang->search->andor, $field['andOr']) . sprintf($this->lang->story->report->tpl->search, $fieldName, $operator, $field['value']);
elseif($index < 6) $rightConditions[] = zget($this->lang->search->andor, $field['andOr']) . sprintf($this->lang->story->report->tpl->search, $fieldName, $operator, $field['value']);
}
if(empty($leftConditions) && empty($rightConditions)) return '';
if(empty($leftConditions)) return implode('', $rightConditions);
if(empty($rightConditions)) return implode('', $leftConditions);
return sprintf($this->lang->story->report->tpl->multi, implode('', $leftConditions), zget($this->lang->search->andor, $groupAndOr), implode('', $rightConditions));
}
}
+47
View File
@@ -15,6 +15,53 @@ title=测试taskModel->batchUpdate();
timeout=0
cid=1
- 检查修改任务名称
- 第1[0]条的old属性 @开发任务11
- 第1[0]条的new属性 @修改1
- 检查修改任务模块
- 第2[0]条的old属性 @0
- 第2[0]条的new属性 @1
- 检查修改任务类型
- 第3[0]条的old属性 @test
- 第3[0]条的new属性 @devel
- 检查修改任务指派人
- 第4[0]条的old属性 @`^$`
- 第4[0]条的new属性 @admin
- 检查修改任务状态
- 第5[0]条的old属性 @wait
- 第5[0]条的new属性 @done
- 检查修改任务开始日期
- 第6[0]条的old属性 @2023-01-02
- 第6[0]条的new属性 @2023-05-25
- 检查修改任务截止日期
- 第7[0]条的old属性 @2023-01-10
- 第7[0]条的new属性 @2023-05-25
- 检查修改任务优先级
- 第8[0]条的old属性 @3
- 第8[0]条的new属性 @1
- 检查修改任务预计工时
- 第9[0]条的old属性 @3
- 第9[0]条的new属性 @1
- 检查修改任务消耗工时
- 第10[0]条的old属性 @0
- 第10[0]条的new属性 @1
- 检查修改任务剩余工时
- 第11[1]条的old属性 @3
- 第11[1]条的new属性 @1
- 检查修改任务完成者
- 第12[1]条的old属性 @`^$`
- 第12[1]条的new属性 @admin
- 检查修改任务关闭者
- 第13[1]条的old属性 @`^$`
- 第13[1]条的new属性 @admin
- 检查任务名称必填项 @『任务名称』不能为空。
- 检查任务类型必填项 @『任务类型』不能为空。
- 检查任务所属模块必填项 @『所属模块』不能为空。
- 检查任务优先级必填项 @『优先级』不能为空。
- 检查任务最初预计必填项 @『最初预计』不能为空。
- 检查任务预计开始必填项 @『预计开始』不能为空。
- 检查任务截止日期必填项 @『截止日期』不能为空。
*/
$taskIdList = range(1, 20);
@@ -10,6 +10,23 @@ title=taskModel->canOperateEffort();
timeout=0
cid=1
- 判断非多人任务 @1
- 判断已完成的串行多人任务并且不判断日志 @0
- 判断已关闭的串行多人任务并且不判断日志 @0
- 判断已取消的串行多人任务并且不判断日志 @0
- 判断已暂停的串行多人任务并且不判断日志 @0
- 判断当前用户不在多人任务团队成员列表中 @0
- 判断串行多人任务的指派给不是当前用户 @0
- 判断串行多人任务的指派给是当前用户 @1
- 判断当前用户在并行多人任务团队成员列表中 @1
- 判断已完成多人任务并且日志创建者和当前用户一致 @1
- 判断已完成多人任务并且日志创建者和当前用户不一致 @0
- 判断已关闭的串行多人任务并且判断日志 @0
- 判断已取消的串行多人任务并且判断日志 @0
- 判断已暂停的串行多人任务并且判断日志 @0
- 判断进行中的串行多人任务并且当前日志创建者不是当前用户 @0
- 判断进行中的串行多人任务并且当前日志创建者是当前用户 @1
*/
$user = new stdclass();
+4 -1
View File
@@ -6,7 +6,10 @@ su('admin');
/**
title=测试记录任务的工时
title=测试taskModel->recordWorkHour();
timeout=0
cid=1
- 任务未开始时记录工时,查看已消耗工时,应该在之前消耗的基础上增加测试设置的消耗值
- 属性field @consumed
- 属性old @3
+94
View File
@@ -2131,4 +2131,98 @@ class taskZen extends task
}
return $parents;
}
/**
* 处理过滤条件显示内容。
* Process filter title.
*
* @param string $browseType
* @param int $param
* @access public
* @return string
*/
public function processFilterTitle(string $browseType, int $param): string
{
if($browseType != 'bysearch' && $browseType != 'bymodule')
{
$statusName = zget($this->lang->execution->featureBar['task'], $browseType, '');
if(empty($statusName)) $statusName = zget($this->lang->execution->statusSelects, $browseType);
return sprintf($this->lang->task->report->tpl->feature, $statusName);
}
$fieldParams = array();
$searchConfig = $this->session->tasksearchParams;
if($searchConfig) $fieldParams = json_decode($searchConfig['fieldParams'], true);
if($browseType == 'bymodule') return sprintf($this->lang->task->report->tpl->search, $this->config->execution->search['fields']['module'], '=', zget($fieldParams['module']['values'], $param));
$leftConditions = array();
$rightConditions = array();
$searchFields = $this->session->taskForm;
$fieldNames = json_decode($searchConfig['searchFields']);
if(!$searchFields) return sprintf($this->lang->task->report->tpl->feature, $this->lang->all);
$this->app->loadLang('search');
$groupAndOr = 'and';
$users = $this->loadModel('user')->getPairs('noletter');
foreach($searchFields as $index => $field)
{
if($index == 6) $groupAndOr = $field['groupAndOr'];
if(!isset($field['field'])) continue;
if(isset($field['value']) && $field['value'] === '') continue;
if(!empty($fieldParams[$field['field']]['values']))
{
if($fieldParams[$field['field']]['values'] == 'users') $fieldParams[$field['field']]['values'] = $users;
$field['value'] = zget($fieldParams[$field['field']]['values'], $field['value']);
}
$fieldName = zget($fieldNames, $field['field']);
$operator = zget($this->lang->search->operators, $field['operator']);
if($index == 0 || $index == 3) $field['andOr'] = '';
if($index < 3) $leftConditions[] = zget($this->lang->search->andor, $field['andOr']) . sprintf($this->lang->task->report->tpl->search, $fieldName, $operator, $field['value']);
elseif($index < 6) $rightConditions[] = zget($this->lang->search->andor, $field['andOr']) . sprintf($this->lang->task->report->tpl->search, $fieldName, $operator, $field['value']);
}
if(empty($leftConditions) && empty($rightConditions)) return sprintf($this->lang->task->report->tpl->feature, $this->lang->all);
if(empty($leftConditions)) return implode('', $rightConditions);
if(empty($rightConditions)) return implode('', $leftConditions);
return sprintf($this->lang->task->report->tpl->multi, implode('', $leftConditions), zget($this->lang->search->andor, $groupAndOr), implode('', $rightConditions));
}
/**
* 获取报表任务列表。
* Get report task list.
*
* @param object $execution
* @param string $browseType
* @param int $param
* @access public
* @return array
*/
public function getReportTaskList(object $execution, string $browseType = '', int $param = 0): array
{
if(!$execution->multiple) unset($this->lang->task->report->charts['tasksPerExecution']);
$this->loadModel('execution')->setMenu($execution->id);
if($this->app->tab == 'project') $this->view->projectID = $execution->project;
$mode = $this->app->tab == 'execution' ? 'multiple' : '';
$executions = $this->execution->getPairs(0, 'all', "nocode,noprefix,{$mode}");
/* Set queryID, moduleID and productID. */
$queryID = $moduleID = $productID = 0;
if($browseType == 'bysearch') $queryID = (int)$param;
if($browseType == 'bymodule') $moduleID = (int)$param;
if($browseType == 'byproduct') $productID = (int)$param;
if($this->app->tab == 'project' && !in_array($browseType, array('bysearch', 'bymodule', 'byproduct')))
{
$moduleID = $this->cookie->moduleBrowseParam ? $this->cookie->moduleBrowseParam : 0;
$productID = $this->cookie->productBrowseParam ? $this->cookie->productBrowseParam : 0;
}
return $this->execution->getTasks((int)$productID, $execution->id, $executions, $browseType, $queryID, (int)$moduleID, 'id_desc');
}
}
File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More