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

This commit is contained in:
刘刚
2025-07-09 08:55:23 +08:00
committed by Gitfox
142 changed files with 1567 additions and 541 deletions
+42 -2
View File
@@ -57,7 +57,7 @@ class baseHelper
if(!is_object(${$objName}) or empty($key)) return false;
$key = str_replace('.', '->', $key);
$value = serialize($value);
$code = ("\$${objName}->{$key}=unserialize(<<<EOT\n$value\nEOT\n);");
$code = ("\${$objName}->{$key}=unserialize(<<<EOT\n$value\nEOT\n);");
eval($code);
return true;
}
@@ -885,7 +885,7 @@ class baseHelper
* @access public
* @return bool
*/
public static function setcookie(string $name, string|int|bool $value = '', int $expire = null, string $path = null, string $domain = '', bool $secure = null, bool $httponly = true)
public static function setcookie(string $name, string|int|bool $value = '', ?int $expire = null, ?string $path = null, string $domain = '', ?bool $secure = null, bool $httponly = true)
{
if(defined('RUN_MODE') && RUN_MODE == 'test')
{
@@ -1488,3 +1488,43 @@ function arrayUnion(...$args): array
}
return $result;
}
/**
* 压缩 ID 列表。
* Compress ID list.
*
* @param string|array $idList
* @access public
* @return string
*/
function compress(string|array $idList): string
{
if(is_string($idList)) $idList = array_filter(explode(',', $idList));
if(!is_array($idList)) return $idList;
$firstID = reset($idList);
if(!is_numeric($firstID) || (float)$firstID != $firstID) return $idList; // If the first ID is not numeric, return the original array.
$idList = array_values($idList);
asort($idList);
$encoded = [$idList[0]];
for($i = 1; $i < count($idList); $i++) $encoded[] = $idList[$i] - $idList[$i-1];
return gzcompress(implode(',', $encoded));
}
/**
* 解压缩 ID 列表。
* Uncompress ID list.
*
* @param string $encoded
* @access public
* @return array
*/
function uncompress(string $encoded): array
{
$decoded = explode(',', gzuncompress($encoded));
for($i = 1; $i < count($decoded); $i++) $decoded[$i] += $decoded[$i-1];
return $decoded;
}
+7 -11
View File
@@ -853,7 +853,7 @@ class baseRouter
*/
public function setDebug()
{
if(!empty($this->config->debug)) error_reporting(E_ALL & ~ E_STRICT);
if(!empty($this->config->debug)) error_reporting(E_ALL);
}
/**
@@ -1229,15 +1229,9 @@ class baseRouter
if(is_writable($savePath))
{
session_save_path($this->getTmpRoot() . 'session');
$ztSessionHandler = new ztSessionHandler();
session_set_save_handler(
array($ztSessionHandler, 'open'),
array($ztSessionHandler, 'close'),
array($ztSessionHandler, 'read'),
array($ztSessionHandler, 'write'),
array($ztSessionHandler, 'destroy'),
array($ztSessionHandler, 'gc')
);
session_set_save_handler($ztSessionHandler, true);
}
}
@@ -3359,7 +3353,7 @@ class baseRouter
}
/* Show non-serious errors to classic page. */
if($level == E_NOTICE or $level == E_WARNING or $level == E_STRICT or $level == 8192)
if($level == E_NOTICE or $level == E_WARNING or $level == 8192)
{
$cmd = "vim +$line $file";
$size = strlen($cmd);
@@ -3596,6 +3590,7 @@ else
*
* @package framework
*/
#[AllowDynamicProperties]
class language
{
/**
@@ -3640,6 +3635,7 @@ class language
*
* @package framework
*/
#[AllowDynamicProperties]
class super
{
/**
@@ -3811,7 +3807,7 @@ class EndResponseException extends \Exception
*
* @package framework
*/
class ztSessionHandler
class ztSessionHandler implements SessionHandlerInterface
{
public $sessSavePath;
public $sessionFile;
+5 -3
View File
@@ -18,6 +18,8 @@
* @package framework
*/
include __DIR__ . '/base/control.class.php';
#[AllowDynamicProperties]
class control extends baseControl
{
/**
@@ -515,7 +517,7 @@ class control extends baseControl
* @access public
* @return zin\fieldList
*/
public function appendExtendFields(zin\fieldList $fields, string $moduleName = '', string $methodName = '', object $object = null): zin\fieldList
public function appendExtendFields(zin\fieldList $fields, string $moduleName = '', string $methodName = '', ?object $object = null): zin\fieldList
{
if($this->config->edition == 'open') return $fields;
if(!empty($this->app->installing) || !empty($this->app->upgrading)) return $fields;
@@ -557,7 +559,7 @@ class control extends baseControl
* @access public
* @return string
*/
public function appendExtendCssAndJS(string $moduleName = '', string $methodName = '', object $object = null): string
public function appendExtendCssAndJS(string $moduleName = '', string $methodName = '', ?object $object = null): string
{
if($this->config->edition == 'open') return '';
if(!empty($this->app->installing) || !empty($this->app->upgrading)) return '';
@@ -598,7 +600,7 @@ class control extends baseControl
* @access public
* @return array
*/
public function appendExtendForm(string $position = 'info', object $object = null, string $moduleName = '', string $methodName = ''): array
public function appendExtendForm(string $position = 'info', ?object $object = null, string $moduleName = '', string $methodName = ''): array
{
if($this->config->edition == 'open') return array();
if(!empty($this->app->installing) || !empty($this->app->upgrading)) return array();
+1 -1
View File
@@ -509,7 +509,7 @@ function initPageEntity(object $object): array
* @access public
* @return array
*/
function initTableData(array $items, array &$fieldList, object $model = null, string $moduleName = ''): array
function initTableData(array $items, array &$fieldList, ?object $model = null, string $moduleName = ''): array
{
if(!empty($_GET['orderBy']) && strpos($_GET['orderBy'], '-') !== false) list($orderField, $orderValue) = explode('_', $_GET['orderBy']);
if(!empty($orderField) && !empty($orderValue) && !empty($fieldList[$orderField]))
+2
View File
@@ -18,6 +18,8 @@
* @package framework
*/
include __DIR__ . '/base/model.class.php';
#[AllowDynamicProperties]
class model extends baseModel
{
/**
+3
View File
@@ -18,6 +18,9 @@
* @package framework
*/
include __DIR__ . '/base/router.class.php';
#[AllowDynamicProperties]
class router extends baseRouter
{
/**
+1 -1
View File
@@ -441,7 +441,7 @@ class baseDAO
* @access public
* @return void
*/
public function setCache($key, $sql = '', $value = null, int $ttl = null)
public function setCache($key, $sql = '', $value = null, ?int $ttl = null)
{
if(!$this->app->isServing() || empty($this->cache)) return false;
+9
View File
@@ -50,6 +50,15 @@ class cache
*/
private $dao;
/**
* 全局数据库操作句柄。
* Global database operation handler.
*
* @access private
* @var object
*/
private $dbh;
/**
* 全局配置对象。
* Global configuration object.
+2 -2
View File
@@ -68,7 +68,7 @@ class form extends fixer
* @param int $objectID
* @return form
*/
public static function data(array $configObject = null, int $objectID = 0): form
public static function data(?array $configObject = null, int $objectID = 0): form
{
global $app, $config;
@@ -85,7 +85,7 @@ class form extends fixer
* @param array|null $configObject
* @return form
*/
public static function batchData(array $configObject = null): form
public static function batchData(?array $configObject = null): form
{
global $app, $config;
+7
View File
@@ -7,6 +7,13 @@
*/
class pinyin
{
/**
* Segments.
* @var array
*
*/
protected array $segments = array();
/**
* Constructor.
*
-2
View File
@@ -17,8 +17,6 @@ require_once __DIR__ . DS . 'zin.func.php';
class item extends node
{
public bool $notRenderInGlobal = true;
public function build(): array|node|directive
{
if($this->parent instanceof node && method_exists($this->parent, 'onBuildItem'))
+8
View File
@@ -47,6 +47,14 @@ class jsCallback extends jsHelper
*/
public bool $isArrowFunc = false;
/**
* Parent node
*
* @access public
* @var node
*/
public $parent = null;
/**
* 构造函数。
*
+2
View File
@@ -57,6 +57,8 @@ class node implements \JsonSerializable
public array $eventBindings = array();
public ?bool $notRenderInGlobal = null;
public function __construct(mixed ...$args)
{
$this->gid = static::nextGid();
+10 -2
View File
@@ -25,6 +25,14 @@ class dataset implements \JsonSerializable
*/
protected array $storedData = array();
/**
* Parent node
*
* @access public
* @var node
*/
public $parent = null;
/**
* Create an instance, the initialed data can be passed.
*
@@ -32,7 +40,7 @@ class dataset implements \JsonSerializable
* @param array|object|string $data Properties list array.
* @param mixed $value Property value.
*/
public function __construct(array|string $data = null, mixed $value = null)
public function __construct($data = null, $value = null)
{
if($data !== null) $this->set($data, $value);
}
@@ -191,7 +199,7 @@ class dataset implements \JsonSerializable
* @param mixed $defaultValue Optional default value if actual value is null.
* @return mixed
*/
public function get(string|array $prop = null, mixed $defaultValue = null): mixed
public function get($prop = null, mixed $defaultValue = null): mixed
{
if(is_null($prop)) return $this->storedData;
+6 -6
View File
@@ -140,12 +140,12 @@ class docApp extends wg
{
$menu = array();
$menu['text'] = $item['name'];
$menu['icon'] = $item['icon'];
$menu['module'] = $item['module'];
$menu['method'] = $item['method'];
$menu['params'] = $item['params'];
$menu['priv'] = $item['priv'];
if(isset($item['name'])) $menu['text'] = $item['name'];
if(isset($item['icon'])) $menu['icon'] = $item['icon'];
if(isset($item['module'])) $menu['module'] = $item['module'];
if(isset($item['method'])) $menu['method'] = $item['method'];
if(isset($item['params'])) $menu['params'] = $item['params'];
if(isset($item['priv'])) $menu['priv'] = $item['priv'];
if(isset($item['subMenu']))
{
+7 -5
View File
@@ -31,14 +31,15 @@ class editor extends wg
);
protected static string $css = <<<CSS
.editor {border: unset; border-radius: unset;}
.editor {border: unset; border-radius: unset; color: var(--color-fore)}
.editor.size-auto {min-height: 0;}
zen-editor-menu-item > .menu-item {color: #9ea3b0!important;}
zen-editor-menu-item > .menu-item:hover {color: var(--color-primary-400)!important; background-color: var(--color-gray-200)!important;}
zen-editor-menu-item {display: inline-flex; align-items: center;}
zen-editor-menu-item > .menu-item {color: #64758B!important; display: inline-flex; align-items: center;}
zen-editor-menu-item > .menu-item:hover {color: var(--color-primary-400)!important; background-color: var(--color-gray-100)!important;}
zen-editor-menu-item > .menu-item.is-active {color: var(--color-primary-400)!important; background-color: transparent!important; box-shadow: inset 0 0 0 1px var(--color-primary-300);}
zen-editor-menu-item > .menu-item.is-active:hover {background-color: var(--color-gray-200)!important;}
zen-editor-menu-item > .menu-item.is-active:not(:hover) {background-color: transparent!important;}
zen-editor-menu-item > .menu-item:has(.color):hover, zen-editor-menu-item > .menu-item:has(.color).is-active {background-color: transparent!important; box-shadow: inset 0 0 0 1px var(--color-primary-300)!important;}
zen-editor-menu-item > .menu-item:has(.color):hover, zen-editor-menu-item > .menu-item:has(.color).is-active {background-color: ransparent!important; box-shadow: inset 0 0 0 1px var(--color-primary-300)!important;}
.menubar {border-bottom: 1px solid #d8dbde!important; padding: 0.125rem;}
.tippy-content > div {border: 1px solid #d8dbde!important;}
.tippy-content zen-editor-menu-item {line-height: normal;}
@@ -94,7 +95,7 @@ class editor extends wg
protected function build()
{
global $lang;
global $lang, $app;
$editor = new h
(
@@ -115,6 +116,7 @@ class editor extends wg
$editor->add(set($customProps));
$editor->add(set('css', self::$css)); // Inject CSS into editor.
$editor->add(set('css-src', $app->getWebRoot() . 'js/zui3/zen-editor/zui-inject-style.css')); // Inject CSS on page, for tippy menus.
$editor->add(h('article', set('slot', 'content'), html($this->prop('value')), $this->children())); // Set initial content.
$templateType = $this->prop('templateType');
+2
View File
@@ -4,6 +4,8 @@ namespace zin;
class floatToolbar extends wg
{
protected ?object $object = null;
protected static array $defineProps = array(
'prefix?:array',
'main?:array',
-2
View File
@@ -22,8 +22,6 @@ class field extends setting
{
public ?fieldList $fieldList;
public ?field $parent;
public ?string $dataType;
public mixed $default;
+4 -4
View File
@@ -285,7 +285,7 @@ class actionModel extends model
* @access public
* @return object
*/
public function processHistory(object $history = null): object
public function processHistory(?object $history = null): object
{
if(empty($history)) return $history;
$users = $this->loadModel('user')->getPairs('noletter');
@@ -433,7 +433,7 @@ class actionModel extends model
* @access public
* @return array
*/
public function getTrashes(string $objectType, string $type, string $orderBy, object $pager = null): array
public function getTrashes(string $objectType, string $type, string $orderBy, ?object $pager = null): array
{
$noMultipleExecutions = $this->dao->select('id')->from(TABLE_EXECUTION)->where('multiple')->eq('0')->andWhere('type')->in('sprint,kanban')->fetchPairs();
@@ -534,7 +534,7 @@ class actionModel extends model
* @access public
* @return array
*/
public function getTrashesBySearch(string $objectType, string $type, string|int $queryID, string $orderBy, object $pager = null): array
public function getTrashesBySearch(string $objectType, string $type, string|int $queryID, string $orderBy, ?object $pager = null): array
{
if($objectType == 'all') return array();
if($queryID && $queryID != 'myQueryID')
@@ -955,7 +955,7 @@ class actionModel extends model
* @access public
* @return array
*/
public function buildActionList(array $actions, array|null $users = null, bool $commentEditable = true): array
public function buildActionList(array $actions, ?array $users = null, bool $commentEditable = true): array
{
if(empty($users)) $users = $this->loadModel('user')->getPairs('noletter');
+10 -10
View File
@@ -1,12 +1,12 @@
<?php
$config->admin->metricLib = new stdClass();
$config->admin->metricLib->updateSQLs[1] = 'CREATE INDEX IF NOT EXISTS `metricCode_system_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `system`, `date`)';
$config->admin->metricLib->updateSQLs[2] = 'CREATE INDEX IF NOT EXISTS `metricCode_program_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `program`, `date`)';
$config->admin->metricLib->updateSQLs[3] = 'CREATE INDEX IF NOT EXISTS `metricCode_project_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `project`, `date`)';
$config->admin->metricLib->updateSQLs[4] = 'CREATE INDEX IF NOT EXISTS `metricCode_product_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `product`, `date`)';
$config->admin->metricLib->updateSQLs[5] = 'CREATE INDEX IF NOT EXISTS `metricCode_execution_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `execution`, `date`)';
$config->admin->metricLib->updateSQLs[6] = 'CREATE INDEX IF NOT EXISTS `metricCode_user_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `user`(30), `date`)';
$config->admin->metricLib->updateSQLs[7] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX IF EXISTS `metricID`';
$config->admin->metricLib->updateSQLs[8] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX IF EXISTS `metricCode`';
$config->admin->metricLib->updateSQLs[9] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX IF EXISTS `date`';
$config->admin->metricLib->updateSQLs[10] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX IF EXISTS `deleted`';
$config->admin->metricLib->updateSQLs[1] = 'CREATE INDEX `metricCode_system_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `system`, `date`)';
$config->admin->metricLib->updateSQLs[2] = 'CREATE INDEX `metricCode_program_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `program`, `date`)';
$config->admin->metricLib->updateSQLs[3] = 'CREATE INDEX `metricCode_project_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `project`, `date`)';
$config->admin->metricLib->updateSQLs[4] = 'CREATE INDEX `metricCode_product_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `product`, `date`)';
$config->admin->metricLib->updateSQLs[5] = 'CREATE INDEX `metricCode_execution_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `execution`, `date`)';
$config->admin->metricLib->updateSQLs[6] = 'CREATE INDEX `metricCode_user_date` ON ' . TABLE_METRICLIB . ' (`metricCode`, `user`(30), `date`)';
$config->admin->metricLib->updateSQLs[7] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX `metricID`';
$config->admin->metricLib->updateSQLs[8] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX `metricCode`';
$config->admin->metricLib->updateSQLs[9] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX `date`';
$config->admin->metricLib->updateSQLs[10] = 'ALTER TABLE ' . TABLE_METRICLIB . ' DROP INDEX `deleted`';
+3 -4
View File
@@ -373,14 +373,13 @@ class admin extends control
try
{
$this->dbh->exec($sql);
if(isset($this->config->admin->metricLib->updateSQLs[++$key])) return $this->send(['result' => 'success', 'key' => $key]);
return $this->send(['result' => 'success']);
}
catch(PDOException $e)
{
return $this->sendError($e->getMessage());
$this->app->triggerError($e->getMessage(), __FILE__, __LINE__);
}
if(isset($this->config->admin->metricLib->updateSQLs[++$key])) return $this->send(['result' => 'success', 'key' => $key]);
return $this->send(['result' => 'success']);
}
$this->view->title = $this->lang->metriclib->common;
+4 -4
View File
@@ -390,7 +390,7 @@ class apiModel extends model
* @param object $pager
* @return array
*/
public function getListByModuleID(int $libID = 0, int $moduleID = 0, int $releaseID = 0, object $pager = null): array
public function getListByModuleID(int $libID = 0, int $moduleID = 0, int $releaseID = 0, ?object $pager = null): array
{
/* Get release info. */
if($releaseID > 0)
@@ -472,7 +472,7 @@ class apiModel extends model
* @access public
* @return array
*/
public function getStructByQuery(int $libID, object $pager = null, string $orderBy = ''): array
public function getStructByQuery(int $libID, ?object $pager = null, string $orderBy = ''): array
{
return $this->dao->select('t1.*,t2.realname as addedName')->from(TABLE_APISTRUCT)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')->on('t2.account = t1.addedBy')
@@ -494,7 +494,7 @@ class apiModel extends model
* @access public
* @return array
*/
public function getStructListByRelease(object $release, string $where = '1 = 1 ', object $pager = null, string $orderBy = 'id'): array
public function getStructListByRelease(object $release, string $where = '1 = 1 ', ?object $pager = null, string $orderBy = 'id'): array
{
$strJoin = array();
if(isset($release->snap['structs']))
@@ -527,7 +527,7 @@ class apiModel extends model
* @access public
* @return array
*/
public function getReleaseByQuery(array $libID, object $pager = null, string $orderBy = ''): array
public function getReleaseByQuery(array $libID, ?object $pager = null, string $orderBy = ''): array
{
return $this->dao->select('*')->from(TABLE_API_LIB_RELEASE)
->where('lib')->in($libID)
+5 -3
View File
@@ -330,9 +330,11 @@ $config->block->size['scrumproject']['projectdynamic'] = array(1 => 8, 2 => 8);
$config->block->size['waterfallproject']['waterfallgantt'] = array(2 => 8, 1 => 8);
$config->block->size['waterfallproject']['projectdynamic'] = array(1 => 8, 2 => 8);
$config->block->size['agileplusproject'] = $config->block->size['scrumproject'];
$config->block->size['waterfallplusproject'] = $config->block->size['waterfallproject'];
$config->block->size['ipdproject'] = $config->block->size['waterfallproject'];
/* 旗舰版和IPD版本,敏捷项目和瀑布项目都新增了区块,融合敏捷项目的区块和敏捷项目的区块保持一致,融合瀑布项目和IPD项目的区块和瀑布项目的区块保持一致 。*/
/* In the max and IPD versions, new blocks are added for scrum project and waterfall project. The blocks for agile plus project are consistent with scrum project, and the blocks for waterfall plus and IPD project are consistent with waterfall project. */
$config->block->size['agileplusproject'] = &$config->block->size['scrumproject'];
$config->block->size['waterfallplusproject'] = &$config->block->size['waterfallproject'];
$config->block->size['ipdproject'] = &$config->block->size['waterfallproject'];
$config->block->size['execution']['overview'] = array(1 => 3);
$config->block->size['execution']['statistic'] = array(2 => 5, 1 => 8);
+2 -2
View File
@@ -2471,7 +2471,7 @@ class blockZen extends block
$involveds = $this->product->getOrderedProducts('involved', 0, 0, 'all');
$productIdList = array_merge(array_keys($products), array_keys($involveds));
$stmt = $this->dao->select('id,product,lib,title,type,addedBy,addedDate,editedDate,status,acl,groups,readGroups,users,readUsers,deleted')->from(TABLE_DOC)->alias('t1')
$stmt = $this->dao->select('id,product,lib,title,type,addedBy,addedDate,editedDate,status,acl,`groups`,readGroups,users,readUsers,deleted')->from(TABLE_DOC)->alias('t1')
->where('deleted')->eq(0)
->andWhere('product')->in($productIdList)
->beginIF($this->config->doc->notArticleType)->andWhere('t1.type')->notIN($this->config->doc->notArticleType)->fi()
@@ -3499,7 +3499,7 @@ class blockZen extends block
* @access protected
* @return object
*/
protected function buildProjectStatistic(object $project, array $data, object $pager = null): object
protected function buildProjectStatistic(object $project, array $data, ?object $pager = null): object
{
extract($data);
$projectID = $project->id;
+1 -1
View File
@@ -53,7 +53,7 @@ class branchModel extends model
* @access public
* @return array
*/
public function getList(int $productID, int $executionID = 0, string $browseType = 'active', string $orderBy = 'order', object|null $pager = null, bool $withMainBranch = true): array
public function getList(int $productID, int $executionID = 0, string $browseType = 'active', string $orderBy = 'order', ?object $pager = null, bool $withMainBranch = true): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getBranches();
+11 -11
View File
@@ -97,7 +97,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getList(string $browseType, array $productIdList, int $projectID, array $executionIdList, int|string $branch = 'all', int $moduleID = 0, int $queryID = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getList(string $browseType, array $productIdList, int $projectID, array $executionIdList, int|string $branch = 'all', int $moduleID = 0, int $queryID = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
if($browseType == 'bymodule' && $this->session->bugBrowseType && $this->session->bugBrowseType != 'bysearch') $browseType = $this->session->bugBrowseType;
@@ -125,7 +125,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getPlanBugs(int $planID, string $status = 'all', string $orderBy = 'id_desc', object $pager = null): array
public function getPlanBugs(int $planID, string $status = 'all', string $orderBy = 'id_desc', ?object $pager = null): array
{
if(common::isTutorialMode()) return array();
@@ -216,7 +216,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getActiveBugs(array|int $products, int|string $branch, string $executions, array $excludeBugs, object $pager = null, string $orderBy = 'id desc'): array
public function getActiveBugs(array|int $products, int|string $branch, string $executions, array $excludeBugs, ?object $pager = null, string $orderBy = 'id desc'): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getBugs();
@@ -244,7 +244,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getActiveAndPostponedBugs(array $products, int $executionID, object $pager = null): array
public function getActiveAndPostponedBugs(array $products, int $executionID, ?object $pager = null): array
{
return $this->dao->select('t1.*')->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_PROJECTPRODUCT)->alias('t2')->on('t1.product = t2.product')
@@ -670,7 +670,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getBugs2Link(int $bugID, bool $bySearch = false, string $excludeBugs = '', int $queryID = 0, object $pager = null): array
public function getBugs2Link(int $bugID, bool $bySearch = false, string $excludeBugs = '', int $queryID = 0, ?object $pager = null): array
{
$bug = $this->getByID($bugID);
@@ -861,7 +861,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getUserBugs(string $account, string $type = 'assignedTo', string $orderBy = 'id_desc', int $limit = 0, object $pager = null, int $executionID = 0, int $queryID = 0): array
public function getUserBugs(string $account, string $type = 'assignedTo', string $orderBy = 'id_desc', int $limit = 0, ?object $pager = null, int $executionID = 0, int $queryID = 0): array
{
if($type != 'bySearch' and !$this->loadModel('common')->checkField(TABLE_BUG, $type)) return array();
@@ -974,7 +974,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getProjectBugs(int $projectID, int $productID = 0, int|string $branchID = 0, int $build = 0, string $type = '', int $param = 0, string $orderBy = 'id_desc', string $excludeBugs = '', object $pager = null): array
public function getProjectBugs(int $projectID, int $productID = 0, int|string $branchID = 0, int $build = 0, string $type = '', int $param = 0, string $orderBy = 'id_desc', string $excludeBugs = '', ?object $pager = null): array
{
if(strpos($orderBy, 'pri_') !== false) $orderBy = str_replace('pri_', 'priOrder_', $orderBy);
if(strpos($orderBy, 'severity_') !== false) $orderBy = str_replace('severity_', 'severityOrder_', $orderBy);
@@ -1026,7 +1026,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getExecutionBugs(int $executionID, int $productID = 0, string|int $branchID = 'all', string|array $builds = '0', string $type = '', int $param = 0, string $orderBy = 'id_desc', string $excludeBugs = '', object $pager = null): array
public function getExecutionBugs(int $executionID, int $productID = 0, string|int $branchID = 'all', string|array $builds = '0', string $type = '', int $param = 0, string $orderBy = 'id_desc', string $excludeBugs = '', ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getBugs();
@@ -1088,7 +1088,7 @@ class bugModel extends model
* @access public
* @return array|null
*/
public function getProductLeftBugs(array $buildIdList, int $productID, int|string $branch = '', string $linkedBugs = '', object $pager = null): array|null
public function getProductLeftBugs(array $buildIdList, int $productID, int|string $branch = '', string $linkedBugs = '', ?object $pager = null): array|null
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getBugs();
@@ -1202,7 +1202,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getReleaseBugs(array $buildIdList, int $productID, int|string $branch = 0, string $linkedBugs = '', object $pager = null): array
public function getReleaseBugs(array $buildIdList, int $productID, int|string $branch = 0, string $linkedBugs = '', ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getBugs();
@@ -2143,7 +2143,7 @@ class bugModel extends model
* @access public
* @return array
*/
public function getBySearch(string $object = 'bug', array|int $productIdList = array(), int|string $branch = 0, int $projectID = 0, int $executionID = 0, int $queryID = 0, string $excludeBugs = '', string $orderBy = '', object $pager = null): array
public function getBySearch(string $object = 'bug', array|int $productIdList = array(), int|string $branch = 0, int $projectID = 0, int $executionID = 0, int $queryID = 0, string $excludeBugs = '', string $orderBy = '', ?object $pager = null): array
{
$bugQuery = $this->processSearchQuery($object, $queryID, $productIdList, (string)$branch);
+2 -2
View File
@@ -38,7 +38,7 @@ class bugTao extends bugModel
* @access protected
* @return array
*/
protected function getListByBrowseType(string $browseType, array $productIdList, int $projectID, array $executionIdList, int|string $branch, array $moduleIdList, int $queryID, string $orderBy, object $pager = null): array
protected function getListByBrowseType(string $browseType, array $productIdList, int $projectID, array $executionIdList, int|string $branch, array $moduleIdList, int $queryID, string $orderBy, ?object $pager = null): array
{
$browseType = strtolower($browseType);
@@ -112,7 +112,7 @@ class bugTao extends bugModel
* @access protected
* @return array
*/
protected function getNeedConfirmList(array $productIdList, int $projectID, array $executionIdList, int|string $branch, array $moduleIdList, string $orderBy, object $pager = null): array
protected function getNeedConfirmList(array $productIdList, int $projectID, array $executionIdList, int|string $branch, array $moduleIdList, string $orderBy, ?object $pager = null): array
{
return $this->dao->select("t1.*, t2.title AS storyTitle, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) AS priOrder, IF(t1.`severity` = 0, {$this->config->maxPriValue}, t1.`severity`) AS severityOrder")->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story = t2.id')
+12 -27
View File
@@ -15,42 +15,27 @@ title=bugModel->getActiveBugs();
timeout=0
cid=1
- 测试获取产品 1 2 3 类型 空 开始日期 上月 结束日期 下月 的bug @2,5,6,9
- 查询产品1 2 3 不存在的产品1000001下 且不排除bug的bug @BUG9,bug8,缺陷!()(){}|+=%^&*$#测试bug名称到底可以有多长!#¥%&*":.<>。?/();7,BUG6,BUG5,BUG4,BUG3,BUG2,BUG1
- 测试获取产品 1 2 3 类型 空 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 1 2 3 类型 resolved 开始日期 上月 结束日期 下月 的bug @5,6,9
- 查询产品1 2 3 不存在的产品1000001下 且排除bug2的bug @BUG9,bug8,缺陷!()(){}|+=%^&*$#测试bug名称到底可以有多长!#¥%&*":.<>。?/();7,BUG6,BUG5,BUG4,BUG3,BUG1
- 测试获取产品 1 2 3 类型 resolved 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 1 2 3 类型 opened 开始日期 上月 结束日期 下月 的bug @2,5,6,9
- 查询产品1 2 3 不存在的产品1000001下 且排除bug3 8的bug @BUG9,缺陷!()(){}|+=%^&*$#测试bug名称到底可以有多长!#¥%&*":.<>。?/();7,BUG6,BUG5,BUG4,BUG2,BUG1
- 测试获取产品 1 2 3 类型 opened 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 4 5 6 类型 空 开始日期 上月 结束日期 下月 的bug @10,13,14,17,18
- 查询产品1 3下 且不排除bug的bug @BUG9,bug8,缺陷!()(){}|+=%^&*$#测试bug名称到底可以有多长!#¥%&*":.<>。?/();7,BUG3,BUG2,BUG1
- 测试获取产品 4 5 6 类型 空 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 4 5 6 类型 resolved 开始日期 上月 结束日期 下月 的bug @10,13,14,17,18
- 查询产品1 3下 且排除bug2的bug @BUG9,bug8,缺陷!()(){}|+=%^&*$#测试bug名称到底可以有多长!#¥%&*":.<>。?/();7,BUG3,BUG1
- 测试获取产品 4 5 6 类型 resolved 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 4 5 6 类型 opened 开始日期 上月 结束日期 下月 的bug @10,13,14,17,18
- 查询产品1 3下 且排除bug3 8的bug @BUG9,缺陷!()(){}|+=%^&*$#测试bug名称到底可以有多长!#¥%&*":.<>。?/();7,BUG2,BUG1
- 测试获取产品 4 5 6 类型 opened 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 7 8 9 类型 空 开始日期 上月 结束日期 下月 的bug @21,22,25,26
- 查询产品1下 且不排除bug的bug @BUG3,BUG2,BUG1
- 测试获取产品 7 8 9 类型 空 开始日期 上周 结束日期 下周 的bug @25,26
- 查询产品1下 且排除bug2的bug @BUG3,BUG1
- 测试获取产品 7 8 9 类型 resolved 开始日期 上月 结束日期 下月 的bug @21,22,25,26
- 查询产品1下 且排除bug3 8的bug @BUG2,BUG1
- 测试获取产品 7 8 9 类型 resolved 开始日期 上周 结束日期 下周 的bug @25,26
- 测试获取产品 7 8 9 类型 opened 开始日期 上月 结束日期 下月 的bug @21,22,25,26
- 测试获取产品 7 8 9 类型 opened 开始日期 上周 结束日期 下周 的bug @25,26
- 测试获取产品 空 类型 空 开始日期 上月 结束日期 下月 的bug @0
- 测试获取产品 空 类型 空 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 空 类型 resolved 开始日期 上月 结束日期 下月 的bug @0
- 测试获取产品 空 类型 resolved 开始日期 上周 结束日期 下周 的bug @0
- 测试获取产品 空 类型 opened 开始日期 上月 结束日期 下月 的bug @0
- 测试获取产品 空 类型 opened 开始日期 上周 结束日期 下周 的bug @0
- 查询不存在的产品1000001下 且不排除bug的bug @0
- 查询不存在的产品1000001下 且排除bug2的bug @0
- 查询不存在的产品1000001下 且排除bug3 8的bug @0
*/
+6 -6
View File
@@ -74,7 +74,7 @@ class buildModel extends model
* @access public
* @return array
*/
public function getProjectBuilds(int $projectID = 0, string $type = 'all', string $param = '', string $orderBy = 't1.date_desc,t1.id_desc', object $pager = null): array
public function getProjectBuilds(int $projectID = 0, string $type = 'all', string $param = '', string $orderBy = 't1.date_desc,t1.id_desc', ?object $pager = null): array
{
$shadows = $this->dao->select('shadow')->from(TABLE_RELEASE)->where("FIND_IN_SET({$projectID}, project)")->fetchPairs('shadow', 'shadow');
$builds = $this->dao->select('t1.*, t2.name as productName')
@@ -129,7 +129,7 @@ class buildModel extends model
* @access public
* @return array
*/
public function getProjectBuildsBySearch(int $projectID, int $queryID, string $orderBy = 't1.date_desc,t1.id_desc', object $pager = null): array
public function getProjectBuildsBySearch(int $projectID, int $queryID, string $orderBy = 't1.date_desc,t1.id_desc', ?object $pager = null): array
{
/* If there are saved query conditions, reset the session. */
if((int)$queryID)
@@ -170,7 +170,7 @@ class buildModel extends model
* @access public
* @return array
*/
public function getExecutionBuilds(int $executionID, string $type = '', string $param = '', string $orderBy = 't1.date_desc,t1.id_desc', object $pager = null): array
public function getExecutionBuilds(int $executionID, string $type = '', string $param = '', string $orderBy = 't1.date_desc,t1.id_desc', ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getBuilds();
@@ -198,7 +198,7 @@ class buildModel extends model
* @access public
* @return object[]
*/
public function getExecutionBuildsBySearch(int $executionID, int $queryID, object $pager = null): array
public function getExecutionBuildsBySearch(int $executionID, int $queryID, ?object $pager = null): array
{
/* If there are saved query conditions, reset the session. */
if($queryID)
@@ -896,7 +896,7 @@ class buildModel extends model
* @access public
* @return array
*/
public function getBugList(string $bugIdList, string $orderBy = '', object $pager = null): array
public function getBugList(string $bugIdList, string $orderBy = '', ?object $pager = null): array
{
return $this->dao->select('*')->from(TABLE_BUG)
->where('id')->in($bugIdList)
@@ -916,7 +916,7 @@ class buildModel extends model
* @access public
* @return array
*/
public function getStoryList(string $storyIdList, int $branch = 0, string $orderBy = '', object $pager = null): array
public function getStoryList(string $storyIdList, int $branch = 0, string $orderBy = '', ?object $pager = null): array
{
$stories = $this->dao->select("*, IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder")->from(TABLE_STORY)
->where('id')->in($storyIdList)
+3 -3
View File
@@ -152,7 +152,7 @@ class caselibModel extends model
* @access public
* @return array
*/
public function getList(string $type = 'all', string $orderBy = 'id_desc', object $pager = null): array
public function getList(string $type = 'all', string $orderBy = 'id_desc', ?object $pager = null): array
{
return $this->dao->select('*')->from(TABLE_TESTSUITE)
->where('product')->eq(0)
@@ -174,7 +174,7 @@ class caselibModel extends model
* @access public
* @return array
*/
public function getPairs(string $type = 'all', string $orderBy = 'id_desc', object $pager = null): array
public function getPairs(string $type = 'all', string $orderBy = 'id_desc', ?object $pager = null): array
{
return $this->dao->select('id,name')->from(TABLE_TESTSUITE)
->where('product')->eq(0)
@@ -227,7 +227,7 @@ class caselibModel extends model
* @access public
* @return array
*/
public function getLibCases(int $libID, string $browseType, int $queryID = 0, int $moduleID = 0, string $sort = 'id_desc', object $pager = null, string $from = 'qa'): array
public function getLibCases(int $libID, string $browseType, int $queryID = 0, int $moduleID = 0, string $sort = 'id_desc', ?object $pager = null, string $from = 'qa'): array
{
$browseType = $browseType == 'bymodule' && $this->session->libBrowseType && $this->session->libBrowseType != 'bysearch' ? $this->session->libBrowseType : $browseType;
+1 -1
View File
@@ -47,7 +47,7 @@ class cneModel extends model
* @access public
* @return bool
*/
public function updateConfig(object $instance, object $settings = null): bool
public function updateConfig(object $instance, ?object $settings = null): bool
{
$apiParams = array();
$apiParams['cluster'] = '';
+6 -6
View File
@@ -1303,7 +1303,7 @@ eof;
* @access public
* @return bool
*/
public static function hasPriv(string $module, string $method, mixed $object = null, string $vars = '')
public static function hasPriv(string $module, string $method, $object = null, string $vars = '')
{
/* If the user is doing a tutorial, have all privileges. */
if(commonModel::isTutorialMode()) return true;
@@ -1347,7 +1347,7 @@ eof;
* @access public
* @return bool
*/
public static function getUserPriv(string $module, string $method, mixed $object = null, string $vars = ''): bool
public static function getUserPriv(string $module, string $method, $object = null, string $vars = ''): bool
{
global $app,$config;
$module = strtolower($module);
@@ -1846,7 +1846,7 @@ eof;
* @access public
* @return bool
*/
public static function canBeChanged(string $module, mixed $object = null): bool
public static function canBeChanged(string $module, $object = null): bool
{
if(defined('RUN_MODE') && RUN_MODE == 'api') return true;
@@ -1980,7 +1980,7 @@ eof;
* @access public
* @return string|array|bool
*/
public static function http(string $url, string|array|object|null $data = null, array $options = array(), array $headers = array(), string $dataType = 'data', string $method = 'POST', int $timeout = 30, bool $httpCode = false, bool $log = true): string|array|bool
public static function http(string $url, mixed $data = null, array $options = array(), array $headers = array(), string $dataType = 'data', string $method = 'POST', int $timeout = 30, bool $httpCode = false, bool $log = true): string|array|bool
{
global $lang, $app;
@@ -2469,7 +2469,7 @@ eof;
* @access public
* @return void
*/
public static function buildActionItem(string $module, string $method, string $params, object|null $object = null, array $attrs = array()): array
public static function buildActionItem(string $module, string $method, string $params, ?object $object = null, array $attrs = array()): array
{
if(!commonModel::hasPriv($module, $method, $object)) return array();
@@ -3819,7 +3819,7 @@ eof;
* @access public
* @return mixed
*/
public static function printCommentIcon(string $commentFormLink, object $object = null)
public static function printCommentIcon(string $commentFormLink, ?object $object = null)
{
global $lang;
+1 -1
View File
@@ -51,7 +51,7 @@ class companyModel extends model
* @access public
* @return array
*/
public function getUsers(string $browseType = 'inside', string $type = '', string|int $queryID = 0, int $deptID = 0, string $sort = '', object $pager = null): array
public function getUsers(string $browseType = 'inside', string $type = '', string|int $queryID = 0, int $deptID = 0, string $sort = '', ?object $pager = null): array
{
if($type == 'bydept')
{
+1 -1
View File
@@ -54,7 +54,7 @@ class compileModel extends model
* @access public
* @return array
*/
public function getList(int $repoID, int $jobID, string $browseType = '', int $queryID = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getList(int $repoID, int $jobID, string $browseType = '', int $queryID = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
$compileQuery = '';
if($browseType == 'bySearch')
+11 -3
View File
@@ -40,9 +40,17 @@ cid=1
*/
global $lang;
$lang->SRCommon = '研发需求';
$lang->URCommon = '用户需求';
global $lang, $app, $config;
$lang->SRCommon = '研发需求';
$lang->URCommon = '用户需求';
$config->edition = 'open';
$app::$loadedLangs = array();
include($app->getModuleRoot() . '/story/control.php');
$app->control = new story();
$app->loadLang('custom');
$app->control->loadModel('task');
$app->control->loadModel('story');
$datatable = new datatableTest();
r($datatable->getSettingTest('product', 'browse')) && p('id:title;id:width;title:title;title:width') && e('ID,80,研发需求名称,0.44'); //获取产品模块browse方法自定义列
+1 -1
View File
@@ -335,7 +335,7 @@ class deptModel extends model
* @access public
* @return array
*/
public function getUsers(string $browseType = 'inside', array $depts = array(), string $orderBy = 'id', object $pager = null): array
public function getUsers(string $browseType = 'inside', array $depts = array(), string $orderBy = 'id', ?object $pager = null): array
{
return $this->dao->select('*')->from(TABLE_USER)
->where('deleted')->eq(0)
+6 -6
View File
@@ -91,7 +91,7 @@ class designModel extends model
* @access public
* @return bool|array
*/
public function update(int $designID = 0, object $design = null): bool|array
public function update(int $designID = 0, ?object $design = null): bool|array
{
$oldDesign = $this->getByID($designID);
if(!$oldDesign) return false;
@@ -135,7 +135,7 @@ class designModel extends model
* @access public
* @return array|bool
*/
public function assign(int $designID = 0, object $design = null): array|bool
public function assign(int $designID = 0, ?object $design = null): array|bool
{
$oldDesign = $this->getByID($designID);
if(!$oldDesign) return false;
@@ -302,7 +302,7 @@ class designModel extends model
* @access public
* @return object
*/
public function getAffectedScope(object $design = null): object
public function getAffectedScope(?object $design = null): object
{
if(!isset($design->id)) return $design;
@@ -329,7 +329,7 @@ class designModel extends model
* @access public
* @return object[]
*/
public function getList(int|array $projectID = 0, int|array $productID = 0, string $type = 'all', int $param = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getList(int|array $projectID = 0, int|array $productID = 0, string $type = 'all', int $param = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getDesigns();
@@ -370,7 +370,7 @@ class designModel extends model
* @access public
* @return object|bool
*/
public function getCommit(int $designID = 0, object $pager = null): object|bool
public function getCommit(int $designID = 0, ?object $pager = null): object|bool
{
$design = $this->dao->select('*')->from(TABLE_DESIGN)->where('id')->eq($designID)->fetch();
if(!$design) return false;
@@ -401,7 +401,7 @@ class designModel extends model
* @access public
* @return object[]
*/
public function getBySearch(int $projectID = 0, int $productID = 0, int $queryID = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getBySearch(int $projectID = 0, int $productID = 0, int $queryID = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
if($queryID)
{
+12 -12
View File
@@ -373,7 +373,7 @@ class docModel extends model
* @access public
* @return bool|int
*/
public function createApiLib(object $formData = null): bool|int
public function createApiLib(?object $formData = null): bool|int
{
$this->app->loadLang('api');
@@ -411,7 +411,7 @@ class docModel extends model
* @access public
* @return array|false
*/
public function updateApiLib(int $id, object $formData = null): array|bool
public function updateApiLib(int $id, ?object $formData = null): array|bool
{
$oldLib = $this->getLibByID($id);
@@ -495,7 +495,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getDocsByBrowseType(string $browseType, int $queryID, int $moduleID, string $sort, object $pager = null)
public function getDocsByBrowseType(string $browseType, int $queryID, int $moduleID, string $sort, ?object $pager = null)
{
if($browseType == 'all') return $this->getDocs(0, 0, $browseType, $sort, $pager);
@@ -558,7 +558,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getMyDocListBySearch(int $queryID, array $hasPrivDocIdList, array $allLibIDList, string $sort, object $pager = null): array
public function getMyDocListBySearch(int $queryID, array $hasPrivDocIdList, array $allLibIDList, string $sort, ?object $pager = null): array
{
if($queryID)
{
@@ -664,7 +664,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getDocTemplateList(int $libID = 0, string $type = 'all', string $orderBy = 'id_desc', object $pager = null, string $searchName = ''): array
public function getDocTemplateList(int $libID = 0, string $type = 'all', string $orderBy = 'id_desc', ?object $pager = null, string $searchName = ''): array
{
return $this->dao->select('*')->from(TABLE_DOC)
->where('templateType')->ne('')
@@ -725,7 +725,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getDocs(int $libID, int $moduleID, string $browseType, string $orderBy, object $pager = null): array
public function getDocs(int $libID, int $moduleID, string $browseType, string $orderBy, ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getDocs();
@@ -915,7 +915,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getMineList(string $type, string $browseType, int $queryID = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getMineList(string $type, string $browseType, int $queryID = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
$query = '';
if($browseType == 'bysearch')
@@ -978,7 +978,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getMySpaceDocs(string $type, string $browseType, string $query = '', string $orderBy = 'id_desc', object $pager = null, string $appendDocs = '', string $filterDocs = ''): array
public function getMySpaceDocs(string $type, string $browseType, string $query = '', string $orderBy = 'id_desc', ?object $pager = null, string $appendDocs = '', string $filterDocs = ''): array
{
if(!in_array($type, array('all', 'view', 'collect', 'createdby', 'editedby'))) return array();
@@ -2421,7 +2421,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getLibFiles(string $type, int $objectID, string $browseType = '', int $param = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getLibFiles(string $type, int $objectID, string $browseType = '', int $param = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
if(!in_array($type, array('execution', 'project', 'product'))) return array();
@@ -3064,7 +3064,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getDocsBySearch(string $type, int $objectID, int $libID, int $queryID, string $orderBy = 'id_desc', object $pager = null): array
public function getDocsBySearch(string $type, int $objectID, int $libID, int $queryID, string $orderBy = 'id_desc', ?object $pager = null): array
{
$query = $this->buildQuery($type, $queryID);
$libs = $this->getLibsByObject($type, $objectID, $libID);
@@ -3311,7 +3311,7 @@ class docModel extends model
* @access public
* @return object
*/
public function buildLibItem(int $libID, object $lib, string $type, int $moduleID = 0, int $objectID = 0, string $browseType = '', int $docID = 0, object|null|bool $release = null): object
public function buildLibItem(int $libID, object $lib, string $type, int $moduleID = 0, int $objectID = 0, string $browseType = '', int $docID = 0, mixed $release = null): object
{
$releaseModule = array();
if($release && $release->lib == $lib->id)
@@ -3597,7 +3597,7 @@ class docModel extends model
* @access public
* @return array
*/
public function getDynamic(object $pager = null): array
public function getDynamic(?object $pager = null): array
{
$allLibs = $this->getLibs('hasApi');
$hasPrivDocIdList = $this->getPrivDocs(array(), 0, 'all');
+3 -3
View File
@@ -13,7 +13,7 @@ cid=1
- 属性myDocs @50
- 获取登录用户为admin时,用户浏览跟收藏的文档数
- 第myDoc条的docViews属性 @0
- 第myDoc条的docCollects属性 @0
- 第myDoc条的docCollects属性 @100
- 获取登录用户为user1时,文档总数、今日编辑文档数、用户编辑过的文档数、用户创建的文档数
- 属性totalDocs @50
- 属性todayEditedDocs @0
@@ -38,8 +38,8 @@ $user1Info = $docTester->getStatisticInfoTest('user1');
/* Admin statistic information. */
r($adminInfo) && p('totalDocs,todayEditedDocs,myEditedDocs,myDocs') && e('50,0,10,50'); // 获取登录用户为admin时,文档总数、今日编辑文档数、用户编辑过的文档数、用户创建的文档数
r($adminInfo) && p('myDoc:docViews,docCollects') && e('0,0'); // 获取登录用户为admin时,用户浏览跟收藏的文档数
r($adminInfo) && p('myDoc:docViews,docCollects') && e('0,100'); // 获取登录用户为admin时,用户浏览跟收藏的文档数
/* User1 statistic information.*/
r($user1Info) && p('totalDocs,todayEditedDocs,myEditedDocs,myDocs') && e('50,0,10,0'); // 获取登录用户为user1时,文档总数、今日编辑文档数、用户编辑过的文档数、用户创建的文档数
r($user1Info) && p('myDoc:docViews,docCollects') && e('~~,~~'); // 获取登录用户为user1时,用户浏览跟收藏的文档数
r($user1Info) && p('myDoc:docViews,docCollects') && e('~~,~~'); // 获取登录用户为user1时,用户浏览跟收藏的文档数
+2 -2
View File
@@ -60,7 +60,7 @@ class entryModel extends model
* @access public
* @return array
*/
public function getList(string $orderBy = 'id_desc', object $pager = null): array
public function getList(string $orderBy = 'id_desc', ?object $pager = null): array
{
if(strpos($orderBy, 'desc_') !== false) $orderBy = str_replace('desc_', '`desc`_', $orderBy);
return $this->dao->select('*')->from(TABLE_ENTRY)->where('deleted')->eq('0')->orderBy($orderBy)->page($pager)->fetchAll('id');
@@ -76,7 +76,7 @@ class entryModel extends model
* @access public
* @return array
*/
public function getLogs(int $id, string $orderBy = 'date_desc', object $pager = null): array
public function getLogs(int $id, string $orderBy = 'date_desc', ?object $pager = null): array
{
return $this->dao->select('*')->from(TABLE_LOG)
->where('objectType')->eq('entry')
+39 -32
View File
@@ -1051,7 +1051,7 @@ class executionModel extends model
* @access public
* @return bool
*/
public function checkWorkload(string $type = '', float $percent = 0, object $oldExecution = null): bool
public function checkWorkload(string $type = '', float $percent = 0, ?object $oldExecution = null): bool
{
/* Check whether the workload is positive. */
if(!preg_match("/^[0-9]+(.[0-9]{1,3})?$/", (string)$percent))
@@ -1230,7 +1230,7 @@ class executionModel extends model
* @access public
* @return array
*/
public function getList(int $projectID = 0, string $type = 'all',string $status = 'all', int $limit = 0, int $productID = 0, int $branch = 0, object|null $pager = null, bool $withChildren = true)
public function getList(int $projectID = 0, string $type = 'all',string $status = 'all', int $limit = 0, int $productID = 0, int $branch = 0, ?object $pager = null, bool $withChildren = true)
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getExecutionStats($type);
@@ -1400,7 +1400,7 @@ class executionModel extends model
* @access public
* @return array
*/
public function getStatData(int $projectID = 0, string $browseType = 'undone', int $productID = 0, int $branch = 0, bool $withTasks = false, string|int $param = '', string $orderBy = 'id_asc', object|null $pager = null): array
public function getStatData(int $projectID = 0, string $browseType = 'undone', int $productID = 0, int $branch = 0, bool $withTasks = false, string|int $param = '', string $orderBy = 'id_asc', ?object $pager = null): array
{
if(commonModel::isTutorialMode()) return $this->loadModel('tutorial')->getExecutionStats($browseType);
@@ -1501,7 +1501,7 @@ class executionModel extends model
* @access public
* @return array
*/
public function fetchExecutionList(int $projectID = 0, string $browseType = 'undone', int $productID = 0, int $param = 0, string $orderBy = 'id_asc', object|null $pager = null): array
public function fetchExecutionList(int $projectID = 0, string $browseType = 'undone', int $productID = 0, int $param = 0, string $orderBy = 'id_asc', ?object $pager = null): array
{
/* Construct the query SQL at search executions. */
$executionQuery = $browseType == 'bySearch' ? $this->getExecutionQuery($param) : '';
@@ -1973,7 +1973,7 @@ class executionModel extends model
* @access public
* @return array
*/
public function getTasks(int $productID, int|array $executionID, array $executions, string $browseType, int $queryID, int $moduleID, string $sort, object $pager = null): array
public function getTasks(int $productID, int|array $executionID, array $executions, string $browseType, int $queryID, int $moduleID, string $sort, ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getTasks();
@@ -2279,7 +2279,7 @@ class executionModel extends model
* @access public
* @return void
*/
public function buildStorySearchForm(array $products, array $branchGroups, array $modules, int $queryID, string $actionURL, string $type = 'executionStory', object $execution = null): void
public function buildStorySearchForm(array $products, array $branchGroups, array $modules, int $queryID, string $actionURL, string $type = 'executionStory', ?object $execution = null): void
{
$this->loadModel('productplan');
$this->app->loadLang('branch');
@@ -3763,7 +3763,7 @@ class executionModel extends model
* @access public
* @return array
*/
public function getSearchTasks(string $condition, string $orderBy, object $pager = null, string $queryKey = 'task'): array
public function getSearchTasks(string $condition, string $orderBy, ?object $pager = null, string $queryKey = 'task'): array
{
/* 按指派人搜索的时候,可以搜索到参与的多人任务。 */
if(strpos($condition, '`assignedTo`') !== false)
@@ -4162,40 +4162,47 @@ class executionModel extends model
* @param array $executions
* @param int $queryID
* @param string $actionURL
* @param bool $processValues 是否处理字段的选项列表。默认不处理可以提高性能,构造搜索表单时再处理。
* @access public
* @return void
*/
public function buildTaskSearchForm(int $executionID, array $executions, int $queryID, string $actionURL)
public function buildTaskSearchForm(int $executionID, array $executions, int $queryID, string $actionURL, bool $processValues = false)
{
$showAll = empty($executionID) && empty($executions) ? true : false;
if($showAll)
{
$executions = $this->getPairs(0, 'all', "nocode,noprefix,multiple");
$executionID = empty($executions) ? 0 : current(array_keys($executions));
}
$execution = $this->getByID($executionID);
$this->config->execution->search['actionURL'] = $actionURL;
$this->config->execution->search['queryID'] = $queryID;
$this->config->execution->search['params']['story']['values'] = $this->loadModel('story')->getExecutionStoryPairs($executionID, 0, 'all', '', 'full', 'unclosed', 'story', false);
if(isset($execution->type) && $execution->type == 'project')
if($processValues)
{
unset($this->config->execution->search['fields']['project']);
$this->config->execution->search['params']['execution']['values'] = array('' => '') + $executions;
}
else
{
$this->config->execution->search['params']['execution']['values'] = $showAll ? $executions : array(''=>'', $executionID => zget($executions, $executionID, ''), 'all' => $this->lang->execution->allExecutions);
$showAll = empty($executionID) && empty($executions) ? true : false;
if($showAll)
{
$executions = $this->getPairs(0, 'all', "nocode,noprefix,multiple");
$executionID = empty($executions) ? 0 : current(array_keys($executions));
}
$execution = $this->getByID($executionID);
$this->config->execution->search['params']['story']['values'] = $this->loadModel('story')->getExecutionStoryPairs($executionID, 0, 'all', '', 'full', 'unclosed', 'story', false);
if(isset($execution->type) && $execution->type == 'project')
{
unset($this->config->execution->search['fields']['project']);
$this->config->execution->search['params']['execution']['values'] = array('' => '') + $executions;
}
else
{
$this->config->execution->search['params']['execution']['values'] = $showAll ? $executions : array(''=>'', $executionID => zget($executions, $executionID, ''), 'all' => $this->lang->execution->allExecutions);
}
$projects = $this->loadModel('project')->getPairsByProgram();
$this->config->execution->search['params']['project']['values'] = $projects + array('all' => $this->lang->project->allProjects);
$showAllModule = isset($this->config->execution->task->allModule) ? $this->config->execution->task->allModule : '';
$this->config->execution->search['params']['module']['values'] = $this->loadModel('tree')->getTaskOptionMenu($executionID, 0, $showAllModule ? 'allModule' : '');
}
$projects = $this->loadModel('project')->getPairsByProgram();
$this->config->execution->search['params']['project']['values'] = $projects + array('all' => $this->lang->project->allProjects);
$showAllModule = isset($this->config->execution->task->allModule) ? $this->config->execution->task->allModule : '';
$this->config->execution->search['params']['module']['values'] = $this->loadModel('tree')->getTaskOptionMenu($executionID, 0, $showAllModule ? 'allModule' : '');
$this->loadModel('search')->setSearchParams($this->config->execution->search);
$funcArgs = func_get_args();
array_pop($funcArgs); // 构造表单时调用该方法 $processValues 值一定为 true,这里不需要传递。
$this->loadModel('search')->setSearchParams($this->config->execution->search, __FUNCTION__, ...$funcArgs); // 传递当前方法名和参数列表以便构造表单时调用该方法处理字段的选项列表。
}
/**
@@ -4209,7 +4216,7 @@ class executionModel extends model
* @access public
* @return array
*/
public function getKanbanTasks(int $executionID, string $orderBy = 'status_asc, id_desc', array $excludeTasks = array(), object|null $pager = null): array
public function getKanbanTasks(int $executionID, string $orderBy = 'status_asc, id_desc', array $excludeTasks = array(), ?object $pager = null): array
{
$excludeTasks = array_filter($excludeTasks);
$tasks = $this->dao->select('t1.*, t2.id AS storyID, t2.title AS storyTitle, t2.version AS latestStoryVersion, t2.status AS storyStatus, t3.realname AS assignedToRealName')
+1 -1
View File
@@ -421,7 +421,7 @@ class executionTao extends executionModel
* @access public
* @return object[]
*/
public function getSearchBugs(array $productIdList, int $executionID, string $sql = '1=1', string $orderBy = 'id_desc', object|null $pager = null): array
public function getSearchBugs(array $productIdList, int $executionID, string $sql = '1=1', string $orderBy = 'id_desc', ?object $pager = null): array
{
return $this->dao->select('*')->from(TABLE_BUG)
->where($sql)
@@ -0,0 +1,96 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class closeExecutionTester extends tester
{
/**
* 关闭执行弹窗中输入实际完成日期。
* Input fields.
*
* @param string $realEnd
* @param string $executionId
* @access public
*/
public function inputFields($realEnd, $executionId)
{
$this->switchVision('lite');
$this->page->wait(5);
$viewForm = $this->initForm('execution', 'view', array('execution' => $executionId), 'appIframe-project');
$viewForm->wait(1);
$realBegan = $viewForm->dom->realBeganView->getText();
$form = $this->initForm('execution', 'kanban', array('execution' => $executionId), 'appIframe-project');
$form->wait(1);
$form->dom->kanbanSettingInLite->click();
$form->wait(1);
$form = $this->loadPage();
$form->wait(1);
$form->dom->btn($this->lang->execution->close)->click();
$form->wait(1);
$form = $this->loadPage();
$form->wait(1);
if(isset($realEnd)) $form->dom->realEnd->datePicker($realEnd);
$form->wait(1);
$form->dom->closeSubmitInLite->click();
$form->wait(1);
return $realBegan;
}
/**
* 正常关闭执行。
* Close execution.
*
* @param string $realEnd
* @param string $executionId
* @access public
* @return bool
*/
public function close($realEnd, $executionId)
{
$this->inputFields($realEnd, $executionId);
$form = $this->initForm('execution', 'view', array('execution' => $executionId), 'appIframe-project');
$form->wait(1);
if($form->dom->status->getText() != $this->lang->execution->statusList->closed) return $this->failed('执行状态错误');
if($form->dom->realEndView->getText() != $realEnd) return $this->failed('执行实际完成日期错误');
return $this->success('关闭执行成功');
}
/**
* 实际完成日期大于当前日期。
* The real end date is greater than the current date.
*
* @param string $realEnd
* @param string $executionId
* @access public
* @return bool
*/
public function closeWithGreaterDate($realEnd, $executionId)
{
$this->inputFields($realEnd, $executionId);
$form = $this->loadPage();
$field = $form->dom->realEndField->getText();
$text = $form->dom->realEndTip->getText();
$info = sprintf($this->lang->error->le, $field, date('Y-m-d'));
if($text == $info) return $this->success('关闭执行表单页提示信息正确');
return $this->failed('关闭执行表单页提示信息不正确');
}
/**
* 实际完成日期小于实际开始日期。
* The real end date is less than the real start date.
*
* @param string $realEnd
* @param string $executionId
* @access public
* @return bool
*/
public function closeWithLessDate($realEnd, $executionId)
{
$realBegan = $this->inputFields($realEnd, $executionId);
$form = $this->loadPage();
$form->wait(1);
$field = $form->dom->realEndField->getText();
$text = $form->dom->realEndTip->getText();
$info = sprintf($this->lang->execution->ge, $field, $realBegan);
if($text == $info) return $this->success('关闭执行表单页提示信息正确');
return $this->failed('关闭执行表单页提示信息不正确');
}
}
@@ -12,6 +12,7 @@ class createExecutionTester extends tester
public function inputFields($execution)
{
$this->switchVision('lite');
$this->page->wait(5);
$form = $this->initForm('execution', 'create', '', 'appIframe-project');
$form->wait(1);
if(isset($execution['project'])) $form->dom->project->picker($execution['project']);
@@ -0,0 +1,29 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class deleteExecutionTester extends tester
{
/**
* 删除执行。
* Delete execution.
*
* @access public
* @return object
*/
public function delete()
{
$viewForm = $this->initForm('execution', 'view', array('execution' => '2'), 'appIframe-execution');
$viewForm->wait(1);
$executionName = $viewForm->dom->executionName->getText();
$viewForm->dom->deleteBtn->click();
$viewForm->wait(1);
$viewForm->dom->alertModal();
$viewForm->wait(1);
$form = $this->initForm('execution', 'all', '', 'appIframe-execution');
$form->wait(1);
$form->dom->search(array(",=,{$executionName}"));
$form->wait(1);
if(is_object($form->dom->tips) && $form->dom->tips->getText() == $this->lang->execution->noExecutions) return $this->success('删除执行成功');
return $this->failed('删除执行失败');
}
}
@@ -13,7 +13,7 @@ class editExecutionTester extends tester
{
$form = $this->initForm('execution', 'view', array('execution' => $execution['id']), 'appIframe-execution');
$form->wait(1);
$form->dom->edit->click();
$form->dom->editBtn->click();
$form = $this->loadPage();
$form->wait(1);
if(isset($execution['name'])) $form->dom->name->setValue($execution['name']);
@@ -31,7 +31,7 @@ class editExecutionTester extends tester
*
* @param string $type sprint|stage|kanban
* @access public
* @return bool
* @return object
*/
public function checkRepeatInfo($type = 'sprint')
{
@@ -57,7 +57,7 @@ class editExecutionTester extends tester
*
* @param string $dateType begin|end
* @access public
* @return bool
* @return object
*/
public function checkDateInfo($dateType = 'end')
{
@@ -92,7 +92,7 @@ class editExecutionTester extends tester
* Get error info of manage products.
*
* @access public
* @return bool
* @return object
*/
public function checkManageProductsInfo()
{
@@ -16,6 +16,7 @@ class kanbanTester extends tester
public function checkKanban($col, $num, $groupId = '', $lane = '1')
{
$this->switchVision('lite');
$this->page->wait(5);
$form = $this->initForm('execution', 'kanban', array('kanbanID' => '2'), 'appIframe-project');
$form->wait(1);
@@ -14,6 +14,7 @@ class putoffExecutionTester extends tester
public function inputFields($execution, $executionId)
{
$this->switchVision('lite');
$this->page->wait(5);
$form = $this->initForm('execution', 'kanban', array('kanbanID' => $executionId ), 'appIframe-project');
$form->wait(1);
$form->dom->kanbanSettingInLite->click();
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env php
<?php
/**
title=运营界面关闭看板
timeout=0
cid=1
- 执行tester模块的closeWithGreaterDate方法,参数是$realEnd[0], '2'▫
- 最终测试状态 @SUCCESS
- 测试结果 @关闭执行表单页提示信息正确
- 执行tester模块的closeWithLessDate方法,参数是$realEnd[2], '2'▫
- 最终测试状态 @SUCCESS
- 测试结果 @关闭执行表单页提示信息正确
- 执行tester模块的close方法,参数是$realEnd[1], '2'▫
- 最终测试状态 @SUCCESS
- 测试结果 @关闭执行成功
*/
chdir(__DIR__);
include '../lib/closeinlite.ui.class.php';
$product = zenData('product');
$product->id->range('1');
$product->name->range('产品1');
$product->shadow->range('1');
$product->type->range('normal');
$product->vision->range('lite');
$product->gen(1);
$project = zenData('project');
$project->id->range('1-5');
$project->project->range('0');
$project->model->range('kanban');
$project->type->range('project');
$project->auth->range('extend');
$project->storytype->range('[]');
$project->path->range('`,1,`');
$project->grade->range('1');
$project->name->range('项目1');
$project->hasProduct->range('1');
$project->begin->range('(-2M)-(-M):1D')->type('timestamp')->format('YY/MM/DD');
$project->end->range('(+2M)-(+3M):1D')->type('timestamp')->format('YY/MM/DD');
$project->status->range('doing');
$project->acl->range('open');
$project->vision->range('lite');
$project->gen(1);
$execution = zenData('project');
$execution->id->range('2');
$execution->project->range('1');
$execution->type->range('kanban');
$execution->parent->range('1');
$execution->path->range('`,1,2,`');
$execution->grade->range('1');
$execution->name->range('测试关闭看板');
$execution->hasProduct->range('1');
$execution->begin->range('(-5D)-(-4D):1D')->type('timestamp')->format('YY/MM/DD');
$execution->end->range('(+M)-(+2M):1D')->type('timestamp')->format('YY/MM/DD');
$execution->realBegan->range('(-3D)-(-2D):1D')->type('timestamp')->format('YY/MM/DD');
$execution->status->range('doing');
$execution->vision->range('lite');
$execution->gen(1, false);
$projectProduct = zenData('projectproduct');
$projectProduct->project->range('1-5');
$projectProduct->product->range('1');
$projectProduct->gen(2);
zenData('task')->gen(0);
$tester = new closeExecutionTester();
$tester->login();
$realEnd = array(date('Y-m-d', strtotime('+20 days')), date('Y-m-d'), date('Y-m-d', strtotime('-4 days')));
r($tester->closeWithGreaterDate($realEnd[0], '2')) && p('status,message') && e('SUCCESS,关闭执行表单页提示信息正确');
r($tester->closeWithLessDate($realEnd[2], '2')) && p('status,message') && e('SUCCESS,关闭执行表单页提示信息正确');
r($tester->close($realEnd[1], '2')) && p('status,message') && e('SUCCESS,关闭执行成功');
$tester->closeBrowser();
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/env php
<?php
/**
title=删除执行
timeout=0
cid=1
- 执行tester模块的delete方法▫
- 最终测试状态 @SUCCESS
- 测试结果 @删除执行成功
*/
chdir(__DIR__);
include '../lib/delete.ui.class.php';
$project = zenData('project');
$project->id->range('1-100');
$project->project->range('0, 1{2}');
$project->model->range('scrum, []{2}');
$project->type->range('project, sprint{2}');
$project->auth->range('extend, []{2}');
$project->storyType->range('story, []{2}');
$project->parent->range('0, 1{2}');
$project->path->range('`,1,`, `,1,2,`, `,1,3,`');
$project->grade->range('1');
$project->name->range('项目, 执行1, 执行2');
$project->begin->range('(-2M)-(-M):1D')->type('timestamp')->format('YY/MM/DD');
$project->end->range('(+2M)-(+3M):1D')->type('timestamp')->format('YY/MM/DD');
$project->openedBy->range('user1');
$project->acl->range('open');
$project->status->range('wait');
$project->gen(3);
$tester = new deleteExecutionTester();
$tester->login();
r($tester->delete()) && p('status,message') && e('SUCCESS,删除执行成功');
$tester->closeBrowser();
+2
View File
@@ -19,6 +19,8 @@ class allPage extends page
'suspendedTab' => "//*[@id='featureBar']/menu/li[5]/a",
'delayedTab' => "//*[@id='featureBar']/menu/li[6]/a",
'closedTab' => "//*[@id='featureBar']/menu/li[7]/a",
/* 搜索不到执行数据的提示信息 */
'tips' => "//*[@id='table-execution-all']/div/div/div",
/* 批量编辑状态 */
'statusBtn' => "//*[@id='table-execution-all']/div[3]/nav[1]/button",
'wait' => "//*[@data-page='execution-all']/div[2]/menu/menu/li[1]/a",
+3
View File
@@ -16,6 +16,9 @@ class kanbanPage extends page
'putoffSubmitInLite' => "//form[contains(@id,'zin_execution_putoff')]//button",
/* 挂起看板弹窗中的提交按钮 */
'suspendSubmitInLite' => "//form[contains(@id,'zin_execution_suspend')]//button",
/* 关闭看板弹窗中的元素 */
'realEndField' => "//div[@data-name='realEnd']/label/span",
'closeSubmitInLite' => "//form[contains(@id,'zin_execution_close')]//button",
);
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
}
+2 -1
View File
@@ -18,7 +18,8 @@ class viewPage extends page
'plannedEnd' => "//*[@id='mainContent']/div[2]/div[1]/div/table[3]/tbody/tr/td/div/div[2]/span[2]",
'realBeganView' => "//*[@id='mainContent']/div[2]/div[1]/div/table[3]/tbody/tr/td/div/div[3]/span[2]",
'realEndView' => "//*[@id='mainContent']/div[2]/div[1]/div/table[3]/tbody/tr/td/div/div[4]/span[2]",
'edit' => "//*[@id='mainContent']/div[3]/div/a[last()-1]",
'editBtn' => "//*[@id='mainContent']/div[3]/div/a[last()-1]",
'deleteBtn' => "//*[@id='mainContent']/div[3]/div/a[last()]",
'linckedProducta' => "//*[@id='mainContent']/div[2]/div[1]/div/table[1]/tbody/tr[1]/td[1]",
'linckedProductb' => "//*[@id='mainContent']/div[2]/div[1]/div/table[1]/tbody/tr[2]/td[1]",
'productsNev' => "//*[@data-id='products']",
+1 -1
View File
@@ -1725,7 +1725,7 @@ class executionZen extends execution
* @param object[]|object $execution
* @return array
*/
protected function setUserMoreLink(array|object $execution = null): array
protected function setUserMoreLink(mixed $execution = null): array
{
$appendPo = $appendPm = $appendQd = $appendRd = array();
if(is_array($execution))
+1 -1
View File
@@ -341,7 +341,7 @@ class file extends control
* @access public
* @return void
*/
public function printFiles(array $files, string $fieldset, object|null $object = null, string $method = 'view', bool $showDelete = true, bool $showEdit = true)
public function printFiles(array $files, string $fieldset, ?object $object = null, string $method = 'view', bool $showDelete = true, bool $showEdit = true)
{
$this->view->files = $files;
$this->view->fieldset = $fieldset;
+5 -5
View File
@@ -45,7 +45,7 @@ class gitlabModel extends model
* @access public
* @return array
*/
public function getList(string $orderBy = 'id_desc', object $pager = null): array
public function getList(string $orderBy = 'id_desc', ?object $pager = null): array
{
$gitlabList = $this->loadModel('pipeline')->getList('gitlab', $orderBy, $pager);
@@ -271,7 +271,7 @@ class gitlabModel extends model
* @access public
* @return array
*/
public function getCommits(object $repo, string $entry, object $pager = null, string $begin = '', string $end = '', object|null $query = null): array
public function getCommits(object $repo, string $entry, ?object $pager = null, string $begin = '', string $end = '', ?object $query = null): array
{
$scm = $this->app->loadClass('scm');
$scm->setEngine($repo);
@@ -619,7 +619,7 @@ class gitlabModel extends model
* @access public
* @return array
*/
public function apiGetProjectsPager(int $gitlabID, string $keyword = '', string $orderBy = 'id_desc', object $pager = null): array
public function apiGetProjectsPager(int $gitlabID, string $keyword = '', string $orderBy = 'id_desc', ?object $pager = null): array
{
$apiRoot = $this->getApiRoot($gitlabID);
if(!$apiRoot) return array('pager' => null, 'projects' => array());
@@ -1434,7 +1434,7 @@ class gitlabModel extends model
* @access public
* @return object|array|null
*/
public function apiGetTags(int $gitlabID, int $projectID, string $orderBy = '', string $keyword = '', object $pager = null): object|array|null
public function apiGetTags(int $gitlabID, int $projectID, string $orderBy = '', string $keyword = '', ?object $pager = null): object|array|null
{
$apiRoot = $this->getApiRoot($gitlabID);
@@ -2294,7 +2294,7 @@ class gitlabModel extends model
* @access public
* @return bool
*/
public function checkUserAccess(int $gitlabID, int $projectID = 0, object $project = null, array $groupIDList = array(), string $maxRole = 'maintainer'): bool
public function checkUserAccess(int $gitlabID, int $projectID = 0, ?object $project = null, array $groupIDList = array(), string $maxRole = 'maintainer'): bool
{
if($this->app->user->admin) return true;
+1 -1
View File
@@ -336,7 +336,7 @@ class gitlabZen extends gitlab
* @access protected
* @return object
*/
protected function issueToZentaoObject(object $issue, int $gitlabID, object $changes = null): object
protected function issueToZentaoObject(object $issue, int $gitlabID, ?object $changes = null): object
{
if(!isset($this->config->gitlab->maps->{$issue->objectType})) return null;
+1 -1
View File
@@ -23,7 +23,7 @@ class hostModel extends model
* @access public
* @return array
*/
public function getList(string $browseType = 'all', int $param = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getList(string $browseType = 'all', int $param = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
$browseType = strtolower($browseType);
+2 -2
View File
@@ -112,7 +112,7 @@ class instanceModel extends model
* @access public
* @return array
*/
public function getList(object $pager = null, string $pinned = '', string $searchParam = '', string $status = 'all', bool $alertMark = true)
public function getList(?object $pager = null, string $pinned = '', string $searchParam = '', string $status = 'all', bool $alertMark = true)
{
$instances = $this->dao->select('instance.*')->from(TABLE_INSTANCE)->alias('instance')
->leftJoin(TABLE_SPACE)->alias('space')->on('space.id=instance.space')
@@ -583,7 +583,7 @@ class instanceModel extends model
* @access public
* @return false|object Failure: return false, Success: return instance
*/
public function install(object $app, object $dbInfo, object $customData, int $spaceID = null, array $settings = array())
public function install(object $app, object $dbInfo, object $customData, ?int $spaceID = null, array $settings = array())
{
$this->loadModel('space');
if(!isset($this->app->user->account))
+5 -5
View File
@@ -104,7 +104,7 @@ class kanbanModel extends model
* @access public
* @return int
*/
public function createRegion(object $kanban, object $fromRegion = null, int $copyRegionID = 0, string $from = 'kanban', string $param = '')
public function createRegion(object $kanban, ?object $fromRegion = null, int $copyRegionID = 0, string $from = 'kanban', string $param = '')
{
$account = $this->app->user->account;
$order = 1;
@@ -355,7 +355,7 @@ class kanbanModel extends model
* @access public
* @return int|false
*/
public function createColumn(int $regionID, object $column = null, string $from = 'kanban', string $mode = 'new'): int|false
public function createColumn(int $regionID, ?object $column = null, string $from = 'kanban', string $mode = 'new'): int|false
{
if($mode == 'new')
{
@@ -1865,7 +1865,7 @@ class kanbanModel extends model
* @access public
* @return array
*/
public function getSpaceList(string $browseType, object $pager = null): array
public function getSpaceList(string $browseType, ?object $pager = null): array
{
$account = $this->app->user->account;
$spaceIdList = $this->getCanViewObjects('kanbanspace', $browseType);
@@ -2155,7 +2155,7 @@ class kanbanModel extends model
* @access public
* @return int|bool
*/
public function createLane(int $kanbanID, int $regionID, object $lane = null, string $mode = 'new'): int|bool
public function createLane(int $kanbanID, int $regionID, ?object $lane = null, string $mode = 'new'): int|bool
{
$laneType = isset($_POST['laneType']) ? $_POST['laneType'] : 'common';
if($laneType == 'common')
@@ -3665,7 +3665,7 @@ class kanbanModel extends model
* @access public
* @return array
*/
public function getCards2Import(int $kanbanID = 0, int $excludedID = 0, object $pager = null): array
public function getCards2Import(int $kanbanID = 0, int $excludedID = 0, ?object $pager = null): array
{
$kanbanIdList = $this->getCanViewObjects();
+1 -1
View File
@@ -482,7 +482,7 @@ class mailModel extends model
* @access public
* @return array
*/
public function getQueue(string $status = 'all', string $orderBy = 'id_desc', object|null $pager = null, bool $mergeByUser = true): array
public function getQueue(string $status = 'all', string $orderBy = 'id_desc', ?object $pager = null, bool $mergeByUser = true): array
{
$mails = $this->dao->select('*')->from(TABLE_NOTIFY)
->where('objectType')->eq('mail')
+2 -2
View File
@@ -35,7 +35,7 @@ class mrModel extends model
* @access public
* @return array
*/
public function getList(string $mode = 'all', string $param = 'all', string $orderBy = 'id_desc', array $filterProjects = array(), int $repoID = 0, int $objectID = 0, object $pager = null): array
public function getList(string $mode = 'all', string $param = 'all', string $orderBy = 'id_desc', array $filterProjects = array(), int $repoID = 0, int $objectID = 0, ?object $pager = null): array
{
$filterProjectSql = '';
if(!$this->app->user->admin && !empty($filterProjects))
@@ -964,7 +964,7 @@ class mrModel extends model
* @access public
* @return array
*/
public function getLinkList(int $MRID, string $type, string $orderBy = 'id_desc', object $pager = null): array
public function getLinkList(int $MRID, string $type, string $orderBy = 'id_desc', ?object $pager = null): array
{
if(!isset($this->config->objectTables[$type])) return array();
+10 -10
View File
@@ -262,7 +262,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getAssignedByMe(string $account, object $pager = null, string $orderBy = 'id_desc', string $objectType = ''): array
public function getAssignedByMe(string $account, ?object $pager = null, string $orderBy = 'id_desc', string $objectType = ''): array
{
$module = $objectType == 'requirement' ? 'story' : $objectType;
$objectIdList = $this->dao->select('objectID')->from(TABLE_ACTION)
@@ -315,7 +315,7 @@ class myModel extends model
* @access private
* @return array
*/
private function getTaskAssignedByMe(object $pager = null, string $orderBy = 'id_desc', array $objectIdList = array()): array
private function getTaskAssignedByMe(?object $pager = null, string $orderBy = 'id_desc', array $objectIdList = array()): array
{
// 处理优先级排序
if(strpos($orderBy, 'pri_') !== false) $orderBy = str_replace('pri_', 'priOrder_', $orderBy);
@@ -391,7 +391,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getTestcasesBySearch(int $queryID, string $type, string $orderBy, object $pager = null): array
public function getTestcasesBySearch(int $queryID, string $type, string $orderBy, ?object $pager = null): array
{
$queryName = $type == 'contribute' ? 'contributeTestcaseQuery' : 'workTestcaseQuery';
$queryForm = $type == 'openedbyme' ? 'contributeTestcaseForm' : 'workTestcaseForm';
@@ -494,7 +494,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getTasksBySearch(string $account, int $limit = 0, object $pager = null, string $orderBy = 'id_desc', int $queryID = 0): array
public function getTasksBySearch(string $account, int $limit = 0, ?object $pager = null, string $orderBy = 'id_desc', int $queryID = 0): array
{
$moduleName = $this->app->rawMethod == 'work' ? 'workTask' : 'contributeTask';
$queryName = $moduleName . 'Query';
@@ -619,7 +619,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getRisksBySearch(int $queryID, string $type, string $orderBy, object $pager = null): array
public function getRisksBySearch(int $queryID, string $type, string $orderBy, ?object $pager = null): array
{
$queryName = $type == 'contribute' ? 'contributeRiskQuery' : 'workRiskQuery';
if($queryID && $queryID != 'myQueryID')
@@ -715,7 +715,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getStoriesBySearch(int $queryID, string $type, string $orderBy, object $pager = null): array
public function getStoriesBySearch(int $queryID, string $type, string $orderBy, ?object $pager = null): array
{
$queryName = $type == 'contribute' ? 'contributeStoryQuery' : 'workStoryQuery';
$queryForm = $type == 'contribute' ? 'contributeStoryForm' : 'workStoryForm';
@@ -865,7 +865,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getEpicsBySearch(int $queryID, string $type, string $orderBy, object $pager = null): array
public function getEpicsBySearch(int $queryID, string $type, string $orderBy, ?object $pager = null): array
{
$queryName = $type == 'contribute' ? 'contributeEpicQuery' : 'workEpicQuery';
$queryForm = $type == 'contribute' ? 'contributeEpicForm' : 'workEpicForm';
@@ -907,7 +907,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getRequirementsBySearch(int $queryID, string $type, string $orderBy, object $pager = null): array
public function getRequirementsBySearch(int $queryID, string $type, string $orderBy, ?object $pager = null): array
{
$queryName = $type == 'contribute' ? 'contributeRequirementQuery' : 'workRequirementQuery';
$queryForm = $type == 'contribute' ? 'contributeRequirementForm' : 'workRequirementForm';
@@ -981,7 +981,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getReviewingList(string $browseType, string $orderBy = 'time_desc', object $pager = null): array
public function getReviewingList(string $browseType, string $orderBy = 'time_desc', ?object $pager = null): array
{
$vision = $this->config->vision;
$reviewList = array();
@@ -1370,7 +1370,7 @@ class myModel extends model
* @access public
* @return array
*/
public function getReviewedList(string $browseType, string $orderBy = 'time_desc', object $pager = null): array
public function getReviewedList(string $browseType, string $orderBy = 'time_desc', ?object $pager = null): array
{
$field = $orderBy;
$direction = 'asc';
+5 -5
View File
@@ -23,7 +23,7 @@ class myTao extends myModel
* @access protected
* @return array
*/
protected function getProductRelatedAssignedByMe(array $objectIdList, string $objectType, string $module, string $orderBy, object $pager = null): array
protected function getProductRelatedAssignedByMe(array $objectIdList, string $objectType, string $module, string $orderBy, ?object $pager = null): array
{
$nameField = $objectType == 'bug' ? 'productName' : 'productTitle';
$orderBy = strpos($orderBy, 'priOrder') !== false || strpos($orderBy, 'severityOrder') !== false || strpos($orderBy, $nameField) !== false ? $orderBy : "t1.{$orderBy}";
@@ -63,7 +63,7 @@ class myTao extends myModel
* @access protected
* @return array
*/
protected function fetchTasksBySearch(string $query, string $moduleName, string $account, array $taskIdList, string $orderBy, int $limit, object $pager = null): array
protected function fetchTasksBySearch(string $query, string $moduleName, string $account, array $taskIdList, string $orderBy, int $limit, ?object $pager = null): array
{
$query = preg_replace('/`(\w+)`/', 't1.`$1`', $query);
$query = str_replace('t1.`project`', 't2.`project`', $query);
@@ -133,7 +133,7 @@ class myTao extends myModel
* @access protected
* @return array
*/
protected function fetchStoriesBySearch(string $myStoryQuery, string $type, string $orderBy, object $pager = null, array $storiesAssignedByMe = array()): array
protected function fetchStoriesBySearch(string $myStoryQuery, string $type, string $orderBy, ?object $pager = null, array $storiesAssignedByMe = array()): array
{
if($type == 'contribute')
{
@@ -188,7 +188,7 @@ class myTao extends myModel
* @access protected
* @return array
*/
protected function fetchEpicsBySearch(string $myEpicQuery, string $type, string $orderBy, object $pager = null, array $epicIDList = array()): array
protected function fetchEpicsBySearch(string $myEpicQuery, string $type, string $orderBy, ?object $pager = null, array $epicIDList = array()): array
{
if($type == 'contribute')
{
@@ -245,7 +245,7 @@ class myTao extends myModel
* @access protected
* @return array
*/
protected function fetchRequirementsBySearch(string $myRequirementQuery, string $type, string $orderBy, object $pager = null, array $requirementIDList = array()): array
protected function fetchRequirementsBySearch(string $myRequirementQuery, string $type, string $orderBy, ?object $pager = null, array $requirementIDList = array()): array
{
if($type == 'contribute')
{
+2 -2
View File
@@ -529,7 +529,7 @@ class personnelModel extends model
* @access public
* @return array
*/
public function getWhitelist(int $objectID = 0, string $objectType = '', string $orderBy = 'id_desc', object $pager = null): array
public function getWhitelist(int $objectID = 0, string $objectType = '', string $orderBy = 'id_desc', ?object $pager = null): array
{
return $this->dao->select('t1.id,t1.account,t2.realname,t2.dept,t2.role,t2.phone,t2.qq,t2.weixin,t2.email')->from(TABLE_ACL)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')->on('t1.account = t2.account')
@@ -823,7 +823,7 @@ class personnelModel extends model
* @access public
* @return string
*/
public function createMemberLink(object $dept = null, int $programID = 0): string
public function createMemberLink(?object $dept = null, int $programID = 0): string
{
return helper::createLink('personnel', 'accessible', "program={$programID}&deptID={$dept->id}");
}
+1 -1
View File
@@ -11,7 +11,7 @@ class pivotTao extends pivotModel
* @access public
* @return object|bool
*/
protected function fetchPivot(int $id, string|null $version = null): object|bool
protected function fetchPivot(int $id, ?string $version = null): object|bool
{
$pivot = $this->dao->select('*')->from(TABLE_PIVOT)->where('id')->eq($id)->andWhere('deleted')->eq('0')->fetch();
if(!$pivot) return false;
+1 -1
View File
@@ -192,7 +192,7 @@ class pivotZen extends pivot
* @access public
* @return void
*/
public function show(int $groupID, int $pivotID, string $mark = '', string|null $version = null): void
public function show(int $groupID, int $pivotID, string $mark = '', ?string $version = null): void
{
$this->pivot->checkAccess($pivotID, 'preview');
+5 -5
View File
@@ -651,7 +651,7 @@ class productModel extends model
* @access public
* @return array
*/
public function getStories(int|array $productID, string $branch, string $browseType, int $queryID, int $moduleID, string $type = 'story', string $sort = 'id_desc', object|null$pager = null): array
public function getStories(int|array $productID, string $branch, string $browseType, int $queryID, int $moduleID, string $type = 'story', string $sort = 'id_desc', ?object $pager = null): array
{
if(commonModel::isTutorialMode()) return $this->loadModel('tutorial')->getStories();
@@ -909,7 +909,7 @@ class productModel extends model
* @access public
* @return array
*/
public function getProjectListByProduct(int $productID, string $browseType = 'all', string $branch = '0', bool $involved = false, string $orderBy = 'order_desc', object|null $pager = null): array
public function getProjectListByProduct(int $productID, string $browseType = 'all', string $branch = '0', bool $involved = false, string $orderBy = 'order_desc', ?object $pager = null): array
{
$branch = $branch ? $branch : '0';
if(!$involved) $projectList = $this->productTao->fetchAllProductProjects($productID, $browseType, $branch, $orderBy, $pager);
@@ -939,7 +939,7 @@ class productModel extends model
* @access public
* @return int[]
*/
public function getProjectStatsByProduct(int $productID, string $browseType = 'all', string $branch = '0', bool $involved = false, string $orderBy = 'order_desc', object|null $pager = null): array
public function getProjectStatsByProduct(int $productID, string $browseType = 'all', string $branch = '0', bool $involved = false, string $orderBy = 'order_desc', ?object $pager = null): array
{
$projects = $this->getProjectListByProduct($productID, $browseType, $branch, $involved, $orderBy, $pager);
if(empty($projects)) return array();
@@ -1103,7 +1103,7 @@ class productModel extends model
* @access public
* @return array
*/
public function getStats(array $productIdList, string $orderBy = 'order_asc', object|null $pager = null, string $storyType = 'story', int $programID = 0): array
public function getStats(array $productIdList, string $orderBy = 'order_asc', ?object $pager = null, string $storyType = 'story', int $programID = 0): array
{
/* Call the getProductStats method of the tutorial module if you are in tutorial mode.*/
if(commonModel::isTutorialMode()) return $this->loadModel('tutorial')->getProductStats();
@@ -1673,7 +1673,7 @@ class productModel extends model
* @access public
* @return array
*/
public function getStatsProducts(array $productIdList, bool $appendProgram, string $orderBy, object|null $pager = null): array
public function getStatsProducts(array $productIdList, bool $appendProgram, string $orderBy, ?object $pager = null): array
{
if($orderBy == 'program_asc')
{
+2 -2
View File
@@ -82,7 +82,7 @@ class productTao extends productModel
* @access protected
* @return array
*/
protected function fetchAllProductProjects(int $productID, string $browseType = 'all', string $branch = 'all', string $orderBy = 'order_desc', object|null $pager = null): array
protected function fetchAllProductProjects(int $productID, string $browseType = 'all', string $branch = 'all', string $orderBy = 'order_desc', ?object $pager = null): array
{
return $this->dao->select('DISTINCT t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
@@ -110,7 +110,7 @@ class productTao extends productModel
* @access protected
* @return array
*/
protected function fetchInvolvedProductProjects(int $productID, string $browseType = 'all', string $branch = 'all', string $orderBy = 'order_desc', object|null $pager = null): array
protected function fetchInvolvedProductProjects(int $productID, string $browseType = 'all', string $branch = 'all', string $orderBy = 'order_desc', ?object $pager = null): array
{
return $this->dao->select('DISTINCT t2.*')->from(TABLE_PROJECTPRODUCT)->alias('t1')
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
+3 -3
View File
@@ -412,7 +412,7 @@ class productZen extends product
* @access protected
* @return array
*/
protected function getExportData(int $programID, string $browseType, string $orderBy, int $param = 0, object|null $pager = null): array
protected function getExportData(int $programID, string $browseType, string $orderBy, int $param = 0, ?object $pager = null): array
{
$users = $this->user->getPairs('noletter');
$products = strtolower($browseType) == 'bysearch' ? $this->product->getListBySearch((int)$param) : $this->product->getList($programID, $browseType);
@@ -916,7 +916,7 @@ class productZen extends product
* @access protected
* @return array
*/
public function getStories(int $projectID, int $productID, string $branchID = '', int $moduleID = 0, int $param = 0, string $storyType = 'all', string $browseType = 'allstory', string $orderBy = 'id_desc', object $pager = null): array
public function getStories(int $projectID, int $productID, string $branchID = '', int $moduleID = 0, int $param = 0, string $storyType = 'all', string $browseType = 'allstory', string $orderBy = 'id_desc', ?object $pager = null): array
{
/* Append id for second sort. */
$sort = common::appendOrder($orderBy);
@@ -956,7 +956,7 @@ class productZen extends product
* @access public
* @return array
*/
public function getStoriesByStoryType(int $productID, string $branch = '', string $storyType = 'all', string $orderBy = 'id_desc', object $pager = null): array
public function getStoriesByStoryType(int $productID, string $branch = '', string $storyType = 'all', string $orderBy = 'id_desc', ?object $pager = null): array
{
/* Append id for second sort. */
$sort = common::appendOrder($orderBy);
+2 -2
View File
@@ -102,7 +102,7 @@ class productplanModel extends model
* @access public
* @return array
*/
public function getList(int $productID = 0, string $branch = '', string $browseType = 'undone', object|null $pager = null, string $orderBy = 'begin_desc', string $param = '', int $queryID = 0): array
public function getList(int $productID = 0, string $branch = '', string $browseType = 'undone', ?object $pager = null, string $orderBy = 'begin_desc', string $param = '', int $queryID = 0): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getPlans();
@@ -623,7 +623,7 @@ class productplanModel extends model
* @access public
* @return object
*/
public function buildPlanByStatus(string $status, string $closedReason = '', object $plan = null): object
public function buildPlanByStatus(string $status, string $closedReason = '', ?object $plan = null): object
{
$now = helper::now();
+2 -2
View File
@@ -24,7 +24,7 @@ class productplanTao extends productplanModel
* @access protected
* @return array
*/
protected function getPlanList(array $productIdList, string $branch = '', string $browseType = '', string $param = '', string $orderBy = '', object $pager = null): array
protected function getPlanList(array $productIdList, string $branch = '', string $browseType = '', string $param = '', string $orderBy = '', ?object $pager = null): array
{
return $this->dao->select('*')->from(TABLE_PRODUCTPLAN)
->where('deleted')->eq(0)
@@ -48,7 +48,7 @@ class productplanTao extends productplanModel
* @access protected
* @return array
*/
protected function getPlanProjects(array $planIdList, int|null $productID = null): array
protected function getPlanProjects(array $planIdList, ?int $productID = null): array
{
if(empty($planIdList)) return [];
+5 -5
View File
@@ -189,7 +189,7 @@ class programModel extends model
* @access public
* @return array
*/
public function getList(string $status = 'all', string $orderBy = 'id_asc', string $type = '', array $topIdList = array(), object $pager = null): array
public function getList(string $status = 'all', string $orderBy = 'id_asc', string $type = '', array $topIdList = array(), ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getPrograms();
@@ -245,7 +245,7 @@ class programModel extends model
* @access public
* @return array
*/
public function getListBySearch(string $orderBy = 'id_asc', int $queryID = 0, bool $hasProject = false, object|null $pager = null): array
public function getListBySearch(string $orderBy = 'id_asc', int $queryID = 0, bool $hasProject = false, ?object $pager = null): array
{
if($this->session->programQuery == false) $this->session->set('programQuery', ' 1 = 1');
if($queryID)
@@ -500,7 +500,7 @@ class programModel extends model
* @access public
* @return object[]
*/
public function getProjectList(int $programID = 0, string $browseType = 'all', int $queryID = 0, string $orderBy = 'id_desc', string $programTitle = '', bool $queryAll = false, object $pager = null): array
public function getProjectList(int $programID = 0, string $browseType = 'all', int $queryID = 0, string $orderBy = 'id_desc', string $programTitle = '', bool $queryAll = false, ?object $pager = null): array
{
$path = '';
if($programID) $path = $this->getByID($programID)->path;
@@ -574,7 +574,7 @@ class programModel extends model
* @access public
* @return array
*/
public function getStakeholders(int $programID = 0, string $orderBy = 'id_desc', object $pager = null): array
public function getStakeholders(int $programID = 0, string $orderBy = 'id_desc', ?object $pager = null): array
{
return $this->dao->select('t2.account,t2.realname,t2.role,t2.qq,t2.mobile,t2.phone,t2.weixin,t2.email,t1.id,t1.type,t1.from,t1.key')->from(TABLE_STAKEHOLDER)->alias('t1')
->leftJoin(TABLE_USER)->alias('t2')->on('t1.user=t2.account')
@@ -1127,7 +1127,7 @@ class programModel extends model
* @access public
* @return array
*/
public function getProjectStats(int $programID = 0, string $browseType = 'undone', int $queryID = 0, string $orderBy = 'id_desc', string $programTitle = '', bool $queryAll = false, object|null $pager = null): array
public function getProjectStats(int $programID = 0, string $browseType = 'undone', int $queryID = 0, string $orderBy = 'id_desc', string $programTitle = '', bool $queryAll = false, ?object $pager = null): array
{
if(commonModel::isTutorialMode()) return $this->loadModel('tutorial')->getProjectStats($browseType);
+1 -1
View File
@@ -115,7 +115,7 @@ class programZen extends program
* @access protected
* @return array
*/
protected function getProgramsByType(string $status, string $orderBy, int $param = 0, object|null $pager = null): array
protected function getProgramsByType(string $status, string $orderBy, int $param = 0, ?object $pager = null): array
{
$status = strtolower($status);
$this->view->summary = '';
+2 -2
View File
@@ -507,7 +507,7 @@ class programplanModel extends model
* @access public
* @return bool
*/
public function update(int $planID = 0, int $projectID = 0, object|null $plan = null): bool
public function update(int $planID = 0, int $projectID = 0, ?object $plan = null): bool
{
if(empty($plan)) return false;
@@ -882,7 +882,7 @@ class programplanModel extends model
* @access public
* @return array
*/
public function getGanttTasks(int $projectID, array $planIdList, string $browseType, int $queryID, object $pager = null)
public function getGanttTasks(int $projectID, array $planIdList, string $browseType, int $queryID, ?object $pager = null)
{
$tasks = array();
if($browseType == 'bysearch')
+1 -1
View File
@@ -875,7 +875,7 @@ class programplanTao extends programplanModel
* @access protected
* @return array
*/
protected function getTaskDateLimit(object $task, object|null $execution = null, object|null $parent = null): array
protected function getTaskDateLimit(object $task, ?object $execution = null, ?object $parent = null): array
{
$estStart = helper::isZeroDate($task->estStarted) ? '' : $task->estStarted;
$estEnd = helper::isZeroDate($task->deadline) ? '' : $task->deadline;
+1 -1
View File
@@ -208,7 +208,7 @@ class programplanZen extends programplan
* @access protected
* @return object|false
*/
protected function prepareEditPlan(int $planID, int $projectID, object $plan, object|null $parentStage = null): object|false
protected function prepareEditPlan(int $planID, int $projectID, object $plan, ?object $parentStage = null): object|false
{
if($plan->end < $plan->begin) dao::$errors['end'] = $this->lang->programplan->error->planFinishSmall;
+3 -3
View File
@@ -224,7 +224,7 @@ class projectModel extends model
}
/* 项目模板不校验访问权限。 */
$isTpl = $this->dao->select('isTpl')->from(TABLE_PROJECT)->where('id')->eq($projectID)->andWhere('id')->in($this->app->user->view->projects)->fetch('isTpl');
$isTpl = $this->dao->select('isTpl')->from(TABLE_PROJECT)->where('id')->eq($projectID)->fetch('isTpl');
if(empty($isTpl) && !isset($projects[$projectID]))
{
if($projectID && strpos(",{$this->app->user->view->projects},", ",{$projectID},") === false && !empty($projects))
@@ -336,7 +336,7 @@ class projectModel extends model
* @access public
* @return array
*/
public function getList(string $status = 'undone', string $orderBy = 'order_desc', bool $involved = false, object|null $pager = null): array
public function getList(string $status = 'undone', string $orderBy = 'order_desc', bool $involved = false, ?object $pager = null): array
{
/* Get project list by status. */
$projects = $this->projectTao->fetchProjectList($status, $orderBy, $involved, $pager);
@@ -1463,7 +1463,7 @@ class projectModel extends model
* @access public
* @return array|false
*/
public function update(object $project, object $oldProject, object $postProductData = null): array|false
public function update(object $project, object $oldProject, ?object $postProductData = null): array|false
{
/* 通过主键查老项目信息, 处理父节点和图片字段。*/
/* Fetch old project's info and dispose parent and file info. */
@@ -0,0 +1,42 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class activeprojectliteTester extends tester
{
/**
* Active a project.
*
* @param array $project
* @access public
* @return object
*/
public function activeProject(array $project)
{
$this->switchVision('lite');
$form = $this->initForm('project', 'browse', '', 'appIframe-project');
$featureBar = (array)$this->lang->project->featureBar;
$featureBar['browse'] = (array)$featureBar['browse'];
$form->dom->btn($featureBar['browse']['more'])->click();
$form->dom->closed->click();
$form->wait(1);
$form->dom->activeBtn->click();
$form->wait(1);
$title = $form->dom->title->getText();
$form->dom->activeProject->click();
$form->wait(1);
/* 点击进行中标签进入进行中列表,搜索激活的项目*/
$featureBar = (array)$this->lang->project->featureBar;
$featureBar['browse'] = (array)$featureBar['browse'];
$form->dom->btn($featureBar['browse']['doing'])->click();
$form->wait(1);
$form->dom->search(array("{$this->lang->project->name},=,{$title}"));
$form->wait(1);
$featureBar['index'] = (array)$featureBar['index'];
if($featureBar['index']['doing'] != $form->dom->browseStatus->getText()) return $this->failed('激活项目失败');
return $this->success('激活项目成功');
}
}
@@ -3,72 +3,84 @@ include dirname(__FILE__, 5) . '/test/lib/ui.php';
class batchEditProjectTester extends tester
{
/**
* Batch edit a project.
*
* @param array $project
* @access public
* @return object
*/
public function batchEditProject(array $project)
{
$form = $this->initForm('project', 'browse', '', 'appIframe-project');
$form->dom->selectBtn->click();
$form->dom->batchEditBtn->click();
$firstID = $form->dom->id_static_0->getText(); //获取第一行的项目id
$beginInput = "begin[{$firstID}]";
$endInput = "end[{$firstID}]";
if(isset($project['name'])) $form->dom->name_0->setValue($project['name']);
if(isset($project['begin'])) $form->dom->$beginInput->datePicker($project['begin']);
if(isset($project['end'])) $form->dom->$endInput->datePicker($project['end']);
$form->wait(1);
$form->dom->btn($this->lang->save)->click();
$form->wait(1);
return $this->checkBatchEdit($form, $firstID, $project);
}
/**
* Check the result after batch edit the project.
* 批量编辑项目后检查结果。
* 批量编辑项目时检查页面输入。
* Check the page input when batch edit the project.
*
* @param array $project
* @access public
* @return object
*/
public function checkBatchEdit(object $form, string $firstID, array $project)
public function checkInput($project = array())
{
if($this->response('method') != 'browse')
{
$firstBeginTip = "begin[{$firstID}]Tip";
$firstEndTip = "end[{$firstID}]Tip";
$firstNameTip = "name[{$firstID}]Tip";
if($form->dom->$firstNameTip)
$form = $this->initForm('project', 'browse', array(), 'appIframe-project');
$form->dom->selectAllBtn->click();
$form->dom->batchEditBtn->click();
$firstID = $form->dom->id_static_0->getText(); //获取第一行的ID
$firstBegin = "begin[{$firstID}]";
$firstEnd = "end[{$firstID}]";
$firstAcl = "acl[{$firstID}]";
if(isset($project['name'])) $form->dom->name_0->setValue($project['name']);
if(isset($project['begin'])) $form->dom->$firstBegin->datePicker($project['begin']);
if(isset($project['end'])) $form->dom->$firstEnd->datePicker($project['end']);
if(isset($project['acl'])) $form->dom->$firstAcl->picker($project['acl']);
$form->dom->btn($this->lang->save)->click();
$form->wait(2);
return $this->checkResult($project, $firstID);
}
/**
* 批量编辑项目后结果检查。
* Check the result after batch edit the project.
*
* @param array $project
* @access public
* @return object
*/
public function checkResult($project = array(), $firstID)
{
/* 检查批量编辑页面提示信息 */
$form = $this->loadPage('project', 'batchEdit');
if($this->response('method') != 'view')
{ $firstNameTipDom = "name[{$firstID}]Tip"; //第一行的名称提示信息
/* 检查项目名称不能为空 */
if($form->dom->$firstNameTipDom && $project['name'] == '')
{
//检查项目名称不能为空
$nameTipText = $form->dom->$firstNameTip->getText();
$nameTipText = $form->dom->$firstNameTipDom->getText();
$nameTip = sprintf($this->lang->error->notempty, $this->lang->project->name);
return ($nameTipText == $nameTip) ? $this->success('批量编辑项目表单页提示信息正确') : $this->failed('批量编辑项目表单页提示信息不正确');
return ($nameTipText == $nameTip) ? $this->success('项目名称必填提示信息正确') : $this->failed('项目名称必填提示信息不正确');
}
if($form->dom->$firstBeginTip)
/* 检查项目名称唯一 */
if($form->dom->alertModal && $project['name'] != '')
{
//检查计划开始不能为空
$beginTipText = $form->dom->$firstBeginTip->getText();
$beginTip = sprintf($this->lang->error->notempty, $this->lang->project->begin);
return ($beginTipText == $beginTip) ? $this->success('批量编辑项目表单页提示信息正确') : $this->failed('批量编辑项目表单页提示信息不正确');
$existName = '敏捷项目2';
$nameTipText = $form->dom->alertModal('text');
$nameTip = 'ID' . $firstID . sprintf($this->lang->error->repeat, $this->lang->project->name, $existName);
return ($nameTipText == $nameTip) ? $this->success('项目名称唯一提示信息正确') : $this->failed('项目名称唯一提示信息不正确');
}
if($form->dom->$firstEndTip)
/* 检查计划完成日期不能大于计划开始日期 */
if($form->dom->alertModal && $project['begin'] > $project['end'])
{
//检查计划完成不能为空
$endTipText = $form->dom->$firstEndTip->getText();
$endTip = sprintf($this->lang->project->copyProject->endTips,'');
return ($endTipText == $endTip) ? $this->success('批量编辑项目表单页提示信息正确') : $this->failed('批量编辑项目表单页提示信息不正确');
$endTipText = $form->dom->alertModal('text');
$endTip = 'ID' . $firstID . sprintf($this->lang->error->gt, $this->lang->project->end, $project['begin']);
return ($endTipText == $endTip) ? $this->success('计划完成校验提示信息正确') : $this->failed('计划完成校验提示信息不正确');
}
}
$browsePage = $this->loadPage('project', 'browse');
$browsePage->wait(1);
if($browsePage->dom->projectName->getText() != $project['name']) return $this->failed('名称错误');
return $this->success();
/* 跳转到项目列表页面,按照项目名称进行搜索 */
$browsePage = $this->initForm('project', 'browse');
$browsePage->dom->search($searchList = array("项目名称,包含,{$project['name']}"));
$browsePage->wait(2);
$browsePage->dom->projectName->click();
$browsePage->wait(2);
/* 进入项目概况页面 */
$browsePage->dom->settings->click();
$viewPage = $this->loadPage('project', 'view');
$viewPage->wait(2);
/* 断言检查字段信息是否正确 */
if($viewPage->dom->projectName->getText() != $project['name']) return $this->failed('名称错误');
if($viewPage->dom->acl->getText() != $this->lang->project->shortAclList->open) return $this->failed('权限错误');
return $this->success('批量编辑项目成功');
}
}
@@ -0,0 +1,33 @@
<?php
include dirname(__FILE__, 5) . '/test/lib/ui.php';
class executionTester extends tester
{
/**
* 敏捷项目迭代列表页面标签数量。
* Project execution tab.
*
* @param string $tab
* @param string $expectNum
* @access public
*/
public function checkTab($tab, $expectNum)
{
$form = $this->initForm('project', 'execution', '', 'appIframe-project');
$status = [
'all' => '全部',
'undone' => '未完成',
'wait' => '未开始',
'doing' => '进行中',
'suspended' => '已挂起',
'delayed' => '已延期',
'closed' => '已关闭',
];
$tabDom = $tab.'Tab';
$form->dom->$tabDom->click();
$form->wait(2);
/*添加断言,判断标签下条数是否符合预期*/
if($form->dom->numDom->getText() == $expectNum) return $this->success($status[$tab] . '标签下条数显示正确');
return $this->failed($status[$tab] . '标签下条数显示不正确');
}
}
@@ -0,0 +1,78 @@
<?php
class projectZenTest
{
public $projectZenTest;
public $tester;
function __construct()
{
global $tester;
$this->tester = $tester;
$tester->app->setModuleName('project');
$tester->loadModel('project');
$this->projectZenTest = initReference('project');
}
/**
* 构建POST数据。
* Build POST data.
*
* @param int $testData
* @access public
* @return array
*/
public function buildPostData($testData)
{
$origData = array(
'storyType' => array('story'),
'parent' => 0,
'charter' => '',
'model' => 'scrum',
'hasProduct' => 1,
'workflowGroup' => 2,
'budget' => '',
'multiple' => 'on',
'name' => 'name1',
'PM' => '',
'begin' => '2025-07-07',
'end' => '',
'days' => '',
'productName' => '',
'products' => array(''),
'branch' => array(array('')),
'plans' => array(array('')),
'desc' => '',
'budgetUnit' => 'CNY',
'linkType' => 'plan',
'deliverable' => array('new_0' => array('name' => '', 'doc' => '', 'fileID' => '')),
'acl' => 'open',
'whitelist' => array(''),
'contactList' => '',
'auth' => 'extend',
'taskDateLimit' => 'auto'
);
return array_merge($origData, $testData);
}
/**
* 测试prepareCreateExtras方法。
* Test prepareCreateExtras method.
*
* @param int $testData
* @param int $expect
* @access public
* @return array|bool
*/
public function prepareCreateExtrasTest($testData, $expect)
{
$_POST = $this->buildPostData($testData);
$postData = form::data($this->tester->config->project->form->create);
$method = $this->projectZenTest->getMethod('prepareCreateExtras');
$method->setAccessible(true);
$result = $method->invokeArgs($this->projectZenTest->newInstance(), [$postData, $expect]);
if(dao::isError()) return dao::getError();
return $result;
}
}
+1 -1
View File
@@ -28,4 +28,4 @@ r($tester->project->checkAccess($idList[0], $projects)) && p() && e('10'); //不
r($tester->project->checkAccess($idList[1], $projects)) && p() && e('11'); //传入存在ID的值
r($tester->project->checkAccess($idList[0], $projects)) && p() && e('11'); //不传入ID,读取session信息
r($tester->project->checkAccess($idList[2], $projects)) && p() && e('14'); //传入正确的ID
r($tester->project->checkAccess($idList[3], $projects)) && p() && e('0'); //传入不存在的ID
r($tester->project->checkAccess($idList[3], $projects)) && p() && e('0'); //传入不存在的ID
@@ -12,6 +12,14 @@ zenData('build')->gen(0);
zenData('release')->gen(0);
zenData('testtask')->gen(0);
zenData('design')->gen(0);
zenData('review')->gen(0);
zenData('researchplan')->gen(0);
zenData('issue')->gen(0);
zenData('risk')->gen(0);
zenData('opportunity')->gen(0);
zenData('auditplan')->gen(0);
zenData('gapanalysis')->gen(0);
zenData('meeting')->gen(0);
/**
+53
View File
@@ -0,0 +1,53 @@
#!/usr/bin/env php
<?php
/**
title=运营界面激活项目测试
timeout=0
cid=73
- 激活项目测试结果 @激活项目成功
*/
chdir(__DIR__);
include '../lib/activeprojectlite.ui.class.php';
$project = zenData('project');
$project->id->range('1-4');
$project->project->range('0');
$project->model->range('kanban');
$project->type->range('project');
$project->auth->range('[]');
$project->grade->range('1');
$project->path->range('`,1,`, `,2,`, `,3,`, `,4,`');
$project->name->range('运营界面项目1, 运营界面项目2, 运营界面项目3, 运营界面项目4');
$project->hasProduct->range('0');
$project->begin->range('(-3w)-(-2w):1D')->type('timestamp')->format('YY/MM/DD');
$project->end->range('(+5w)-(+6w):1D')->type('timestamp')->format('YY/MM/DD');
$project->acl->range('open');
$project->status->range('wait{1}, doing{1}, suspended{1}, closed{1}');
$project->vision->range('lite');
$project->gen(4);
$product = zenData('product');
$product->id->range('1-4');
$product->name->range('影子产品1, 影子产品2, 影子产品3, 影子产品4');
$product->shadow->range('1');
$product->type->range('normal');
$product->vision->range('lite');
$product->gen(4);
$projectProduct = zenData('projectproduct');
$projectProduct->project->range('1-4');
$projectProduct->product->range('1-4');
$projectProduct->gen(4);
$tester = new activeProjectLiteTester();
$tester->login();
$project = array();
r($tester->activeProject($project)) && p('message') && e('激活项目成功'); //激活项目
$tester->closeBrowser();
+51 -18
View File
@@ -3,39 +3,72 @@
/**
title=批量编辑项目测试
title=批量编辑项目
timeout=0
cid=73
cid=23
- 校验项目名称不能为空
- 测试结果 @批量编辑项目表单页提示信息正确
- 批量编辑项目缺少项目名称
- 测试结果 @项目名称必填提示信息正确
- 最终测试状态 @SUCCESS
- 校验计划开始不能为空
- 测试结果 @批量编辑项目表单页提示信息正确
- 批量编辑项目计划完成时间小于计划开始时间
- 测试结果 @计划完成校验提示信息正确
- 最终测试状态 @SUCCESS
- 校验计划完成不能为空
- 测试结果 @批量编辑项目表单页提示信息正确
- 批量编辑项目名称为已有名称
- 测试结果 @项目名称唯一提示信息正确
- 最终测试状态 @SUCCESS
- 批量编辑项目名称
- 测试结果 @批量编辑项目成功
- 最终测试状态 @SUCCESS
- 批量编辑项目最终测试状态 @SUCCESS
*/
chdir(__DIR__);
include '../lib/batcheditproject.ui.class.php';
zendata('project')->loadYaml('execution', false, 2)->gen(10);
$project = zenData('project');
$project->id->range('1-2');
$project->project->range('0');
$project->model->range('scrum');
$project->type->range('project');
$project->auth->range('extend');
$project->storyType->range('story');
$project->path->range('`,1,`');
$project->grade->range('1');
$project->name->range('敏捷项目1, 敏捷项目2');
$project->hasProduct->range('1');
$project->status->range('doing');
$project->begin->range('(-2w)-(-1w):1D')->type('timestamp')->format('YY/MM/DD');
$project->end->range('(+2w)-(+3w):1D')->type('timestamp')->format('YY/MM/DD');
$project->acl->range('open');
$project->vision->range('rnd');
$project->gen(2);
$product = zenData('product');
$product->id->range('1-2');
$product->name->range('产品1, 产品2');
$product->shadow->range('0');
$product->type->range('normal');
$product->status->range('normal');
$product->vision->range('rnd');
$product->gen(2);
$projectProduct = zenData('projectproduct');
$projectProduct->project->range('1-2');
$projectProduct->product->range('1{1}, 2{1}');
$projectProduct->gen(2);
$tester = new batchEditProjectTester();
$tester->login();
$project = array(
array('name' => ''),
array('name' => '敏捷项目1', 'begin' => '', 'end' => '2022-01-31'),
array('name' => '敏捷项目1', 'begin' => '2020-11-01', 'end' => ''),
array('name' => '编辑敏捷项目1', 'begin' => '2020-11-02', 'end' => '2022-01-31'),
array('name' => '', 'end' => date('Y-m-d', strtotime('+30 days'))),
array('begin' => date('Y-m-d'), 'end' => date('Y-m-d', strtotime('-1 day'))),
array('name' => '敏捷项目2', 'end' => date('Y-m-d', strtotime('+1 month'))),
array('name' => '敏捷项目a'.time(), 'acl' => '公开'),
);
r($tester->batchEditProject($project['0'])) && p('message,status') && e('批量编辑项目表单页提示信息正确, SUCCESS'); //校验项目名称不能为空
r($tester->batchEditProject($project['1'])) && p('message,status') && e('批量编辑项目表单页提示信息正确, SUCCESS'); //校验计划开始不能为空
r($tester->batchEditProject($project['2'])) && p('message,status') && e('批量编辑项目表单页提示信息正确, SUCCESS'); //校验计划完成不能为空
r($tester->batchEditProject($project['3'])) && p('status') && e('SUCCESS'); //批量编辑项目
r($tester->checkInput($project['0'])) && p('message,status') && e('项目名称必填提示信息正确,SUCCESS'); // 批量编辑项目缺少项目名称
r($tester->checkInput($project['1'])) && p('message,status') && e('计划完成校验提示信息正确,SUCCESS'); // 批量编辑项目计划完成时间小于计划开始时间
r($tester->checkInput($project['2'])) && p('message,status') && e('项目名称唯一提示信息正确,SUCCESS'); // 批量编辑项目名称为已有名称
r($tester->checkInput($project['3'])) && p('message,status') && e('批量编辑项目成功,SUCCESS'); // 批量编辑项目名称
$tester->closeBrowser();
+80
View File
@@ -0,0 +1,80 @@
#!/usr/bin/env php
<?php
/**
title=敏捷项目迭代列表标签检查
timeout=0
cid=73
- 检查全部标签数量
- 测试结果 @全部标签下条数显示正确
- 最终测试状态 @SUCCESS
- 检查未完成标签数量
- 测试结果 @未完成标签下条数显示正确
- 最终测试状态 @SUCCESS
- 检查未开始标签数量
- 测试结果 @未开始标签下条数显示正确
- 最终测试状态 @SUCCESS
- 检查进行中标签数量
- 测试结果 @进行中标签下条数显示正确
- 最终测试状态 @SUCCESS
- 检查已挂起标签数量
- 测试结果 @已挂起标签下条数显示正确
- 最终测试状态 @SUCCESS
- 检查已延期标签数量
- 测试结果 @已延期标签下条数显示正确
- 最终测试状态 @SUCCESS
- 检查已关闭标签数量
- 测试结果 @已关闭标签下条数显示正确
- 最终测试状态 @SUCCESS
*/
chdir(__DIR__);
include '../lib/execution.ui.class.php';
$project = zenData('project');
$project->id->range('1-16');
$project->project->range('0, 1{15}');
$project->model->range('scrum, []{15}');
$project->type->range('project, sprint{15}');
$project->auth->range('[]');
$project->storytype->range('[]');
$project->parent->range('0, 1{15}');
$project->path->range('`,1,`, `,1,2,`, `,1,3,`, `,1,4,`, `,1,5,`, `,1,6,`, `,1,7,`, `,1,8,`, `,1,9,`, `,1,10,`, `,1,11,`, `,1,12,`, `,1,13,`, `,1,14,`, `,1,15,`');
$project->grade->range('1');
$project->name->range('敏捷项目1, 迭代1, 迭代2, 迭代3, 迭代4, 迭代5, 迭代6, 迭代7, 迭代8, 迭代9, 迭代10, 迭代11, 迭代12, 迭代13, 迭代14, 迭代15');
$project->hasProduct->range('0');
$project->begin->range('(-2M)-(-M):1D')->type('timestamp')->format('YY/MM/DD');
$project->end->range('(-1M)-(+2M):5D')->type('timestamp')->format('YY/MM/DD');
$project->status->range('wait{8}, doing{4}, suspended{3}, closed{1}');
$project->acl->range('open');
$project->vision->range('rnd');
$project->gen(16);
$product = zenData('product');
$product->id->range('1');
$product->program->range('0');
$product->name->range('产品1');
$product->shadow->range('1');
$product->bind->range('1');
$product->type->range('normal');
$product->gen(1);
$projectProduct = zenData('projectproduct');
$projectProduct->project->range('1-16');
$projectProduct->product->range('1');
$projectProduct->gen(16);
$tester = new executionTester();
$tester->login();
r($tester->checkTab('all', '15')) && p('message,status') && e('全部标签下条数显示正确,SUCCESS'); // 检查全部标签数量
r($tester->checkTab('undone', '14')) && p('message,status') && e('未完成标签下条数显示正确,SUCCESS'); // 检查未完成标签数量
r($tester->checkTab('wait', '7')) && p('message,status') && e('未开始标签下条数显示正确,SUCCESS'); // 检查未开始标签数量
r($tester->checkTab('doing', '4')) && p('message,status') && e('进行中标签下条数显示正确,SUCCESS'); // 检查进行中标签数量
r($tester->checkTab('suspended', '3')) && p('message,status') && e('已挂起标签下条数显示正确,SUCCESS'); // 检查已挂起标签数量
r($tester->checkTab('delayed', '5')) && p('message,status') && e('已延期标签下条数显示正确,SUCCESS'); // 检查已延期标签数量
r($tester->checkTab('closed', '1')) && p('message,status') && e('已关闭标签下条数显示正确,SUCCESS'); // 检查已关闭标签数量
$tester->closeBrowser();
+13
View File
@@ -0,0 +1,13 @@
<?php
class batchEditPage extends page
{
public function __construct($webdriver)
{
parent::__construct($webdriver);
$xpath = array(
'settings' => "//*[@id='navbar']/menu/li[14]/a/span",
'alertModal' => "//*[@class='modal modal-async load-indicator modal-alert modal-trans show in']/div/div/div[2]",
);
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
}
}
+3
View File
@@ -55,6 +55,9 @@ class browsePage extends page
'kanbanName' => "//*[@id='mainContent']/div[2]/div/div/div[2]/div[1]/div/div[2]/div/a",
/*运营界面项目列表*/
'projectNameLite' => "//*[@id='table-project-browse']/div[2]/div[1]/div/div[2]/div/a",
/*批量编辑项目*/
'selectAllBtn' => "//*[@id='table-project-browse']/div[3]/div[1]/div",
'batchEditBtn' => "//*[@id='table-project-browse']/div[3]/nav[1]/nav/button/span",
);
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
}
@@ -25,6 +25,8 @@ class executionPage extends page
'delayedTab' => "//*[@id='featureBar']/menu/li[6]/a/span[1]",
'closedTab' => "//*[@id='featureBar']/menu/li[7]/a/span[1]",
'num' => "//*[@id='featureBar']/menu/li[1]/a/span[2]",
/* 研发界面元素 */
'numDom' => "//*[@id='table-project-execution']/div[3]/div[2]/strong[1]",
);
$this->dom->xpath = array_merge($this->dom->xpath, $xpath);
}
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . '/test/lib/init.php';
include dirname(__FILE__, 2) . '/lib/projectzen.unittest.class.php';
su('admin');
zenData('project')->gen(10);
/**
title=测试 projectZen::prepareCreateExtras();
timeout=0
cid=1
- 执行project模块的prepareCreateExtrasTest方法,参数是$testData, 0 属性end @『计划完成』不能为空。
- 执行project模块的prepareCreateExtrasTest方法,参数是$testData, 0 属性days @可用工作日不能超过『-5』天
- 执行project模块的prepareCreateExtrasTest方法,参数是$testData, 0 属性end @2025-07-17
- 执行project模块的prepareCreateExtrasTest方法,参数是$testData, 1 属性type @project
- 执行project模块的prepareCreateExtrasTest方法,参数是$testData, 0 属性acl @privately
*/
global $tester;
$project = new projectZenTest();
$testData = array();
$testData['name'] = 'test0707';
r($project->prepareCreateExtrasTest($testData, 0)) && p('end') && e('『计划完成』不能为空。');
$testData['end'] = '2025-07-01';
r($project->prepareCreateExtrasTest($testData, 0)) && p('days') && e('可用工作日不能超过『-5』天');
$testData['end'] = '2025-07-17';
r($project->prepareCreateExtrasTest($testData, 0)) && p('end') && e('2025-07-17');
r($project->prepareCreateExtrasTest($testData, 1)) && p('type') && e('project');
$testData['acl'] = 'private';
r($project->prepareCreateExtrasTest($testData, 0)) && p('acl') && e('private');
+1 -1
View File
@@ -25,7 +25,7 @@ class projectreleaseModel extends model
* @access public
* @return array
*/
public function getList(int $projectID, string $type = 'all', string $orderBy = 't1.date_desc', object $pager = null): array
public function getList(int $projectID, string $type = 'all', string $orderBy = 't1.date_desc', ?object $pager = null): array
{
$releases = $this->dao->select('t1.*, t2.name AS productName, t2.type AS productType')->from(TABLE_RELEASE)->alias('t1')
->leftJoin(TABLE_PRODUCT)->alias('t2')->on('t1.product = t2.id')
@@ -13,12 +13,12 @@ class changeStatus extends tester
{
$this->switchVision('lite');
$form = $this->initForm('projectstory', 'view', $storyUrl, 'appIframe-project');
$form->wait(1);
$form->wait(2);
$form->dom->closeBtn->click();
$form->wait(1);
$form->wait(2);
$form->dom->closestoryBtn->click();
$viewPage = $this->initForm('projectstory', 'view', $storyUrl, 'appIframe-project');
$form->wait(1);
$viewPage->wait(2);
$status = $viewPage->dom->storyStatus->getText();
return($status == $this->lang->story->statusList->closed)
? $this->success('目标关闭成功')
@@ -36,12 +36,12 @@ class changeStatus extends tester
{
$this->switchVision('lite');
$form = $this->initForm('projectstory', 'view', $storyUrl, 'appIframe-project');
$form->wait(1);
$form->wait(2);
$form->dom->activateBtn->click();
$form->wait(1);
$form->wait(2);
$form->dom->activateStoryBtn->click();
$viewPage = $this->initForm('projectstory', 'view', $storyUrl, 'appIframe-project');
$form->wait(1);
$viewPage->wait(2);
$status = $viewPage->dom->storyStatus->getText();
return($status != $this->lang->story->statusList->closed)
? $this->success('目标激活成功')
@@ -95,6 +95,15 @@ $storyreview->reviewer->range('admin');
$storyreview->result->range('pass{4},{8}');
$storyreview->gen(12);
$projectstory = ZenData('projectstory');
$projectstory->project->range('1');
$projectstory->product->range('1');
$projectstory->branch->range('0');
$projectstory->story->range('1-12');
$projectstory->version->range('1');
$projectstory->order->range('1-12');
$projectstory->gen(12);
$action = zenData('action');
$action->id->range('1-37');
$action->objectType->range('product,project,story{35}');
+3 -3
View File
@@ -145,7 +145,7 @@ class releaseModel extends model
* @access public
* @return object[]
*/
public function getList(int $productID, string|int $branch = 'all', string $type = 'all', string $orderBy = 't1.date_desc', string $releaseQuery = '', object $pager = null): array
public function getList(int $productID, string|int $branch = 'all', string $type = 'all', string $orderBy = 't1.date_desc', string $releaseQuery = '', ?object $pager = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getReleases();
@@ -1194,7 +1194,7 @@ class releaseModel extends model
* @access public
* @return array
*/
public function getStoryList(string $storyIdList, string|int $branch, string $orderBy = '', object $pager = null): array
public function getStoryList(string $storyIdList, string|int $branch, string $orderBy = '', ?object $pager = null): array
{
$stories = $this->dao->select("t1.*,t2.id as buildID, t2.name as buildName, IF(t1.`pri` = 0, {$this->config->maxPriValue}, t1.`pri`) as priOrder")->from(TABLE_STORY)->alias('t1')
->leftJoin(TABLE_BUILD)->alias('t2')->on("FIND_IN_SET(t1.id, t2.stories)")
@@ -1232,7 +1232,7 @@ class releaseModel extends model
* @access public
* @return array
*/
public function getBugList(string $bugIdList, string $orderBy = '', object $pager = null, string $type = 'linked'): array
public function getBugList(string $bugIdList, string $orderBy = '', ?object $pager = null, string $type = 'linked'): array
{
$bugs = array();
+4 -4
View File
@@ -96,7 +96,7 @@ class repoModel extends model
* @access public
* @return array
*/
public function getList(int $projectID = 0, string $SCM = '', string $orderBy = 'id_desc', object $pager = null, bool $getCodePath = false, bool $lastSubmitTime = false, string $type = '', int $param = 0): array
public function getList(int $projectID = 0, string $SCM = '', string $orderBy = 'id_desc', ?object $pager = null, bool $getCodePath = false, bool $lastSubmitTime = false, string $type = '', int $param = 0): array
{
$repoQuery = $type == 'bySearch' ? $this->repoTao->processSearchQuery($param) : '';
$repos = $this->getListByCondition($repoQuery, $SCM, $orderBy, $pager);
@@ -844,7 +844,7 @@ class repoModel extends model
* @access public
* @return array
*/
public function getCommits(object $repo, string $entry, string $revision = 'HEAD', string $type = 'dir', object|null $pager = null, string $begin = '', string $end = '', object|string|null $query = null): array
public function getCommits(object $repo, string $entry, string $revision = 'HEAD', string $type = 'dir', ?object $pager = null, string $begin = '', string $end = '', mixed $query = null): array
{
if(common::isTutorialMode()) return $this->loadModel('tutorial')->getCommits();
@@ -2105,7 +2105,7 @@ class repoModel extends model
* @access public
* @return array
*/
public function getFileTree(object $repo, string $branch = '', array $diffs = null): array
public function getFileTree(object $repo, string $branch = '', ?array $diffs = null): array
{
set_time_limit(0);
$allFiles = array();
@@ -2964,7 +2964,7 @@ class repoModel extends model
* @access public
* @return array
*/
public function getListByCondition(string $repoQuery, string $SCM, string $orderBy = 'id_desc', object $pager = null): array
public function getListByCondition(string $repoQuery, string $SCM, string $orderBy = 'id_desc', ?object $pager = null): array
{
return $this->dao->select('*')->from(TABLE_REPO)
->where('deleted')->eq('0')
@@ -20,7 +20,7 @@ cid=1
- 测试获取执行 102 的json数据 @0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2
- 测试获取执行 103 的json数据 @0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2
- 测试获取执行 103 的json数据 @0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2
- 测试获取执行 104 的json数据 @0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2
@@ -34,6 +34,6 @@ $executionID = array(101, 102, 103, 104, 105);
r($report->createSingleJSONTest($executionID[0])) && p() && e('0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2'); // 测试获取执行 101 的json数据
r($report->createSingleJSONTest($executionID[1])) && p() && e('0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2'); // 测试获取执行 102 的json数据
r($report->createSingleJSONTest($executionID[2])) && p() && e('0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2'); // 测试获取执行 103 的json数据
r($report->createSingleJSONTest($executionID[2])) && p() && e('0,0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2'); // 测试获取执行 103 的json数据
r($report->createSingleJSONTest($executionID[3])) && p() && e('0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2,2'); // 测试获取执行 104 的json数据
r($report->createSingleJSONTest($executionID[4])) && p() && e('0,0,0,0,0,0,0,0,2,2,2,2,2,2,2,2,2,2'); // 测试获取执行 105 的json数据
@@ -47,6 +47,7 @@ $filter5 = array('type' => 'stackedBar');
$filter6 = array('type' => 'bar');
list($component2, $chart2) = getComponetAndChart($screen, $filter2);
$component2->option->dataset = (object)$component2->option->dataset;
$screen->getBarChartOption($component2, $chart2);
r(isset($component2) && $component2->option->dataset && $component2->option->dataset->dimensions[0] == 'name' && count($component2->option->dataset->source) == 5) && p('') && e('1'); //测试type为cluBarY的图表是否显示正确,生成的指标项和数据项是否正确。
@@ -54,13 +55,15 @@ list($component3, $chart3) = getComponetAndChart($screen, $filter3);
r(is_null($component3) || is_null($chart3)) && p('') && e(1); //测试type为stackedBarY的图表是否显示正确,由于目前系统里没有这种类型的图表,故不作展示。
list($component4, $chart4) = getComponetAndChart($screen, $filter4);
$component4->option->dataset = (object)$component4->option->dataset;
$screen->getBarChartOption($component4, $chart4);
r(isset($component4->option->dataset->dimensions[0]) && $component4->option->dataset->dimensions[0] == 'project' && count($component4->option->dataset->source) == 5 ) && p('') && e(1); //测试type为cluBarX的图表是否显示正确,生成的指标项和数据项是否正确。
list($component5, $chart5) = getComponetAndChart($screen, $filter5);
$component5->option->dataset = (object)$component5->option->dataset;
$screen->getBarChartOption($component5, $chart5);
$dataset = isset($component5) && $component5->option->dataset ? $component5->option->dataset : null;
r($dataset && $dataset->dimensions[0] == '年份' && count($dataset->source) >= 1) && p('') && e(1); //测试type为stackedBar的图表是否显示正确,生成的指标项和数据项是否正确。
list($component6, $chart6) = getComponetAndChart($screen, $filter6);
r(is_null($component6) && is_null($chart6)) && p('') && e(1); //测试type为bar的图表是否显示正确,由于目前系统里没有这种类型的图表,故不作展示。
r(is_null($component6) && is_null($chart6)) && p('') && e(1); //测试type为bar的图表是否显示正确,由于目前系统里没有这种类型的图表,故不作展示。
+28 -4
View File
@@ -34,9 +34,21 @@ class search extends control
$module = empty($module) ? $this->session->searchParams['module'] : $module;
$searchParams = $module . 'searchParams';
$searchForm = $module . 'Form';
$funcName = $_SESSION[$searchParams]['funcName'] ?? '';
$funcArgs = $_SESSION[$searchParams]['funcArgs'] ?? [];
$fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields;
$params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params;
if($funcName)
{
$funcArgs[] = true; // 处理选项列表。
$this->loadModel($module)->$funcName(...$funcArgs);
$fields = empty($fields) ? $this->config->$module->search['fields'] : $fields;
$params = empty($params) ? $this->config->$module->search['params'] : $params;
}
else
{
$fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields;
$params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params;
}
$_SESSION['searchParams']['module'] = $module;
if(empty($_SESSION[$searchForm])) $this->search->initSession($module, $fields, $params);
@@ -82,9 +94,21 @@ class search extends control
$module = empty($module) ? $this->session->searchParams['module'] : $module;
$searchParams = $module . 'searchParams';
$searchForm = $module . 'Form';
$funcName = $_SESSION[$searchParams]['funcName'] ?? '';
$funcArgs = $_SESSION[$searchParams]['funcArgs'] ?? [];
$fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields;
$params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params;
if($funcName)
{
$funcArgs[] = true; // 处理选项列表。
$this->loadModel($module)->$funcName(...$funcArgs);
$fields = empty($fields) ? $this->config->$module->search['fields'] : $fields;
$params = empty($params) ? $this->config->$module->search['params'] : $params;
}
else
{
$fields = empty($fields) ? json_decode($_SESSION[$searchParams]['searchFields'], true) : $fields;
$params = empty($params) ? json_decode($_SESSION[$searchParams]['fieldParams'], true) : $params;
}
$_SESSION['searchParams']['module'] = $module;
if(empty($_SESSION[$searchForm])) $this->search->initOldSession($module, $fields, $params);
+35 -10
View File
@@ -28,13 +28,26 @@ class searchModel extends model
if($this->config->edition != 'open') $searchConfig = $this->searchTao->processBuildinFields($module, $searchConfig);
$searchParams['module'] = $searchConfig['module'];
$searchParams['searchFields'] = json_encode($searchConfig['fields']);
$searchParams['fieldParams'] = json_encode($searchConfig['params']);
$searchParams['actionURL'] = $searchConfig['actionURL'];
$searchParams['style'] = zget($searchConfig, 'style', 'full');
$searchParams['onMenuBar'] = zget($searchConfig, 'onMenuBar', 'no');
$searchParams['queryID'] = isset($searchConfig['queryID']) ? $searchConfig['queryID'] : 0;
$searchParams['module'] = $searchConfig['module'];
$searchParams['actionURL'] = $searchConfig['actionURL'];
$searchParams['style'] = zget($searchConfig, 'style', 'full');
$searchParams['onMenuBar'] = zget($searchConfig, 'onMenuBar', 'no');
$searchParams['queryID'] = isset($searchConfig['queryID']) ? $searchConfig['queryID'] : 0;
$funcArgs = func_get_args();
$funcName = $funcArgs[1] ?? '';
unset($funcArgs[0], $funcArgs[1]);
if($funcName)
{
$searchParams['funcName'] = $funcName;
$searchParams['funcArgs'] = $funcArgs;
}
else
{
$searchParams['searchFields'] = json_encode($searchConfig['fields']);
$searchParams['fieldParams'] = json_encode($searchConfig['params']);
}
$this->session->set($module . 'searchParams', $searchParams);
}
@@ -97,11 +110,23 @@ class searchModel extends model
/* Init vars. */
$module = $this->post->module;
$searchParams = $module . 'searchParams';
$searchFields = json_decode($_SESSION[$searchParams]['searchFields']);
$fieldParams = json_decode($_SESSION[$searchParams]['fieldParams']);
$groupItems = $this->config->search->groupItems;
$groupAndOr = strtoupper($this->post->groupAndOr);
if($groupAndOr != 'AND' && $groupAndOr != 'OR') $groupAndOr = 'AND';
$funcName = $_SESSION[$searchParams]['funcName'] ?? '';
$funcArgs = $_SESSION[$searchParams]['funcArgs'] ?? [];
if($funcName)
{
$funcArgs[] = true; // 处理选项列表。
$this->loadModel($module)->$funcName(...$funcArgs);
$searchFields = json_decode(json_encode($this->config->$module->search['fields']));
$fieldParams = json_decode(json_encode($this->config->$module->search['params']));
}
else
{
$searchFields = json_decode($_SESSION[$searchParams]['searchFields']);
$fieldParams = json_decode($_SESSION[$searchParams]['fieldParams']);
}
$queryForm = $this->searchTao->initSession($module, $searchFields, $fieldParams);
@@ -598,7 +623,7 @@ class searchModel extends model
* @access public
* @return array
*/
public function getList(string $keywords, array|string $type, object $pager = null): array
public function getList(string $keywords, array|string $type, ?object $pager = null): array
{
list($words, $againstCond, $likeCondition) = $this->searchTao->getSqlParams($keywords);
$allowedObjects = $this->searchTao->getAllowedObjects($type);

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