This commit is contained in:
wangyidong
2023-05-04 13:28:16 +08:00
114 changed files with 3186 additions and 1589 deletions
+54 -54
View File
@@ -14,7 +14,7 @@ CREATE TABLE IF NOT EXISTS `zt_acl` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_action`;
CREATE TABLE IF NOT EXISTS `zt_action` (
`id` int(9) unsigned NOT NULL AUTO_INCREMENT,
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`objectType` varchar(30) NOT NULL DEFAULT '',
`objectID` mediumint(8) unsigned NOT NULL DEFAULT '0',
`product` text NULL,
@@ -37,8 +37,8 @@ CREATE TABLE IF NOT EXISTS `zt_action` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_api_lib_release`;
CREATE TABLE IF NOT EXISTS `zt_api_lib_release` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`lib` int(11) UNSIGNED NOT NULL DEFAULT 0,
`desc` varchar(255) NOT NULL DEFAULT '',
`version` varchar(255) NOT NULL DEFAULT '',
`snap` mediumtext NULL,
@@ -48,10 +48,10 @@ CREATE TABLE IF NOT EXISTS `zt_api_lib_release` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_api`;
CREATE TABLE IF NOT EXISTS `zt_api` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`product` varchar(255) NOT NULL DEFAULT '',
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`module` int UNSIGNED NOT NULL DEFAULT 0,
`lib` int(11) UNSIGNED NOT NULL DEFAULT 0,
`module` int(11) UNSIGNED NOT NULL DEFAULT 0,
`title` varchar(100) NOT NULL DEFAULT '',
`path` varchar(255) NOT NULL DEFAULT '',
`protocol` varchar(10) NOT NULL DEFAULT '',
@@ -61,7 +61,7 @@ CREATE TABLE IF NOT EXISTS `zt_api` (
`status` varchar(20) NOT NULL DEFAULT '',
`owner` varchar(30) NOT NULl DEFAULT 0,
`desc` mediumtext NULL,
`version` smallint UNSIGNED NOT NULL DEFAULT 0,
`version` smallint(6) UNSIGNED NOT NULL DEFAULT 0,
`params` text NULL,
`paramsExample` text NUll,
`responseExample` text NUll,
@@ -76,9 +76,9 @@ CREATE TABLE IF NOT EXISTS `zt_api` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_apispec`;
CREATE TABLE IF NOT EXISTS `zt_apispec` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`doc` int UNSIGNED NOT NULL DEFAULT 0,
`module` int UNSIGNED NOT NULL DEFAULT 0,
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`doc` int(11) UNSIGNED NOT NULL DEFAULT 0,
`module` int(11) UNSIGNED NOT NULL DEFAULT 0,
`title` varchar(100) NOT NULL DEFAULT '',
`path` varchar(255) NOT NULL DEFAULT '',
`protocol` varchar(10) NOT NULL DEFAULT '',
@@ -88,7 +88,7 @@ CREATE TABLE IF NOT EXISTS `zt_apispec` (
`status` varchar(20) NOT NULL DEFAULT '',
`owner` varchar(255) NOT NULl DEFAULT 0,
`desc` mediumtext NULL,
`version` smallint UNSIGNED NOT NULL DEFAULT 0,
`version` smallint(6) UNSIGNED NOT NULL DEFAULT 0,
`params` text NULL,
`paramsExample` text NUll,
`responseExample` text NUll,
@@ -99,12 +99,12 @@ CREATE TABLE IF NOT EXISTS `zt_apispec` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_apistruct`;
CREATE TABLE IF NOT EXISTS `zt_apistruct` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`lib` int UNSIGNED NOT NULL DEFAULT 0,
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`lib` int(11) UNSIGNED NOT NULL DEFAULT 0,
`name` varchar(30) NOT NULL DEFAULT '',
`type` varchar(50) NOT NULL DEFAULT '',
`desc` mediumtext NULL,
`version` smallint unsigned NOT NULL DEFAULT 0,
`version` smallint(6) unsigned NOT NULL DEFAULT 0,
`attribute` text NULL,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NULL,
@@ -115,12 +115,12 @@ CREATE TABLE IF NOT EXISTS `zt_apistruct` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_apistruct_spec`;
CREATE TABLE IF NOT EXISTS `zt_apistruct_spec` (
`id` int UNSIGNED NOT NULL AUTO_INCREMENT,
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`type` varchar(50) NOT NULL DEFAULT '',
`desc` varchar(255) NOT NULL DEFAULT '',
`attribute` text NULL,
`version` smallint unsigned NOT NULL DEFAULT 0,
`version` smallint(6) unsigned NOT NULL DEFAULT 0,
`addedBy` varchar(30) NOT NULL DEFAULT 0,
`addedDate` datetime NULL,
primary key (`id`)
@@ -142,7 +142,7 @@ CREATE TABLE IF NOT EXISTS `zt_approval` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_approvalflow`;
CREATE TABLE IF NOT EXISTS `zt_approvalflow` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`code` varchar(100) NOT NULL DEFAULT '',
`desc` mediumtext NULL,
@@ -243,7 +243,7 @@ CREATE TABLE IF NOT EXISTS `zt_branch` (
`desc` varchar(255) NOT NULL DEFAULT '',
`createdDate` date NULL,
`closedDate` date NULL,
`order` smallint unsigned NOT NULL DEFAULT '0',
`order` smallint(6) unsigned NOT NULL DEFAULT '0',
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `product` (`product`)
@@ -418,7 +418,7 @@ CREATE TABLE IF NOT EXISTS `zt_casestep` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
`parent` mediumint(8) unsigned NOT NULL default '0',
`case` mediumint(8) unsigned NOT NULL default '0',
`version` smallint(3) unsigned NOT NULL default '0',
`version` smallint(6) unsigned NOT NULL default '0',
`type` varchar(10) NOT NULL DEFAULT 'step',
`desc` text NULL,
`expect` text NULL,
@@ -432,14 +432,14 @@ CREATE TABLE IF NOT EXISTS `zt_cfd` (
`execution` int(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL DEFAULT '',
`name` char(30) NOT NULL DEFAULT '',
`count` smallint NOT NULL DEFAULT '0',
`count` smallint(6) NOT NULL DEFAULT '0',
`date` date NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE UNIQUE INDEX `execution_type_name_date` ON `zt_cfd`(`execution`,`type`,`name`,`date`);
-- DROP TABLE IF EXISTS `zt_chart`;
CREATE TABLE IF NOT EXISTS `zt_chart` (
`id` mediumint unsigned NOT NULL AUTO_INCREMENT,
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`dimension` mediumint(8) unsigned NOT NULL DEFAULT '0',
`type` varchar(30) NOT NULL DEFAULT '',
@@ -448,7 +448,7 @@ CREATE TABLE IF NOT EXISTS `zt_chart` (
`desc` text NULL,
`settings` mediumtext NULL,
`filters` mediumtext NULL,
`step` tinyint(1) unsigned NOT NULL DEFAULT '0',
`step` tinyint(3) unsigned NOT NULL DEFAULT '0',
`fields` mediumtext NULL,
`langs` text NULL,
`sql` mediumtext NULL,
@@ -459,7 +459,7 @@ CREATE TABLE IF NOT EXISTS `zt_chart` (
`createdDate` datetime NULL,
`editedBy` varchar(30) NOT NULL DEFAULT '',
`editedDate` datetime NULL,
`deleted` tinyint NOT NULL DEFAULT '0',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_screen`;
@@ -560,25 +560,25 @@ CREATE TABLE `zt_dashboard` (
`id` mediumint(8) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`dimension` int(8) NOT NULL default 0,
`module` mediumint NOT NULL DEFAULT '0',
`module` mediumint(8) NOT NULL DEFAULT '0',
`desc` mediumtext NULL,
`layout` mediumtext NULL,
`filters` mediumtext NULL,
`createdBy` varchar(30) NOT NULL DEFAULT '',
`createdDate` datetime NULL,
`deleted` tinyint NOT NULL DEFAULT '0',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_dataset`;
CREATE TABLE `zt_dataset` (
`id` mediumint unsigned NOT NULL AUTO_INCREMENT,
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(155) NOT NULL DEFAULT '',
`sql` text NULL,
`fields` mediumtext NULL,
`objects` mediumtext NULL,
`createdBy` varchar(30) NOT NULL DEFAULT '',
`createdDate` datetime NULL,
`deleted` tinyint NOT NULL DEFAULT '0',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_dataview`;
@@ -596,7 +596,7 @@ CREATE TABLE IF NOT EXISTS `zt_dataview` (
`createdDate` datetime NULL,
`editedBy` varchar(30) NULL DEFAULT '',
`editedDate` datetime NULL,
`deleted` tinyint NOT NULL DEFAULT '0',
`deleted` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_dept`;
@@ -778,7 +778,7 @@ CREATE TABLE IF NOT EXISTS `zt_entry` (
`desc` mediumtext NULL,
`createdBy` varchar(30) NOT NULL DEFAULT '',
`createdDate` datetime NULL,
`calledTime` int(10) unsigned NOT NULL DEFAULT '0',
`calledTime` int(11) unsigned NOT NULL DEFAULT '0',
`editedBy` varchar(30) NOT NULL DEFAULT '',
`editedDate` datetime NULL,
`deleted` enum('0', '1') NOT NULL DEFAULT '0',
@@ -824,7 +824,7 @@ CREATE TABLE IF NOT EXISTS `zt_file` (
`pathname` char(100) NOT NULL DEFAULT '',
`title` varchar(255) NOT NULL DEFAULT '',
`extension` char(30) NOT NULL DEFAULT '',
`size` int(10) unsigned NOT NULL DEFAULT '0',
`size` int(11) unsigned NOT NULL DEFAULT '0',
`objectType` char(30) NOT NULL DEFAULT '',
`objectID` mediumint(9) NOT NULL DEFAULT '0',
`addedBy` char(30) NOT NULL DEFAULT '',
@@ -869,7 +869,7 @@ CREATE TABLE IF NOT EXISTS `zt_holiday` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_history`;
CREATE TABLE IF NOT EXISTS `zt_history` (
`id` int(9) unsigned NOT NULL auto_increment,
`id` int(11) unsigned NOT NULL auto_increment,
`action` mediumint(8) unsigned NOT NULL default '0',
`field` varchar(30) NOT NULL default '',
`old` text NULL,
@@ -1119,7 +1119,7 @@ CREATE TABLE IF NOT EXISTS `zt_mr` (
`sourceBranch` varchar(100) NOT NULL DEFAULT '',
`targetProject` varchar(50) NOT NULL DEFAULT '',
`targetBranch` varchar(100) NOT NULL DEFAULT '',
`mriid` int unsigned NOT NULL DEFAULT '0',
`mriid` int(11) unsigned NOT NULL DEFAULT '0',
`title` varchar(255) NOT NULL DEFAULT '',
`description` text NULL,
`assignee` varchar(255) NOT NULL DEFAULT '',
@@ -1159,10 +1159,10 @@ CREATE TABLE IF NOT EXISTS `zt_mrapproval` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_notify`;
CREATE TABLE IF NOT EXISTS `zt_notify` (
`id` mediumint unsigned NOT NULL AUTO_INCREMENT,
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`objectType` varchar(50) NOT NULL DEFAULT '',
`objectID` mediumint unsigned NOT NULL DEFAULT '0',
`action` mediumint NOT NULL DEFAULT '0',
`objectID` mediumint(8) unsigned NOT NULL DEFAULT '0',
`action` mediumint(9) NOT NULL DEFAULT '0',
`toList` varchar(255) NOT NULL DEFAULT '',
`ccList` text NULL,
`subject` varchar(255) NOT NULL DEFAULT '',
@@ -1484,7 +1484,7 @@ CREATE TABLE IF NOT EXISTS `zt_repo` (
`desc` text NULL,
`extra` char(30) NOT NULL DEFAULT '',
`preMerge` enum('0','1') COLLATE 'utf8_general_ci' NOT NULL DEFAULT '0',
`job` mediumint unsigned NOT NULL DEFAULT '0',
`job` mediumint(8) unsigned NOT NULL DEFAULT '0',
`fileServerUrl` text COLLATE 'utf8_general_ci' NULL,
`fileServerAccount` varchar(40) NOT NULL default '',
`fileServerPassword` varchar(100) NOT NULL default '',
@@ -1502,7 +1502,7 @@ CREATE TABLE IF NOT EXISTS `zt_repobranch` (
CREATE UNIQUE INDEX `repo_revision_branch` ON `zt_repobranch`(`repo`,`revision`,`branch`);
-- DROP TABLE IF EXISTS `zt_repofiles`;
CREATE TABLE IF NOT EXISTS `zt_repofiles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`repo` mediumint(8) unsigned NOT NULL DEFAULT '0',
`revision` mediumint(8) unsigned NOT NULL DEFAULT '0',
`path` varchar(255) NOT NULL DEFAULT '',
@@ -1553,7 +1553,7 @@ CREATE TABLE IF NOT EXISTS `zt_searchdict` (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_searchindex`;
CREATE TABLE IF NOT EXISTS `zt_searchindex` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`vision` varchar(10) NOT NULL DEFAULT 'rnd',
`objectType` char(20) NOT NULL DEFAULT '',
`objectID` mediumint(9) NOT NULL DEFAULT '0',
@@ -1889,7 +1889,7 @@ CREATE TABLE IF NOT EXISTS `zt_testsuite` (
`name` varchar(255) NOT NULL DEFAULT '',
`desc` mediumtext NULL,
`type` varchar(20) NOT NULL DEFAULT '',
`order` smallint unsigned NOT NULL DEFAULT '0',
`order` smallint(6) unsigned NOT NULL DEFAULT '0',
`addedBy` char(30) NOT NULL DEFAULT '',
`addedDate` datetime NULL,
`lastEditedBy` char(30) NOT NULL DEFAULT '',
@@ -1992,7 +1992,7 @@ CREATE TABLE IF NOT EXISTS `zt_user` (
`visits` mediumint(8) unsigned NOT NULL DEFAULT '0',
`visions` varchar(20) NOT NULL DEFAULT 'rnd,lite',
`ip` char(15) NOT NULL DEFAULT '',
`last` int(10) unsigned NOT NULL DEFAULT '0',
`last` int(11) unsigned NOT NULL DEFAULT '0',
`fails` tinyint(5) NOT NULL DEFAULT '0',
`locked` datetime NULL,
`feedback` enum('0','1') NOT NULL DEFAULT '0',
@@ -2397,9 +2397,9 @@ INSERT INTO `zt_cron` (`m`, `h`, `dom`, `mon`, `dow`, `command`, `remark`, `type
-- DROP TABLE IF EXISTS `zt_relationoftasks`;
CREATE TABLE IF NOT EXISTS `zt_relationoftasks` (
`id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT ,
`execution` MEDIUMINT(8) UNSIGNED NOT NULL ,
`pretask` MEDIUMINT(8) UNSIGNED NOT NULL ,
`id` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT ,
`execution` mediumint(8) UNSIGNED NOT NULL ,
`pretask` mediumint(8) UNSIGNED NOT NULL ,
`condition` ENUM( 'begin', 'end' ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`task` MEDIUMINT( 8 ) UNSIGNED NOT NULL ,
`action` ENUM( 'begin', 'end' ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
@@ -2470,7 +2470,7 @@ CREATE TABLE IF NOT EXISTS `zt_feedback` (
`type` char(30) NOT NULL DEFAULT '',
`solution` char(30) NOT NULL DEFAULT '',
`desc` text NULL,
`pri` tinyint unsigned NOT NULL DEFAULT 2,
`pri` tinyint(3) unsigned NOT NULL DEFAULT 2,
`status` varchar(30) NOT NULL DEFAULT '',
`subStatus` varchar(30) NOT NULL default '',
`public` enum('0','1') NOT NULL DEFAULT '0',
@@ -2518,13 +2518,13 @@ CREATE TABLE IF NOT EXISTS `zt_ticket` (
`startedBy` varchar(255) NOT NULL DEFAULT '',
`startedDate` datetime NULL,
`deadline` date NULL,
`pri` tinyint unsigned NOT NULL DEFAULT '0',
`pri` tinyint(3) unsigned NOT NULL DEFAULT '0',
`estimate` float unsigned NOT NULL,
`left` float unsigned NOT NULL,
`status` varchar(30) NOT NULL DEFAULT '',
`openedBy` varchar(30) NOT NULL DEFAULT '',
`openedDate` datetime NULL,
`activatedCount` int(10) NOT NULL DEFAULT '0',
`activatedCount` int(11) NOT NULL DEFAULT '0',
`activatedBy` varchar(30) NOT NULL DEFAULT '',
`activatedDate` datetime NULL,
`closedBy` varchar(30) NOT NULL DEFAULT '',
@@ -2559,9 +2559,9 @@ CREATE TABLE IF NOT EXISTS `zt_ticketsource` (
-- DROP TABLE IF EXISTS `zt_ticketrelation`;
CREATE TABLE IF NOT EXISTS `zt_ticketrelation` (
`id` mediumint unsigned NOT NULL AUTO_INCREMENT,
`ticketId` mediumint unsigned NOT NULL DEFAULT '0',
`objectId` mediumint NOT NULL DEFAULT '0',
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`ticketId` mediumint(8) unsigned NOT NULL DEFAULT '0',
`objectId` mediumint(9) NOT NULL DEFAULT '0',
`objectType` varchar(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `ticketId` (`ticketId`)
@@ -12632,7 +12632,7 @@ CREATE TABLE IF NOT EXISTS `zt_auditcl` (
`type` char(30) NOT NULL DEFAULT '',
`title` varchar(255) NOT NULL DEFAULT '',
`objectType` char(30) NOT NULL DEFAULT '',
`objectID` int(10) NOT NULL DEFAULT '0',
`objectID` int(11) NOT NULL DEFAULT '0',
`assignedTo` varchar(30) NOT NULL DEFAULT '',
`status` varchar(30) NOT NULL DEFAULT '',
`createdBy` varchar(30) NOT NULL DEFAULT '',
@@ -12919,7 +12919,7 @@ CREATE TABLE IF NOT EXISTS `zt_meeting` (
`host` varchar(30) NOT NULL DEFAULT '',
`participant` text NULL,
`date` date NULL,
`room` int NOT NULL DEFAULT '0',
`room` int(11) NOT NULL DEFAULT '0',
`minutes` text NULL,
`minutedBy` varchar(30) NOT NULL DEFAULT '',
`minutedDate` datetime NULL,
@@ -12938,7 +12938,7 @@ CREATE TABLE IF NOT EXISTS `zt_meetingroom` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
`position` varchar(30) NOT NULL DEFAULT '',
`seats` int NOT NULL DEFAULT '0',
`seats` int(11) NOT NULL DEFAULT '0',
`equipment` varchar(255) NOT NULL DEFAULT '',
`openTime` varchar(255) NOT NULL DEFAULT '',
`createdBy` varchar(30) NOT NULL DEFAULT '',
@@ -12955,7 +12955,7 @@ CREATE TABLE IF NOT EXISTS `zt_assetlib` (
`name` varchar(255) NOT NULL DEFAULT '',
`type` varchar(255) NOT NULL DEFAULT '',
`desc` mediumtext NULL,
`order` SMALLINT UNSIGNED NOT NULL DEFAULT '0',
`order` smallint(6) UNSIGNED NOT NULL DEFAULT '0',
`createdBy` varchar(30) NOT NULL DEFAULT '',
`createdDate` datetime NULL,
`editedBy` varchar(30) NOT NULL DEFAULT '',
@@ -14222,7 +14222,7 @@ CREATE TABLE IF NOT EXISTS `zt_pivot` (
`objects` mediumtext NULL,
`settings` mediumtext NULL,
`filters` mediumtext NULL,
`step` tinyint(1) unsigned NOT NULL DEFAULT '0',
`step` tinyint(3) unsigned NOT NULL DEFAULT '0',
`stage` enum('draft','published') NOT NULL DEFAULT 'draft',
`builtin` enum('0', '1') NOT NULL DEFAULT '0',
`createdBy` varchar(30) NOT NULL DEFAULT '',
+16 -16
View File
@@ -221,11 +221,11 @@ class baseControl
}
elseif(helper::isAjaxRequest())
{
die(json_encode(array('result' => false, 'message' => $this->lang->error->loginTimeout)));
helper::end(json_encode(array('result' => false, 'message' => $this->lang->error->loginTimeout)));
}
$referer = helper::safe64Encode($uri);
die(js::locate(helper::createLink('user', 'login', "referer=$referer")));
helper::end(js::locate(helper::createLink('user', 'login', "referer=$referer")));
}
/**
@@ -1018,13 +1018,14 @@ class baseControl
* 直接输出data数据,通常用于ajax请求中。
* Send data directly, for ajax requests.
*
* @param mixed $data
* @param string $type
* @access public
* @return void
*/
public function send($data, string $type = 'json')
{
if($type != 'json') die();
if($type != 'json') return helper::end();
$data = (array)$data;
@@ -1055,7 +1056,7 @@ class baseControl
for($i = 0; $i < $obLevel; $i++) ob_end_clean();
$response = helper::removeUTF8Bom(urldecode(json_encode($data)));
die($response);
return helper::end($response);
}
/**
@@ -1066,8 +1067,8 @@ class baseControl
{
if(!empty($data['message'])) echo js::alert($data['message']);
$locate = $data['locate'] ?? $_SERVER['HTTP_REFERER'] ?? '';
if(!empty($locate)) die(js::locate($locate));
die($data['message'] ?? 'success');
if(!empty($locate)) return helper::end(js::locate($locate));
return helper::end($data['message'] ?? 'success');
}
if(isset($data['result']) and $data['result'] == 'fail')
@@ -1078,27 +1079,27 @@ class baseControl
{
echo js::alert($data['message']);
$locate = $data['locate'] ?? $_SERVER['HTTP_REFERER'] ?? '';
if (!empty($locate)) die(js::locate($locate));
die($data['message'] ?? 'fail');
if (!empty($locate)) return helper::end(js::locate($locate));
return helper::end($data['message'] ?? 'fail');
}
$message = json_decode(json_encode($data['message']), true);
foreach($message as $item => $errors) $message[$item] = implode(',', $errors);
die(js::alert(strip_tags(implode('\n', $message))));
return helper::end(js::alert(strip_tags(implode('\n', $message))));
}
die('fail');
return helper::end('fail');
}
}
/**
* return error json
*
* @param mixed $error
* @return void
* @author thanatos thanatos915@163.com
*/
public function sendError($error)
{
$this->send(array('result' => 'fail', 'message' => $error));
return $this->send(array('result' => 'fail', 'message' => $error));
}
/**
@@ -1106,13 +1107,12 @@ class baseControl
*
* @param array $data
* @return void
* @author thanatos thanatos915@163.com
*/
public function sendSuccess(array $data)
{
$data['result'] = 'success';
if(empty($data['message'])) $data['message'] = $this->lang->saveSuccess;
$this->send($data);
return $this->send($data);
}
/**
@@ -1157,9 +1157,9 @@ class baseControl
* @access public
* @return void
*/
public function locate($url)
public function locate(string $url)
{
header("location: $url");
exit;
helper::end();
}
}
+5 -2
View File
@@ -420,12 +420,15 @@ class baseHelper
* 去掉UTF-8 Bom头。
* Remove UTF-8 Bom.
*
* @param string $string
* @param string|false $string
* @access public
* @return string
*/
public static function removeUTF8Bom($string)
public static function removeUTF8Bom(string|false $string): string
{
/* The ob_get_clean() will return false if output buffering isn't active. */
if(!is_string($string)) return '';
if(substr($string, 0, 3) == pack('CCC', 239, 187, 191)) return substr($string, 3);
return $string;
}
+3 -2
View File
@@ -287,10 +287,11 @@ class helper extends baseHelper
}
/**
* 代替 die、exit 函数终止并输出
* 代替 die、exit 函数终止并输出。
* Instead of die, exit function to terminate and output.
*
* @param string $content
* @return void
* @return never
*/
public static function end(string $content = ''): never
{
+37 -11
View File
@@ -15,14 +15,32 @@ helper::import(dirname(dirname(__FILE__)) . '/base/filter/filter.class.php');
class form extends baseFixer
{
/**
* @var object 原始 $_POST 数据。The raw $_POST data.
* 原始 $_POST 数据。
* The raw $_POST data.
*
* @var object
*/
public $rawdata;
/**
* 错误信息列表。
* Error list.
*
* @var object
*/
public $errors;
/**
* 构造方法。
* The construct function.
*
* @return void
*/
public function __construct()
{
$this->rawdata = (object)$_POST;
$this->data = (object)array();
$this->errors = array();
}
/**
@@ -51,6 +69,11 @@ class form extends baseFixer
$this->rawconfig = $config;
foreach($this->rawconfig as $key => $value) $this->convertField($key, $value);
if(!empty($this->errors))
{
$response = array('result' => 'fail', 'message' => $this->errors);
helper::end(json_encode($response));
}
return $this;
}
@@ -77,19 +100,22 @@ class form extends baseFixer
*/
public function convertField(string $field, array $config)
{
if(isset($config['required']) && $config['required'] && !isset($this->rawdata->$field))
{
throw new InvalidArgumentException("Field $field is required");
}
if(isset($config['required']) && !$config['required'] && !isset($config['default']))
{
throw new InvalidArgumentException("Field $field is not required, but need default value");
}
global $app;
if(!isset($config['type']))
{
throw new InvalidArgumentException("Field $field need defined type");
if(!isset($this->errors[$field])) $this->errors[$field] = array();
$this->errors[$field][] = "Field '$field' need defined type";
}
if(isset($config['required']) && $config['required'])
{
if(!isset($config['default']) && (!isset($this->rawdata->$field) || $this->rawdata->$field === ''))
{
if(!isset($this->errors[$field])) $this->errors[$field] = array();
$fieldName = isset($app->lang->{$app->rawModule}->$field) ? $app->lang->{$app->rawModule}->$field : $field;
$this->errors[$field][] = sprintf($lang->error->notempty, $fieldName);
}
}
if(isset($this->rawdata->$field))
+107 -103
View File
@@ -47,7 +47,7 @@ $config->block->params['default']->count['name'] = $lang->block->count;
$config->block->params['default']->count['default'] = 20;
$config->block->params['default']->count['control'] = 'input';
$config->block->params['task'] = clone $config->block->params['default'];
$config->block->params['task'] = new stdclass();
$config->block->params['task']->type['name'] = $lang->block->type;
$config->block->params['task']->type['options'] = $lang->block->typeList->task;
$config->block->params['task']->type['control'] = 'select';
@@ -55,8 +55,9 @@ $config->block->params['task']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['task']->orderBy['default'] = 'id_desc';
$config->block->params['task']->orderBy['options'] = $lang->block->orderByList->task;
$config->block->params['task']->orderBy['control'] = 'select';
$config->block->params['task']->count = $config->block->params['default']->count;
$config->block->params['bug'] = clone $config->block->params['default'];
$config->block->params['bug'] = new stdclass();
$config->block->params['bug']->type['name'] = $lang->block->type;
$config->block->params['bug']->type['options'] = $lang->block->typeList->bug;
$config->block->params['bug']->type['control'] = 'select';
@@ -64,8 +65,9 @@ $config->block->params['bug']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['bug']->orderBy['default'] = 'id_desc';
$config->block->params['bug']->orderBy['options'] = $lang->block->orderByList->bug;
$config->block->params['bug']->orderBy['control'] = 'select';
$config->block->params['bug']->count = $config->block->params['default']->count;
$config->block->params['case'] = clone $config->block->params['default'];
$config->block->params['case'] = new stdclass();
$config->block->params['case']->type['name'] = $lang->block->type;
$config->block->params['case']->type['options'] = $lang->block->typeList->case;
$config->block->params['case']->type['control'] = 'select';
@@ -73,13 +75,15 @@ $config->block->params['case']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['case']->orderBy['default'] = 'id_desc';
$config->block->params['case']->orderBy['options'] = $lang->block->orderByList->case;
$config->block->params['case']->orderBy['control'] = 'select';
$config->block->params['case']->count = $config->block->params['default']->count;
$config->block->params['testtask'] = clone $config->block->params['default'];
$config->block->params['testtask']->type['name'] = $lang->block->type;
$config->block->params['testtask']->type['options'] = $lang->block->typeList->testtask;
$config->block->params['testtask']->type['control'] = 'select';
$config->block->params['testtask'] = new stdclass();
$config->block->params['testtask']->type['name'] = $lang->block->type;
$config->block->params['testtask']->type['options'] = $lang->block->typeList->testtask;
$config->block->params['testtask']->type['control'] = 'select';
$config->block->params['testtask']->count = $config->block->params['default']->count;
$config->block->params['story'] = clone $config->block->params['default'];
$config->block->params['story'] = new stdclass();;
$config->block->params['story']->type['name'] = $lang->block->type;
$config->block->params['story']->type['options'] = $lang->block->typeList->story;
$config->block->params['story']->type['control'] = 'select';
@@ -87,153 +91,169 @@ $config->block->params['story']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['story']->orderBy['default'] = 'id_desc';
$config->block->params['story']->orderBy['options'] = $lang->block->orderByList->story;
$config->block->params['story']->orderBy['control'] = 'select';
$config->block->params['story']->count = $config->block->params['default']->count;
$config->block->params['plan'] = clone $config->block->params['default'];
$config->block->params['plan'] = $config->block->params['default'];
$config->block->params['release'] = clone $config->block->params['default'];
$config->block->params['release'] = $config->block->params['default'];
$config->block->params['project'] = clone $config->block->params['default'];
$config->block->params['project'] = new stdclass();
$config->block->params['project']->type['name'] = $lang->block->type;
$config->block->params['project']->type['options'] = $lang->block->typeList->projectAll;
$config->block->params['project']->type['control'] = 'select';
$config->block->params['project']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['project']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['project']->orderBy['control'] = 'select';
$config->block->params['project']->count = $config->block->params['default']->count;
$config->block->params['projectteam'] = clone $config->block->params['default'];
$config->block->params['projectteam'] = new stdclass();
$config->block->params['projectteam']->type['name'] = $lang->block->type;
$config->block->params['projectteam']->type['options'] = $lang->block->typeList->projectAll;
$config->block->params['projectteam']->type['control'] = 'select';
$config->block->params['projectteam']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['projectteam']->orderBy['options'] = $lang->block->orderByList->project;
$config->block->params['projectteam']->orderBy['control'] = 'select';
$config->block->params['projectteam']->count = $config->block->params['default']->count;
$config->block->params['build'] = clone $config->block->params['default'];
$config->block->params['build'] = $config->block->params['default'];
$config->block->params['product'] = clone $config->block->params['default'];
$config->block->params['product'] = new stdclass();
$config->block->params['product']->type['name'] = $lang->block->type;
$config->block->params['product']->type['options'] = $lang->block->typeList->product;
$config->block->params['product']->type['control'] = 'select';
$config->block->params['product']->count = $config->block->params['default']->count;
$config->block->params['productstatistic'] = clone $config->block->params['default'];
$config->block->params['productstatistic'] = new stdclass();
$config->block->params['productstatistic']->type['name'] = $lang->block->type;
$config->block->params['productstatistic']->type['options'] = $lang->block->typeList->product;
$config->block->params['productstatistic']->type['control'] = 'select';
$config->block->params['productstatistic']->count = $config->block->params['default']->count;
$config->block->params['projectstatistic'] = clone $config->block->params['default'];
$config->block->params['projectstatistic'] = new stdclass();
$config->block->params['projectstatistic']->type['name'] = $lang->block->type;
$config->block->params['projectstatistic']->type['options'] = $lang->block->typeList->project;
$config->block->params['projectstatistic']->type['control'] = 'select';
$config->block->params['projectstatistic']->count = $config->block->params['default']->count;
$config->block->params['executionstatistic'] = clone $config->block->params['default'];
$config->block->params['executionstatistic'] = new stdclass();
$config->block->params['executionstatistic']->type['name'] = $lang->block->type;
$config->block->params['executionstatistic']->type['options'] = $lang->block->typeList->execution;
$config->block->params['executionstatistic']->type['control'] = 'select';
$config->block->params['executionstatistic']->count = $config->block->params['default']->count;
$config->block->params['qaStatistic'] = clone $config->block->params['default'];
$config->block->params['qaStatistic']->type['name'] = $lang->block->type;
$config->block->params['qaStatistic']->type['options'] = $lang->block->typeList->product;
$config->block->params['qaStatistic']->type['control'] = 'select';
$config->block->params['qastatistic'] = new stdclass();
$config->block->params['qastatistic']->type['name'] = $lang->block->type;
$config->block->params['qastatistic']->type['options'] = $lang->block->typeList->product;
$config->block->params['qastatistic']->type['control'] = 'select';
$config->block->params['qastatistic']->count = $config->block->params['default']->count;
$config->block->params['waterfallissue'] = clone $config->block->params['default'];
$config->block->params['waterfallissue'] = new stdclass();
$config->block->params['waterfallissue']->type['name'] = $lang->block->type;
$config->block->params['waterfallissue']->type['options'] = $lang->block->typeList->issue;
$config->block->params['waterfallissue']->type['control'] = 'select';
$config->block->params['waterfallissue']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['waterfallissue']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['waterfallissue']->orderBy['control'] = 'select';
$config->block->params['waterfallissue']->count = $config->block->params['default']->count;
$config->block->params['waterfallRisk'] = clone $config->block->params['default'];
$config->block->params['waterfallRisk']->type['name'] = $lang->block->type;
$config->block->params['waterfallRisk']->type['options'] = $lang->block->typeList->risk;
$config->block->params['waterfallRisk']->type['control'] = 'select';
$config->block->params['waterfallRisk']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['waterfallRisk']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['waterfallRisk']->orderBy['control'] = 'select';
$config->block->params['waterfallrisk'] = new stdclass();
$config->block->params['waterfallrisk']->type['name'] = $lang->block->type;
$config->block->params['waterfallrisk']->type['options'] = $lang->block->typeList->risk;
$config->block->params['waterfallrisk']->type['control'] = 'select';
$config->block->params['waterfallrisk']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['waterfallrisk']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['waterfallrisk']->orderBy['control'] = 'select';
$config->block->params['waterfallrisk']->count = $config->block->params['default']->count;
$config->block->params['scrumIssue'] = clone $config->block->params['default'];
$config->block->params['scrumIssue']->type['name'] = $lang->block->type;
$config->block->params['scrumIssue']->type['options'] = $lang->block->typeList->issue;
$config->block->params['scrumIssue']->type['control'] = 'select';
$config->block->params['scrumIssue']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['scrumIssue']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['scrumIssue']->orderBy['control'] = 'select';
$config->block->params['scrumissue'] = new stdclass();
$config->block->params['scrumissue']->type['name'] = $lang->block->type;
$config->block->params['scrumissue']->type['options'] = $lang->block->typeList->issue;
$config->block->params['scrumissue']->type['control'] = 'select';
$config->block->params['scrumissue']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['scrumissue']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['scrumissue']->orderBy['control'] = 'select';
$config->block->params['scrumissue']->count = $config->block->params['default']->count;
$config->block->params['scrumRisk'] = clone $config->block->params['default'];
$config->block->params['scrumRisk']->type['name'] = $lang->block->type;
$config->block->params['scrumRisk']->type['options'] = $lang->block->typeList->risk;
$config->block->params['scrumRisk']->type['control'] = 'select';
$config->block->params['scrumRisk']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['scrumRisk']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['scrumRisk']->orderBy['control'] = 'select';
$config->block->params['scrumrisk'] = new stdclass();
$config->block->params['scrumrisk']->type['name'] = $lang->block->type;
$config->block->params['scrumrisk']->type['options'] = $lang->block->typeList->risk;
$config->block->params['scrumrisk']->type['control'] = 'select';
$config->block->params['scrumrisk']->orderBy['name'] = $lang->block->orderBy;
$config->block->params['scrumrisk']->orderBy['options'] = $lang->block->orderByList->product;
$config->block->params['scrumrisk']->orderBy['control'] = 'select';
$config->block->params['scrumrisk']->count = $config->block->params['default']->count;
$config->block->params['execution'] = clone $config->block->params['default'];
$config->block->params['execution']->type['name'] = $lang->block->type;
$config->block->params['execution']->type['options'] = $lang->block->typeList->execution;
$config->block->params['execution']->type['control'] = 'select';
$config->block->params['execution'] = new stdclass();
$config->block->params['execution']->type['name'] = $lang->block->type;
$config->block->params['execution']->type['options'] = $lang->block->typeList->execution;
$config->block->params['execution']->type['control'] = 'select';
$config->block->params['execution']->count = $config->block->params['default']->count;
$config->block->params['assignToMe'] = new stdclass();
$config->block->params['assignToMe']->todoCount['name'] = $this->lang->block->todoCount;
$config->block->params['assignToMe']->todoCount['default'] = 20;
$config->block->params['assignToMe']->todoCount['control'] = 'input';
$config->block->params['assignToMe']->taskCount['name'] = $this->lang->block->taskCount;
$config->block->params['assignToMe']->taskCount['default'] = 20;
$config->block->params['assignToMe']->taskCount['control'] = 'input';
$config->block->params['assignToMe']->bugCount['name'] = $this->lang->block->bugCount;
$config->block->params['assignToMe']->bugCount['default'] = 20;
$config->block->params['assignToMe']->bugCount['control'] = 'input';
$config->block->params['assigntome'] = new stdclass();
$config->block->params['assigntome']->todoCount['name'] = $this->lang->block->todoCount;
$config->block->params['assigntome']->todoCount['default'] = 20;
$config->block->params['assigntome']->todoCount['control'] = 'input';
$config->block->params['assigntome']->taskCount['name'] = $this->lang->block->taskCount;
$config->block->params['assigntome']->taskCount['default'] = 20;
$config->block->params['assigntome']->taskCount['control'] = 'input';
$config->block->params['assigntome']->bugCount['name'] = $this->lang->block->bugCount;
$config->block->params['assigntome']->bugCount['default'] = 20;
$config->block->params['assigntome']->bugCount['control'] = 'input';
if($config->edition == 'max')
{
if(helper::hasFeature('risk'))
{
$config->block->params['assignToMe']->riskCount['name'] = $this->lang->block->riskCount;
$config->block->params['assignToMe']->riskCount['default'] = 20;
$config->block->params['assignToMe']->riskCount['control'] = 'input';
$config->block->params['assigntome']->riskCount['name'] = $this->lang->block->riskCount;
$config->block->params['assigntome']->riskCount['default'] = 20;
$config->block->params['assigntome']->riskCount['control'] = 'input';
}
if(helper::hasFeature('issue'))
{
$config->block->params['assignToMe']->issueCount['name'] = $this->lang->block->issueCount;
$config->block->params['assignToMe']->issueCount['default'] = 20;
$config->block->params['assignToMe']->issueCount['control'] = 'input';
$config->block->params['assigntome']->issueCount['name'] = $this->lang->block->issueCount;
$config->block->params['assigntome']->issueCount['default'] = 20;
$config->block->params['assigntome']->issueCount['control'] = 'input';
}
if(helper::hasFeature('meeting'))
{
$config->block->params['assignToMe']->meetingCount['name'] = $this->lang->block->meetingCount;
$config->block->params['assignToMe']->meetingCount['default'] = 20;
$config->block->params['assignToMe']->meetingCount['control'] = 'input';
$config->block->params['assigntome']->meetingCount['name'] = $this->lang->block->meetingCount;
$config->block->params['assigntome']->meetingCount['default'] = 20;
$config->block->params['assigntome']->meetingCount['control'] = 'input';
}
$config->block->params['assignToMe']->feedbackCount['name'] = $this->lang->block->feedbackCount;
$config->block->params['assignToMe']->feedbackCount['default'] = 20;
$config->block->params['assignToMe']->feedbackCount['control'] = 'input';
$config->block->params['assigntome']->feedbackCount['name'] = $this->lang->block->feedbackCount;
$config->block->params['assigntome']->feedbackCount['default'] = 20;
$config->block->params['assigntome']->feedbackCount['control'] = 'input';
}
$config->block->params['assignToMe']->storyCount['name'] = $this->lang->block->storyCount;
$config->block->params['assignToMe']->storyCount['default'] = 20;
$config->block->params['assignToMe']->storyCount['control'] = 'input';
$config->block->params['assignToMe']->reviewCount['name'] = $this->lang->block->reviewCount;
$config->block->params['assignToMe']->reviewCount['default'] = 20;
$config->block->params['assignToMe']->reviewCount['control'] = 'input';
$config->block->params['assigntome']->storyCount['name'] = $this->lang->block->storyCount;
$config->block->params['assigntome']->storyCount['default'] = 20;
$config->block->params['assigntome']->storyCount['control'] = 'input';
$config->block->params['assigntome']->reviewCount['name'] = $this->lang->block->reviewCount;
$config->block->params['assigntome']->reviewCount['default'] = 20;
$config->block->params['assigntome']->reviewCount['control'] = 'input';
$config->block->params['assigntome']->count = $config->block->params['default']->count;
$config->block->params['scrumTest'] = clone $config->block->params['default'];
$config->block->params['scrumTest']->type['name'] = $lang->block->type;
$config->block->params['scrumTest']->type['options'] = $lang->block->typeList->testtask;
$config->block->params['scrumTest']->type['control'] = 'select';
$config->block->params['scrumtest'] = new stdclass();
$config->block->params['scrumtest']->type['name'] = $lang->block->type;
$config->block->params['scrumtest']->type['options'] = $lang->block->typeList->testtask;
$config->block->params['scrumtest']->type['control'] = 'select';
$config->block->params['scrumtest']->count = $config->block->params['default']->count;
$config->block->params['scrumList'] = clone $config->block->params['default'];
$config->block->params['scrumList']->type['name'] = $lang->block->type;
$config->block->params['scrumList']->type['options'] = $lang->block->typeList->scrum;
$config->block->params['scrumList']->type['control'] = 'select';
$config->block->params['scrumlist'] = new stdclass();
$config->block->params['scrumlist']->type['name'] = $lang->block->type;
$config->block->params['scrumlist']->type['options'] = $lang->block->typeList->scrum;
$config->block->params['scrumlist']->type['control'] = 'select';
$config->block->params['scrumlist']->count = $config->block->params['default']->count;
$config->block->params['scrumProduct'] = clone $config->block->params['default'];
$config->block->params['scrumProduct'] = $config->block->params['default']->count;
$config->block->params['projectDynamic'] = clone $config->block->params['default'];
$config->block->params['projectDynamic'] = $config->block->params['default']->count;
$config->block->params['productDoc'] = clone $config->block->params['default'];
$config->block->params['productDoc'] = $config->block->params['default']->count;
$config->block->params['projectDoc'] = clone $config->block->params['default'];
$config->block->params['projectDoc'] = $config->block->params['default']->count;
$config->block->modules['project'] = new stdclass();
$config->block->modules['project']->moreLinkList = new stdclass();
@@ -279,19 +299,3 @@ $config->block->modules['doc']->moreLinkList = new stdclass();
$config->block->modules['doc']->moreLinkList->docmycollection = 'doc|myspace|type=collect&libID=0&moduleID=0&browseType=all&param=0&orderBy=editedDate_desc';
$config->block->modules['doc']->moreLinkList->productdoc = 'doc|productspace|';
$config->block->modules['doc']->moreLinkList->projectdoc = 'doc|projectspace|';
$config->block->form = new stdclass();
$config->block->form->create = array();
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['code'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
$config->block->form->create['hidden'] = array('type' => 'int', 'required' => false, 'default' => '0');
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
$config->block->form->edit = array();
$config->block->form->edit['module'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->edit['code'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->edit['title'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->edit['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
$config->block->form->edit['params'] = array('type' => 'array', 'required' => false, 'default' => array());
+22
View File
@@ -0,0 +1,22 @@
<?php
$config->block->create = new stdclass();
$config->block->create->requiredFields = 'module,code,title';
$config->block->edit = new stdclass();
$config->block->edit->requiredFields = 'module,code,title';
$config->block->form = new stdclass();
$config->block->form->create = array();
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['code'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
$config->block->form->create['hidden'] = array('type' => 'int', 'required' => false, 'default' => '0');
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
$config->block->form->edit = array();
$config->block->form->edit['module'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->edit['code'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->edit['title'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->block->form->edit['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
$config->block->form->edit['params'] = array('type' => 'array', 'required' => false, 'default' => array());
+2 -2
View File
@@ -47,7 +47,7 @@ class block extends control
$this->block->create($formData);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true, 'callback' => 'loadCurrentPage()'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true));
}
$this->view->title = $this->lang->block->createBlock;
@@ -80,7 +80,7 @@ class block extends control
$this->block->update($formData);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true, 'callback' => 'loadCurrentPage()'));
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true));
}
$block = $this->block->getByID($blockID);
+1 -1
View File
@@ -4,5 +4,5 @@ function getForm(event)
const module = $('#module').val();
const code = field == 'module' ? '' : $('#code').val();
const url = $.createLink('block', 'create', 'dashboard='+ dashboard +'&module=' + module + '&code=' + (code ? code : ''));
loadPage(url, '#codeRow, #paramsRow');
loadPage(url, '#codesRow, #paramsRow');
}
+2 -3
View File
@@ -23,10 +23,9 @@ $lang->block->estimate = 'Estimate';
$lang->block->last = 'Last';
$lang->block->account = 'Konto';
$lang->block->module = 'Modul';
$lang->block->title = 'Titel';
$lang->block->source = 'Source module';
$lang->block->block = 'Source block';
$lang->block->module = 'Modul';
$lang->block->code = 'InfoBlock';
$lang->block->order = 'Sortierung';
$lang->block->height = 'Höhe';
$lang->block->role = 'Rolle';
+2 -3
View File
@@ -23,10 +23,9 @@ $lang->block->estimate = 'Estimate';
$lang->block->last = 'Last';
$lang->block->account = 'Account';
$lang->block->module = 'Module';
$lang->block->title = 'Title';
$lang->block->source = 'Source Module';
$lang->block->block = 'Source Block';
$lang->block->module = 'Module';
$lang->block->code = 'Block';
$lang->block->order = 'Order';
$lang->block->height = 'Height';
$lang->block->role = 'Role';
+2 -3
View File
@@ -23,10 +23,9 @@ $lang->block->estimate = 'Estimate';
$lang->block->last = 'Last';
$lang->block->account = 'Compte';
$lang->block->module = 'Module';
$lang->block->title = 'Titre';
$lang->block->source = 'Source Module';
$lang->block->block = 'Source Bloc';
$lang->block->module = 'Module';
$lang->block->code = 'Bloc';
$lang->block->order = 'Ordre';
$lang->block->height = 'Hauteur';
$lang->block->role = 'Rôle';
+2 -3
View File
@@ -21,10 +21,9 @@ $lang->block->estimate = 'Estimate';
$lang->block->last = 'Last';
$lang->block->account = 'Tài khoản';
$lang->block->module = 'Module';
$lang->block->title = 'Tiêu đề';
$lang->block->source = 'Nguồn Module';
$lang->block->block = 'Nguồn Block';
$lang->block->module = 'Module';
$lang->block->code = 'Block';
$lang->block->order = 'Sắp xếp';
$lang->block->height = 'Chiều cao';
$lang->block->role = 'Vai trò';
+2 -3
View File
@@ -23,10 +23,9 @@ $lang->block->estimate = '预计工时';
$lang->block->last = '近期';
$lang->block->account = '所属用户';
$lang->block->module = '所属模块';
$lang->block->title = '区块名称';
$lang->block->source = '来源模块';
$lang->block->block = '来源区块';
$lang->block->module = '所属模块';
$lang->block->code = '区块';
$lang->block->order = '排序';
$lang->block->height = '高度';
$lang->block->role = '角色';
+11 -70
View File
@@ -120,51 +120,6 @@ class blockModel extends model
return $this->blockTao->fetchMyBlocks($dashboard, $hidden = 1);
}
/**
* Get block json that user can add.
* 获取允许用户添加的区块列表.
*
* @param string $dashboard
* @param string $module
* @access public
* @return string[]
*/
public function getAvailableBlocks(string $dashboard, string $module = ''): array
{
if($dashboard == 'my')
{
if($module and isset($this->lang->block->modules[$module]))
{
$blocks = $this->lang->block->modules[$module]->availableBlocks;
}
else
{
$blocks = array();
}
}
else
{
if($dashboard and isset($this->lang->block->modules[$dashboard]))
{
$blocks = $this->lang->block->modules[$dashboard]->availableBlocks;
}
else
{
$blocks = $this->lang->block->availableBlocks;
}
}
if(isset($this->config->block->closed))
{
foreach($blocks as $blockKey => $blockName)
{
if(strpos(",{$this->config->block->closed},", ",{$module}|{$blockKey},") !== false) unset($blocks[$blockKey]);
}
}
return $blocks;
}
/**
* Get max order number by block dashboard.
* 获取对应仪表盘下区块的最大排序号.
@@ -175,31 +130,12 @@ class blockModel extends model
*/
public function getMaxOrderByDashboard(string $dashboard): int
{
return $this->blockTao->fetchMaxOrderByDashboard($dashboard);
}
$order = $this->dao->select('MAX(`order`) as `order`')->from(TABLE_BLOCK)
->where('dashboard')->eq($dashboard)
->andWhere('account')->eq($this->app->user->account)
->fetch('order');
/**
* Get block set form params.
* 获取不同区块所需的参数配置.
*
* @param string $type
* @param string $module
* @access public
* @return string
*/
public function getParams(string $code, string $module): string
{
if($code == 'todo' || $code == 'list')
{
$code = $module;
}
elseif($code == 'statistic')
{
$code = $module . $code;
}
$params = zget($this->config->block->params, $code, '');
return json_encode($params);
return (int)$order;
}
/**
@@ -346,7 +282,12 @@ class blockModel extends model
*/
public function update(object $formData): int|false
{
$this->dao->update(TABLE_BLOCK)->data($formData)->where('id')->eq($formData->id)->autoCheck()->exec();
$this->dao->update(TABLE_BLOCK)->data($formData)
->where('id')->eq($formData->id)
->autoCheck()
->batchCheck($this->config->block->edit->requiredFields, 'notempty')
->exec();
if(dao::isError()) return false;
$this->loadModel('score')->create('block', 'set');
+5 -19
View File
@@ -2,24 +2,6 @@
declare(strict_types=1);
class blockTao extends blockModel
{
/**
* Get max order number by block dashboard.
* 获取对应仪表盘下区块的最大排序号.
*
* @param string $module
* @access protected
* @return int
*/
protected function fetchMaxOrderByDashboard(string $dashboard): int
{
$order = $this->dao->select('MAX(`order`) as `order`')->from(TABLE_BLOCK)
->where('dashboard')->eq($dashboard)
->andWhere('account')->eq($this->app->user->account)
->fetch('order');
return (int)$order;
}
/**
* Get block list of current user.
* 获取当前用户的区块列表.
@@ -49,7 +31,11 @@ class blockTao extends blockModel
*/
protected function insert($formData): bool
{
$this->dao->insert(TABLE_BLOCK)->data($formData)->autoCheck()->exec();
$this->dao->insert(TABLE_BLOCK)->data($formData)
->autoCheck()
->batchCheck($this->config->block->create->requiredFields, 'notempty')
->exec();
return true;
}
}
+37 -35
View File
@@ -15,16 +15,17 @@ set::title($title);
jsVar('dashboard', $dashboard);
$paramsRows = array();
$isMyDashboard = $dashboard == 'my';
$showModules = ($dashboard == 'my' and $modules);
$showCodes = (($showModules and $module and $codes) or $dashboard != 'my');
foreach($params as $key => $row)
{
$paramsRows[] = formGroup
(
set::label($row['name']),
set::name('params'),
set::name("params[$key]"),
set::class('form-row'),
set::value($block->params->{$key}),
set::value(zget($row, 'default', '')),
set::control(array
(
'type' => $row['control'],
@@ -39,58 +40,59 @@ form
on::change('#code', 'getForm'),
formGroup
(
set::class($isMyDashboard ? '' : 'hidden'),
set::value($isMyDashboard ? '' : $dashboard),
set::class($showModules ? '' : 'hidden'),
set::value($showModules ? $block : $dashboard),
set::label($lang->block->lblModule),
set::name('module'),
set::control(array
set::control($showModules ? array
(
'type' => 'select',
'items' => $modules
))
) : 'input')
),
div
(
set::id('codeRow'),
$codes
? formGroup
set::id('codesRow'),
formGroup
(
set::label($lang->block->lblBlock),
set::name('code'),
set::value($code),
set::control(array
set::class($showCodes ? '' : 'hidden'),
set::value($showCodes ? $code : $module),
set::control($showCodes ? array
(
'type' => 'select',
'items' => array('') + $codes
))
) : null
) : 'input')
)
),
div
(
set::id('paramsRow'),
set::class('form-grid'),
$paramsRows,
(($module and $code) or ($module and !$codes))
? formGroup
div
(
set::label($lang->block->name),
set::name('title'),
set::value(zget($modules, $module, '') . zget($codes, $code, '')),
set::class('form-row'),
set::control('input')
) : null,
(($module and $code) or ($module and !$codes))
? formGroup
(
set::label($lang->block->grid),
set::name("grid"),
set::class('form-row'),
set::control(array
set::class('form-grid'),
formGroup
(
'type' => 'select',
'items' => $lang->block->gridOptions
))
) : null,
set::label($lang->block->name),
set::name('title'),
set::class('form-row'),
set::value(zget($modules, $module, '') . zget($codes, $code, '')),
set::control('input')
),
$paramsRows,
formGroup
(
set::label($lang->block->grid),
set::name("grid"),
set::class('form-row'),
set::control(array
(
'type' => 'select',
'items' => $lang->block->gridOptions
))
)
)
)
);
+6 -7
View File
@@ -16,15 +16,14 @@ jsVar('blockID', $block->id);
$paramsRows = array();
$showModules = ($dashboard == 'my' and $modules);
$showCodes = ($module and $codes);
$showParams = ($code);
$showCodes = (($showModules and $module and $codes) or $dashboard != 'my');
foreach($params as $key => $row)
{
$paramsRows[] = formGroup
(
set::label($row['name']),
set::name('params'),
set::name("params[$key]"),
set::class('form-row'),
set::value($block->params->{$key}),
set::control(array
@@ -41,10 +40,10 @@ form
on::change('#code', 'getForm'),
formGroup
(
set::class($showModules ? '' : 'hidden'),
set::value($showModules ? $block->module : $dashboard),
set::label($lang->block->lblModule),
set::name('module'),
set::class($showModules ? '' : 'hidden'),
set::value($showModules ? $module : $dashboard),
set::control($showModules ? array
(
'type' => 'select',
@@ -72,8 +71,7 @@ form
set::id('paramsRow'),
div
(
set::class('form-grid' . ($showParams ? '' : ' hidden')),
$paramsRows,
set::class('form-grid'),
formGroup
(
set::label($lang->block->name),
@@ -82,6 +80,7 @@ form
set::value($block->title),
set::control('input')
),
$paramsRows,
formGroup
(
set::label($lang->block->grid),
+42 -7
View File
@@ -71,7 +71,36 @@ class blockZen extends block
if(!$this->block->checkAPI($this->get->hash)) return array();
}
$blocks = $this->block->getAvailableBlocks($dashboard, $module);
if($dashboard == 'my')
{
if($module and isset($this->lang->block->modules[$module]))
{
$blocks = $this->lang->block->modules[$module]->availableBlocks;
}
else
{
$blocks = array();
}
}
else
{
if($dashboard and isset($this->lang->block->modules[$dashboard]))
{
$blocks = $this->lang->block->modules[$dashboard]->availableBlocks;
}
else
{
$blocks = $this->lang->block->availableBlocks;
}
}
if(isset($this->config->block->closed))
{
foreach($blocks as $blockKey => $blockName)
{
if(strpos(",{$this->config->block->closed},", ",{$module}|{$blockKey},") !== false) unset($blocks[$blockKey]);
}
}
if(!$this->selfCall)
{
@@ -92,13 +121,19 @@ class blockZen extends block
* @access protected
* @return array
*/
protected function getAvailableParams(string $dashboard, string $module = '', string $block = ''): array
protected function getAvailableParams(string $dashboard, string $module = '', string $code = ''): array
{
if(!isset($this->lang->block->moduleList[$module])) return array();
if($code == 'todo' || $code == 'list' || $module == 'assigntome')
{
$code = $module;
}
elseif($code == 'statistic')
{
$code = $module . $code;
}
if(!$block) return array();
$params = json_decode($this->block->getParams($block, $module), true);
$params = zget($this->config->block->params, $code, '');
$params = json_decode(json_encode($params), true);
return !empty($params) ? $params : array();
}
@@ -144,7 +179,7 @@ class blockZen extends block
* @param int $projectID
* @return void
*/
private function getBlockMoreLink(object $block, int $project): void
private function getBlockMoreLink(object $block, int $projectID): void
{
$code = $block->code;
$source = empty($block->source) ? 'common' : $block->source;
+2 -12
View File
@@ -337,19 +337,9 @@ class bugModel extends model
/* Get bugs by browse type. */
$bugList = array();
if($browseType == 'all')
{
$bugList = $this->bugTao->getAllBugs($productIdList, $projectID, $executionIdList, $branch, $modules, $orderBy, $pager);
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug');
}
elseif($browseType == 'review')
{
$bugList = $this->bugTao->getListByReviewToMe($productIdList, $projectID, $executionIdList, $branch, $modules, $orderBy, $pager);
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug');
}
if($browseType == 'bysearch') $bugList = $this->getBySearch($productIdList, $branch, $queryID, $orderBy, '', $pager, $projectID);
elseif($browseType == 'needconfirm') $bugList = $this->bugTao->getListByNeedconfirm($productIdList, $projectID, $executionIdList, $branch, $modules, $orderBy, $pager);
elseif($browseType == 'bysearch') $bugList = $this->getBySearch($productIdList, $branch, $queryID, $orderBy, '', $pager, $projectID);
elseif(strpos(',bymodule,assigntome,openedbyme,resolvedbyme,assigntonull,unconfirmed,unresolved,unclosed,toclosed,longlifebugs,postponedbugs,overduebugs,assignedbyme,', ",$browseType,") !== false) $bugList = $this->bugTao->getListByBrowseType($browseType, $productIdList, $projectID, $executionIdList, $branch, $modules, $orderBy, $pager);
elseif(strpos(',all,bymodule,assigntome,openedbyme,resolvedbyme,assigntonull,unconfirmed,unresolved,unclosed,toclosed,longlifebugs,postponedbugs,overduebugs,assignedbyme,review,', ",$browseType,") !== false) $bugList = $this->bugTao->getListByBrowseType($browseType, $productIdList, $projectID, $executionIdList, $branch, $modules, $orderBy, $pager);
return $this->bugTao->batchAppendDelayedDays($bugList);
}
+2 -61
View File
@@ -21,36 +21,6 @@ class bugTao extends bugModel
->where('t1.id')->eq((int)$bugID)->fetch();
}
/**
* Get all bugs.
* 获取所有的bug。
*
* @param int|array $productIdList
* @param int|string $branch
* @param int|array $moduleIdList
* @param int[] $executionIdList
* @param string $orderBy
* @param object $pager
* @param int $projectID
* @access protected
* @return array
*/
protected function getAllBugs(int|array $productIdList, int $projectID, array $executionIdList, int|string $branch, int|array $moduleIdList, string $orderBy, object $pager = null): array
{
return $this->dao->select("t1.*, t2.title as planTitle, 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_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id')
->where('t1.deleted')->eq('0')
->andWhere('t1.product')->in($productIdList)
->beginIF($projectID)->andWhere('t1.project')->eq($projectID)->fi()
->beginIF($this->app->tab !== 'qa')->andWhere('t1.execution')->in($executionIdList)->fi()
->beginIF($branch !== 'all')->andWhere('t1.branch')->eq($branch)->fi()
->beginIF($moduleIdList)->andWhere('t1.module')->in($moduleIdList)->fi()
->beginIF(!$this->app->user->admin)->andWhere('t1.project')->in('0,' . $this->app->user->view->projects)->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
/**
* Get bug list by browse type.
* 通过浏览类型获取bug列表。
@@ -100,6 +70,7 @@ class bugTao extends bugModel
->beginIF($browseType == 'unresolved')->andWhere('status')->eq('active')->fi()
->beginIF($browseType == 'toclosed')->andWhere('status')->eq('resolved')->fi()
->beginIF($browseType == 'postponedbugs')->andWhere('resolution')->eq('postponed')->fi()
->beginIF($browseType == 'review')->andWhere("FIND_IN_SET('{$this->app->user->account}', reviewers)")->fi()
->beginIF($browseType == 'longlifebugs')
->andWhere('lastEditedDate')->lt($lastEditedDate)
@@ -121,6 +92,7 @@ class bugTao extends bugModel
->page($pager)
->fetchAll('id');
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug');
return $bugList;
}
@@ -156,37 +128,6 @@ class bugTao extends bugModel
->fetchAll('id');
}
/**
* Get bug list to review.
* 获取待我审批的bug列表。
*
* @param int|array $productIdList
* @param int $projectID
* @param int[] $executionIdList
* @param int|string $branch
* @param int|array $moduleIdList
* @param string $orderBy
* @param object $pager
* @access public
* @return array
*/
protected function getListByReviewToMe(int|array $productIdList, int $projectID, array $executionIdList, int|string $branch, int|array $moduleIdList, string $orderBy, object $pager = null): array
{
return $this->dao->select("t1.*, t2.title as planTitle, IF(`pri` = 0, {$this->config->maxPriValue}, `pri`) as priOrder, IF(`severity` = 0, {$this->config->maxPriValue}, `severity`) as severityOrder")->from(TABLE_BUG)->alias('t1')
->leftJoin(TABLE_PRODUCTPLAN)->alias('t2')->on('t1.plan = t2.id')
->where('t1.deleted')->eq(0)
->andWhere('t1.product')->in($productIdList)
->beginIF($projectID)->andWhere('t1.project')->eq($projectID)->fi()
->beginIF($this->app->tab !== 'qa')->andWhere('t1.execution')->in($executionIdList)->fi()
->beginIF($branch !== 'all')->andWhere('t1.branch')->eq($branch)->fi()
->beginIF($moduleIdList)->andWhere('t1.module')->in($moduleIdList)->fi()
->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")
->beginIF(!$this->app->user->admin)->andWhere('t1.project')->in('0,' . $this->app->user->view->projects)->fi()
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
/**
* Get cases created by bug.
* 获取bug建的用例。
-1
View File
@@ -64,7 +64,6 @@ r(count($bug->getList($browseType[0], $productIdList[2], $projectID[0], $execut
r(count($bug->getList($browseType[0], $productIdList[0], $projectID[2], $executionIdList[0], $branch[0], $moduleID[0]))) && p('') && e('0'); //获取不存在项目ID的bug列表,查看数量是否正确
r(count($bug->getList($browseType[0], $productIdList[0], $projectID[0], $executionIdList[2], $branch[0], $moduleID[0]))) && p('') && e('0'); //获取不存在执行ID的bug列表,查看数量是否正确
r($bug->getList($browseType[0], $productIdList[0], $projectID[0], $executionIdList[0], $branch[0], $moduleID[0])) && p('1:planTitle') && e('计划1'); //获取全部产品1下的全部bug列表,查看ID为1的bug的计划名称是否正确
r($bug->getList($browseType[0], $productIdList[1], $projectID[1], $executionIdList[1], $branch[1], $moduleID[0])) && p('2:title') && e('BUG2'); //获取全部产品1下的项目相关的全部bug列表,查看ID为2的bug的名称是否正确
r($bug->getList($browseType[1], $productIdList[0], $projectID[0], $executionIdList[0], $branch[0], $moduleID[1])) && p('3:module') && e('1'); //获取产品1模块下的bug列表,查看ID为3的bug的module是否正确
r($bug->getList($browseType[2], $productIdList[0], $projectID[0], $executionIdList[0], $branch[0], $moduleID[0])) && p('1:assignedTo') && e('admin'); //获取产品1下指派给我的bug列表,查看ID为1的bug的指派人是否正确
+1 -1
View File
@@ -77,7 +77,7 @@ class execution extends control
$this->loadModel('product');
/* Get executions and products info. */
$executionID = $this->execution->saveState($executionID, $this->executions);
$executionID = $this->execution->checkAccess($executionID, $this->executions);
$execution = $this->execution->getById($executionID);
$products = $this->product->getProducts($executionID);
$childExecutions = $this->execution->getChildExecutions($executionID);
+1 -2
View File
@@ -322,8 +322,7 @@ class executionModel extends model
}
/* Save session. */
$this->session->set('execution', $executionID, $this->app->tab);
$this->setProjectSession($executionID);
$this->executionTao->saveSession($executionID);
/* Return execution id. */
return $executionID;
+27
View File
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/**
* The tao file of execution module of ZenTaoPMS.
*
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
* @author Shujie Tian <tianshujie@easysoft.ltd>
* @package execution
* @link https://www.zentao.net
*/
class executionTao extends executionModel
{
/**
* 将执行ID保存到session中。
* Save the execution ID to the session.
*
* @param int $executionID
* @access protected
* @return void
*/
protected function saveSession(int $executionID): void
{
$this->session->set('execution', $executionID, $this->app->tab);
$this->setProjectSession($executionID);
}
}
+7 -3
View File
@@ -201,8 +201,12 @@ class product extends control
if($browseType == 'bybranch') setcookie('storyBranch', $branch, 0, $this->config->webRoot, '', $this->config->cookieSecure, false);
$cookieModule = $this->app->tab == 'project' ? $this->cookie->storyModuleParam : $this->cookie->storyModule;
$moduleID = ($browseType == 'bymodule') ? (int)$param : (($browseType == 'bysearch' or $browseType == 'bybranch') ? 0 : ($cookieModule ? $cookieModule : 0));
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
$moduleID = 0;
if($browseType == 'bymodule') $moduleID = (int)$param;
elseif($browseType != 'bysearch' and $browseType != 'bybranch' and $cookieModule) $moduleID = $cookieModule;
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
/* Set moduleTree. */
$createModuleLink = $storyType == 'story' ? 'createStoryLink' : 'createRequirementLink';
@@ -1157,7 +1161,7 @@ class product extends control
if($this->config->systemMode == 'light' and $orderBy == 'program_asc') $orderBy = 'order_asc';
$productStats = $this->product->getStats($orderBy, $pager, $browseType, 0, 'story', 0, $queryID);
$productStructure = $this->product->statisticProgram($productStats);
$productStructure = $this->productZen->statisticProgram($productStats);
/* Save search form. */
$actionURL = $this->createLink('product', 'all', "browseType=bySearch&orderBy=order_asc&queryID=myQueryID");
+65 -166
View File
@@ -1020,40 +1020,37 @@ class productModel extends model
/* Get modules. */
$this->loadModel('tree');
if($this->app->tab == 'project')
if($this->app->tab == 'project' and $productID)
{
if($productID)
$modules = array();
$branchList = $this->loadModel('branch')->getPairs($productID, '', $projectID);
$branchModuleList = $this->tree->getOptionMenu($productID, 'story', 0, array_keys($branchList));
foreach($branchModuleList as $branchID => $branchModules) $modules = array_merge($modules, $branchModules);
}
elseif($this->app->tab == 'project')
{
$moduleList = array();
$modules = array('/');
$branchGroup = $this->loadModel('execution')->getBranchByProduct(array_keys($products), $projectID, '');
foreach($products as $productID => $productName)
{
$modules = array();
$branchList = $this->loadModel('branch')->getPairs($productID, '', $projectID);
$branchModuleList = $this->tree->getOptionMenu($productID, 'story', 0, array_keys($branchList));
foreach($branchModuleList as $branchID => $branchModules) $modules = array_merge($modules, $branchModules);
}
else
{
$moduleList = array();
$modules = array('/');
$branchGroup = $this->loadModel('execution')->getBranchByProduct(array_keys($products), $projectID, '');
foreach($products as $productID => $productName)
if(isset($branchGroup[$productID]))
{
if(isset($branchGroup[$productID]))
$branchModuleList = $this->tree->getOptionMenu($productID, 'story', 0, array_keys($branchGroup[$productID]));
foreach($branchModuleList as $branchID => $branchModules)
{
$branchModuleList = $this->tree->getOptionMenu($productID, 'story', 0, array_keys($branchGroup[$productID]));
foreach($branchModuleList as $branchID => $branchModules)
{
if(is_array($branchModules)) $moduleList += $branchModules;
}
}
else
{
$moduleList = $this->tree->getOptionMenu($productID, 'story', 0, $branch);
if(is_array($branchModules)) $moduleList += $branchModules;
}
}
else
{
$moduleList = $this->tree->getOptionMenu($productID, 'story', 0, $branch);
}
foreach($moduleList as $moduleID => $moduleName)
{
if(empty($moduleID)) continue;
$modules[$moduleID] = $productName . $moduleName;
}
foreach($moduleList as $moduleID => $moduleName)
{
if(empty($moduleID)) continue;
$modules[$moduleID] = $productName . $moduleName;
}
}
}
@@ -1686,19 +1683,19 @@ class productModel extends model
if(empty($products)) return array();
/* Get stats data. */
$productKeys = array_keys($products);
$products = $this->productTao->getStatsProducts($productKeys,$programID, $orderBy, $pager);
$productIDs = array_keys($products);
$products = $this->productTao->getStatsProducts($productIDs,$programID, $orderBy, $pager);
$finishClosedStory = $this->productTao->getFinishClosedStoryTODO();
$unclosedStory = $this->productTao->getUnClosedStoryTODO();
$plans = $this->productTao->getPlansTODO($productKeys);
$releases = $this->productTao->getReleasesTODO($productKeys);
$bugs = $this->productTao->getBugsTODO($productKeys);
$unResolved = $this->productTao->getUnResolvedTODO($productKeys);
$fixedBugs = $this->productTao->getFixedBugsTODO($productKeys);
$closedBugs = $this->productTao->getClosedBugsTODO($productKeys);
$thisWeekBugs = $this->productTao->getThisWeekBugsTODO($productKeys);
$assignToNull = $this->productTao->getAssignToNullTODO($productKeys);
list($stories, $reqs) = $this->productTao->getStatsStoriesAndRequirements($productKeys, $storyType);
$plans = $this->productTao->getPlansTODO($productIDs);
$releases = $this->productTao->getReleasesTODO($productIDs);
$bugs = $this->productTao->getBugsTODO($productIDs);
$unResolved = $this->productTao->getUnResolvedTODO($productIDs);
$fixedBugs = $this->productTao->getFixedBugsTODO($productIDs);
$closedBugs = $this->productTao->getClosedBugsTODO($productIDs);
$thisWeekBugs = $this->productTao->getThisWeekBugsTODO($productIDs);
$assignToNull = $this->productTao->getAssignToNullTODO($productIDs);
list($stories, $reqs) = $this->productTao->getStatsStoriesAndRequirements($productIDs, $storyType);
/* Render statistic result to each product. */
$stats = array();
@@ -1863,39 +1860,35 @@ class productModel extends model
$rateCount = 0;
$allCount = 0;
foreach($stories as $key => $story)
foreach($stories as $story)
{
if(!empty($story->type) && $story->type != $storyType) continue;
$totalEstimate += $story->estimate;
$allCount ++;
/* When the status is not closed or closedReason is done or postponed then add cases rate..*/
if(
empty($story->children) and
($story->status != 'closed' or
($story->status == 'closed' and ($story->closedReason == 'done' or $story->closedReason == 'postponed')))
)
if(empty($story->children))
{
$storyIdList[] = $story->id;
$rateCount ++;
if($story->status != 'closed' or ($story->status == 'closed' and in_array($story->closedReason, ['done', 'postponed'])))
{
$storyIdList[] = $story->id;
$rateCount ++;
}
continue;
}
$allCount ++;
if(!empty($story->children))
foreach($story->children as $child)
{
foreach($story->children as $child)
{
if($child->type != $storyType) continue;
if($child->type != $storyType) continue;
if(
$child->status != 'closed' or
($child->status == 'closed' and ($child->closedReason == 'done' or $child->closedReason == 'postponed'))
)
{
$storyIdList[] = $child->id;
$rateCount ++;
}
$allCount ++;
if($story->status != 'closed' or ($story->status == 'closed' and in_array($story->closedReason, ['done', 'postponed'])))
{
$storyIdList[] = $child->id;
$rateCount ++;
}
$allCount ++;
}
}
@@ -1909,103 +1902,6 @@ class productModel extends model
return sprintf($this->lang->product->storySummary, $allCount, $storyCommon, $totalEstimate, $rate * 100 . "%");
}
/**
* Statistics program data from statistics data of product.
*
* @param array $productStats
* @access public
* @return array
*/
public function statisticProgram(array $productStats): array
{
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProductStats();
$productStructure = array();
foreach($productStats as $product)
{
$productStructure[$product->program][$product->line]['products'][$product->id] = $product;
if($product->line)
{
/* Line name. */
$productStructure[$product->program][$product->line]['lineName'] = $product->lineName;
$productStructure[$product->program][$product->line] = $this->statisticData('line', $productStructure, $product);
}
if($product->program)
{
/* Init vars. */
/* Program name. */
$productStructure[$product->program]['programName'] = $product->programName;
$productStructure[$product->program]['programPM'] = $product->programPM;
$productStructure[$product->program]['id'] = $product->program;
$productStructure[$product->program] = $this->statisticData('program', $productStructure, $product);
}
}
return $productStructure;
}
/**
* Statistic product data.
*
* @param string $type
* @param array $productStructure
* @param object $product
* @access public
* @return void
*/
public function statisticData($type = 'program', $productStructure = array(), $product = null)
{
if(empty($productStructure)) return $productStructure;
/* Init vars. */
$data = $type == 'program' ? $productStructure[$product->program] : $productStructure[$product->program][$product->line];
foreach($this->config->product->statisticFields as $key => $fields)
{
/* Get the total number of requirements and stories. */
if(strpos('stories|requirements', $key) !== false)
{
$totalObjects = 0;
foreach($product->$key as $status => $number)
{
if(isset($this->lang->story->statusList[$status])) $totalObjects += $number;
}
$fieldType = $key == 'stories' ? 'Stories' : 'Requirements';
if(!isset($data['total' . $fieldType])) $data['total' . $fieldType] = 0;
$data['total' . $fieldType] += $totalObjects;
}
elseif($key == 'bugs')
{
$fieldType = 'Bugs';
}
foreach($fields as $field)
{
if(!isset($data[$field])) $data[$field] = 0;
$status = $field;
if(strpos($field, 'Requirements') !== false or strpos($field, 'Stories') !== false or $field == 'unResolvedBugs')
{
$length = strpos($field, $fieldType);
$status = substr($field, 0, $length);
}
if(strpos('requirements|stories', $key) !== false)
{
$objects = $product->$key;
$data[$field] += $objects[$status];
}
else
{
$data[$field] += $product->$status;
}
}
}
return $data;
}
/**
* Judge an action is clickable or not.
*
@@ -2300,18 +2196,21 @@ class productModel extends model
*
* Set menu.
*
* @param int $productID
* @param int|string $branch
* @param int $module
* @param string $moduleType
* @param string $extra
*
* @param int $productID
* @param int|string $branch
* @param int $module
* @param string $moduleType
* @param string $extra
* @access public
* @return void
*/
public function setMenu($productID = 0, $branch = '', $module = 0, $moduleType = '', $extra = '')
public function setMenu($productID = 0, $branch = '', $module = 0, $moduleType = '', $extra = ''): void
{
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL')) return $this->accessDenied($this->lang->product->accessDenied);
if(!$this->app->user->admin and strpos(",{$this->app->user->view->products},", ",$productID,") === false and $productID != 0 and !defined('TUTORIAL'))
{
$this->accessDenied($this->lang->product->accessDenied);
return;
}
$product = $this->getByID($productID);
+13 -1
View File
@@ -97,7 +97,6 @@ class productTao extends productModel
*/
protected function getPagerProductsIn(array $productIDs, object|null $pager, string $orderBy)
{
/* TODO list all fields? */
$products = $this->dao->select('*')->from(TABLE_PRODUCT)
->where('id')->in($productIDs)
->orderBy($orderBy)
@@ -494,4 +493,17 @@ class productTao extends productModel
if(dao::isError())return false;
return (int)$this->dao->lastInsertID();
}
/**
* 从module表中查询所有产品线。
* Get all product lines from module table.
* TODO move to the MODULE module.
*
* @access protected
* @return array
*/
protected function getProductLinesTODO(): array
{
return $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('deleted')->eq(0)->orderBy('`order` asc')->fetchAll();
}
}
+84
View File
@@ -0,0 +1,84 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/product.class.php';
function initData()
{
/* Generate product data. */
$product = zdTable('product')->config('getlist');
$product->name->prefix('产品_')->range('1-50');
$product->code->prefix('p_code_')->range('1-50');
$product->order->range('1-50');
$product->status->range('noclosed,involved,review,normal,closed');
$product->vision->range('rnd,lite,');
$product->gen(50);
/* Generate releated program data. */
$program = zdTable('project');
$program->id->range('1-10');
$program->model->range('');
$program->name->prefix('项目集_')->range('1-10');
$program->type->range('program,project');
$program->project->range('0');
$program->vision->range('rnd');
$program->gen(10);
/* Generate releate product to project data. */
$project2product = zdTable('projectproduct');
$project2product->project->range('2,4,6,8,10');
$project2product->product->range('1-50');
$project2product->branch->range('0');
$project2product->plan->range('0');
$project2product->gen(50);
/* Generate releated team data. */
$team = zdTable('team');
$team->type->range('project');
$team->root->range('2,4,6,8,10');
$team->gen(5);
}
initData();
/**
title=productTao->getList();
cid=2
- 校验总数 @25
- 校验shadow总数 @25
- 校验line总数 @5
- 校验limit @3
- 校验noclosed状态 @20
- 校验所属项目集 @5
*/
global $config;
$product = new productTest('admin');
/* Valiate defualt total. */
$result = $product->objectModel->getList(0, 'all', 0, 0, 'all');
r(count($result)) && p('') && e('25');
/* Validate shadow total. */
$result = $product->objectModel->getList(0, 'all', 0, 0, 0);
r(count($result)) && p('') && e('25');
/* Validate line total. */
$result = $product->objectModel->getList(0, 'all', 0, 1, 0);
r(count($result)) && p('') && e('5');
/* Validate limit. */
$result = $product->objectModel->getList(0, 'all', 3, 1, 0);
r(count($result)) && p('') && e('3');
/* Validate noclosed status. */
$result = $product->objectModel->getList(0, 'noclosed', 0, 0, 0);
r(count($result)) && p('') && e('20');
/* Validate noclosed status. */
$result = $product->objectModel->getList(1, 'noclosed', 0, 0, 0);
r(count($result)) && p('') && e('5');
@@ -0,0 +1,12 @@
title: table zt_product for getList testing
author: Chen Tao
version: "1.0"
fields:
- field: id
range: 1-50
- field: program
range: 1-10
- field: shadow
range: 0-1
- field: line
range: 1-5
+174 -9
View File
@@ -1,13 +1,178 @@
<?php
js::set('programID', $programID);
/**
* The create view of product of ZenTaoPMS.
*/
$form = form();
$form->buildForm($fields);
$form->buildFormAction();
/*
======= Attention ======
$content = block();
$content->from = $form;
This file is generated by zin-tool, you should check the following to-do list.
$page = page('create');
$page->right->content = $content;
$page->x();
+ Familiar with the use of these widgets in zin: .
+ Check the following variables which used in widgets: $programOptions, $lineOptions, $POOptions, $QDOptions, $RDOptions, $reviewerOptions, $typeOptions, $aclOptions, $whitelistOptions.
+ Check the origin code in module/product/view/create.html.php, and ensure that all features have been implemented.
+ Check the origin js code in module/product/js/common.js and module/product/js/create.js
+ Check the origin css code in module/product/css/common.css and module/product/css/create.css
+ Remove the comments which starts with "zin:"
+ Test according to the new design draft and the original implementation
*/
namespace zin;
/* ====== Preparing and processing page data ====== */
/* zin: Set variables to define picker options for form */
$programOptions = array();
$lineOptions = array();
$POOptions = array();
$QDOptions = array();
$RDOptions = array();
$reviewerOptions = array();
$typeOptions = array(array('value' => "normal", 'text' => "正常"), array('value' => "branch", 'text' => "多分支(适用于客户定制场景)"), array('value' => "platform", 'text' => "多平台(适用于跨平台应用开发,比如IOS、安卓、PC端等)"));
$aclOptions = array(array('checked' => true, 'value' => "private", 'disabled' => false, 'text' => "私有(产品相关负责人、所属项目集的负责人及干系人、相关联项目的团队成员和干系人可访问)"), array('checked' => false, 'value' => "open", 'disabled' => false, 'text' => "公开(有产品视图权限,即可访问)"));
$whitelistOptions = array();
/* ====== Define the page structure with zin widgets ====== */
/* zin: Define the form in main content */
formPanel
(
formGroup
(
set::width("1/3"),
set::name("program"),
set::label("项目集"),
set::control("picker"),
set::items($programOptions)
),
formRow
(
set::hidden(true),
formGroup
(
set::width("1/3"),
set::name("line"),
set::label("产品线"),
set::control("picker"),
set::items($lineOptions)
)
),
formGroup
(
set::width("1/3"),
set::name("name"),
set::label("产品名称"),
set::required(true),
set::control("text")
),
formGroup
(
set::width("1/3"),
set::name("PO"),
set::label("产品负责人"),
set::control("picker"),
set::items($POOptions)
),
formGroup
(
set::width("1/3"),
set::name("QD"),
set::label("测试负责人"),
set::control("picker"),
set::items($QDOptions)
),
formGroup
(
set::width("1/3"),
set::name("RD"),
set::label("发布负责人"),
set::control("picker"),
set::items($RDOptions)
),
formGroup
(
set::width("1/3"),
set::name("reviewer[]"),
set::label("评审人"),
set::control(["type" =>"picker","multiple"=>true]),
set::id("reviewer"),
set::items($reviewerOptions)
),
formGroup
(
set::width("1/3"),
set::name("type"),
set::label("产品类型"),
set::value("normal"),
set::control("picker"),
set::items($typeOptions)
),
formGroup
(
set::width("2/3"),
set::label("产品描述"),
inputGroup
(
control(set(array
(
'id' => "title",
'value' => "",
'disabled' => false,
'type' => "text"
))),
"公共",
btn(set(array
(
'type' => "btn",
'text' => "保存",
'class' => "input-group-btn"
)))
)
),
formGroup
(
set::width("2/3"),
set::name("acl"),
set::label("访问控制"),
set::control("radioList"),
set::items($aclOptions)
),
formGroup
(
set::width("1/3"),
set::label("白名单"),
inputGroup
(
control(set(array
(
'name' => "whitelist[]",
'id' => "whitelist",
'value' => NULL,
'disabled' => false,
'type' => "picker",
'items' => $whitelistOptions,
'multiple' => true
))),
btn(set(array
(
'type' => "btn",
'icon' => "cog",
'text' => "",
'class' => "input-group-btn"
))),
btn(set(array
(
'type' => "btn",
'icon' => "refresh",
'text' => "",
'class' => "input-group-btn"
)))
)
)
);
/* ====== Render page ====== */
render();
+98 -2
View File
@@ -247,8 +247,7 @@ class productZen extends product
protected function getProductLines(): array
{
/* Get all product lines. */
/* TODO use model of module. */
$productLines = $this->dao->select('*')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('deleted')->eq(0)->orderBy('`order` asc')->fetchAll();
$productLines = $this->product->getProductLinesTODO();
/* Collect product lines of program lines. */
$programLines = array();
@@ -457,4 +456,101 @@ class productZen extends product
{
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
}
/**
* 从产品统计数据中统计项目集。
* Statistics program data from statistics data of product.
*
* @param array $productStats
* @access protected
* @return array
*/
protected function statisticProgram(array $productStats): array
{
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProductStats();
$programStructure = array();
foreach($productStats as $product)
{
$programStructure[$product->program][$product->line]['products'][$product->id] = $product;
/* Generate line data. */
if($product->line)
{
$programStructure[$product->program][$product->line]['lineName'] = $product->lineName;
$programStructure[$product->program][$product->line] = $this->statisticProductData('line', $programStructure, $product);
}
/* Generate program data. */
if($product->program)
{
$programStructure[$product->program]['programName'] = $product->programName;
$programStructure[$product->program]['programPM'] = $product->programPM;
$programStructure[$product->program]['id'] = $product->program;
$programStructure[$product->program] = $this->statisticProductData('program', $programStructure, $product);
}
}
return $programStructure;
}
/**
* 统计项目集内的产品数据
* Statistic product data.
*
* @param string $type line|program
* @param array $programStructure
* @param object $product
* @access protected
* @return array
*/
protected function statisticProductData(string $type, array $programStructure, object|null $product): array
{
if(empty($programStructure)) return $programStructure;
/* Init vars. */
$data = $type == 'program' ? $programStructure[$product->program] : $programStructure[$product->program][$product->line];
foreach($this->config->product->statisticFields as $key => $fields)
{
/* Get the total number of requirements and stories. */
if(strpos('stories|requirements', $key) !== false)
{
$totalObjects = 0;
foreach($product->$key as $status => $number) if(isset($this->lang->story->statusList[$status])) $totalObjects += $number;
$fieldType = $key == 'stories' ? 'Stories' : 'Requirements';
if(!isset($data['total' . $fieldType])) $data['total' . $fieldType] = 0;
$data['total' . $fieldType] += $totalObjects;
}
elseif($key == 'bugs')
{
$fieldType = 'Bugs';
}
foreach($fields as $field)
{
if(!isset($data[$field])) $data[$field] = 0;
$status = $field;
if(strpos($field, 'Requirements') !== false or strpos($field, 'Stories') !== false or $field == 'unResolvedBugs')
{
$length = strpos($field, $fieldType);
$status = substr($field, 0, $length);
}
if(strpos('requirements|stories', $key) !== false)
{
$objects = $product->$key;
$data[$field] += $objects[$status];
}
else
{
$data[$field] += $product->$status;
}
}
}
return $data;
}
}
+6 -1
View File
@@ -1,6 +1,11 @@
<?php
$config->project->form = new stdclass();
$config->project->form->create = array();
$config->project->form->edit = array();
$config->project->form->close = array();
$config->project->form->start = array();
$config->project->form->create['parent'] = array('type' => 'int', 'required' => false, 'default' => '');
$config->project->form->create['name'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
$config->project->form->create['code'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
@@ -17,7 +22,6 @@ $config->project->form->create['whitelist'] = array('type' => 'array', 'requir
$config->project->form->create['auth'] = array('type' => 'array', 'required' => false, 'default' => '');
$config->project->form->create['model'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->project->form->eidt = array();
$config->project->form->edit['parent'] = array('type' => 'int', 'required' => false, 'default' => '');
$config->project->form->edit['name'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
$config->project->form->edit['code'] = array('type' => 'string', 'required' => true, 'filter' => 'trim');
@@ -33,6 +37,7 @@ $config->project->form->edit['acl'] = array('type' => 'string', 'required
$config->project->form->edit['whitelist'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join');
$config->project->form->edit['auth'] = array('type' => 'array', 'required' => false, 'default' => '');
$config->project->form->edit['model'] = array('type' => 'string', 'required' => false, 'default' => '');
$config->project->form->start['realBegan'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
$config->project->form->close['realEnd'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
+32 -158
View File
@@ -511,7 +511,7 @@ class project extends control
* @access public
* @return void
*/
public function edit(string $projectID, string $from = ''): void
public function edit(string $projectID, string $from = ''): mixed
{
$this->loadModel('action');
$this->loadModel('custom');
@@ -1674,12 +1674,14 @@ class project extends control
/**
* Project edit a group.
*
* @param int $groupID
* @param string $groupID
*
* @access public
* @return void
*/
public function editGroup($groupID)
public function editGroup($groupID): mixed
{
$groupID = (int)$groupID;
$this->loadModel('group');
if(!empty($_POST))
{
@@ -1687,10 +1689,8 @@ class project extends control
return print(js::closeModal('parent.parent', 'this'));
}
$this->view->title = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->edit;
$this->view->position[] = $this->lang->group->edit;
$this->view->group = $this->group->getById($groupID);
$this->view->title = $this->lang->company->orgView . $this->lang->colon . $this->lang->group->edit;
$this->view->group = $this->group->getById($groupID);
$this->display('group', 'edit');
}
@@ -1804,8 +1804,7 @@ class project extends control
$changes = $this->project->activate($projectID, $postData);
if(dao::isError()) return print(js::error(dao::getError()));
$comment = strip_tags($this->post->comment, $this->config->allowedTags);
$this->projectZen->responseAfterActivate($projectID, $changes, $comment);
$this->projectZen->responseAfterActivate($projectID, $changes);
return print(js::reload('parent.parent'));
}
@@ -1935,79 +1934,34 @@ class project extends control
}
/**
* 管理项目下的关联产品
* Manage products.
*
* @param int $projectID
* @param string $projectID
* @param string $from project|program|programproject
*
* @access public
* @return void
*/
public function manageProducts(string $projectID, $from = 'project')
public function manageProducts(string $projectID, $from = 'project'): mixed
{
$projectID = (int)$projectID;
$this->loadModel('product');
$this->loadModel('program');
$this->loadModel('execution');
$project = $this->project->getById($projectID);
$project = $this->project->getById($projectID);
if(!$project->hasProduct) return print(js::error($this->lang->project->cannotManageProducts) . js::locate('back'));
$executions = $this->execution->getPairs($projectID);
$executions = $this->loadModel('execution')->getPairs($projectID);
$executionIDs = array_keys($executions);
if(!empty($_POST))
{
if(!isset($_POST['products']) and !isset($_POST['otherProducts']))
$postData = form::data();
if(!isset($postData->rawdata->products) and !isset($postData->rawdata->otherProducts))
{
dao::$errors['message'][] = $this->lang->project->errorNoProducts;
return $this->send(array('result' => 'fail', 'message' => dao::getError()));
}
$oldProducts = $this->product->getProducts($projectID);
if($project->multiple and $project->model != 'waterfall' and $project->model != 'waterfallplus') $oldExecutionProducts = $this->dao->select('project,product')->from(TABLE_PROJECTPRODUCT)->where('project')->in(array_keys($executions))->fetchGroup('project', 'product');
$this->project->updateProducts($projectID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
if(empty($project->multiple))
{
$executionID = $this->execution->getNoMultipleID($projectID);
if($executionID) $this->execution->updateProducts($executionID);
}
$newProducts = $this->product->getProducts($projectID);
$oldProductIDs = array_keys($oldProducts);
$newProductIDs = array_keys($newProducts);
$diffProducts = array_merge(array_diff($oldProductIDs, $newProductIDs), array_diff($newProductIDs, $oldProductIDs));
if($diffProducts) $this->loadModel('action')->create('project', $projectID, 'Managed', '', !empty($_POST['products']) ? join(',', $_POST['products']) : '');
if(empty($project->division))
{
foreach(array_keys($executions) as $executionID)
{
$this->execution->updateProducts($executionID);
if($diffProducts) $this->loadModel('action')->create('execution', $executionID, 'Managed', '', implode(',', array_keys($newProducts)));
}
}
if($project->multiple and $project->model != 'waterfall' and $project->model != 'waterfallplus')
{
$unlinkedProducts = array_diff($oldProductIDs, $newProductIDs);
if(!empty($unlinkedProducts))
{
$unlinkedProductPairs = array();
foreach($unlinkedProducts as $unlinkedProduct) $unlinkedProductPairs[$unlinkedProduct] = $oldProducts[$unlinkedProduct]->name;
$unlinkExecutions = array();
foreach($oldExecutionProducts as $executionID => $executionProducts)
{
$unlinkExecutionProducts = array_intersect_key($unlinkedProductPairs, $executionProducts);
if($unlinkExecutionProducts) $unlinkExecutions[$executionID] = $unlinkExecutionProducts;
}
foreach($unlinkExecutions as $executionID => $unlinkExecutionProducts) $this->action->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkExecutionProducts));
}
}
$this->projectZen->mergeProducts($projectID, $project, $executionIDs, $postData);
$locateLink = inLink('manageProducts', "projectID=$projectID");
if($from == 'program') $locateLink = $this->session->projectList;
@@ -2023,125 +1977,45 @@ class project extends control
$this->project->setMenu($projectID);
}
$linkedBranches = array();
$linkedBranchIdList = array();
$branches = $this->project->getBranchesByProject($projectID);
$linkedProductIdList = empty($branches) ? '' : array_keys($branches);
$allProducts = $this->program->getProductPairs($project->parent, 'all', 'noclosed', $linkedProductIdList);
$linkedProducts = $this->product->getProducts($projectID, 'all', '', true, $linkedProductIdList);
$projectStories = $this->project->getStoriesByProject($projectID);
$projectBranches = $this->project->getBranchGroupByProject($projectID, array_keys($linkedProducts));
/* If the story of the product which linked the project, you don't allow to remove the product. */
$unmodifiableProducts = array();
$unmodifiableBranches = array();
$unmodifiableMainBranches = array();
foreach($linkedProducts as $productID => $linkedProduct)
{
$linkedBranches[$productID] = array();
foreach($branches[$productID] as $branchID => $branch)
{
$linkedBranches[$productID][$branchID] = $branchID;
$linkedBranchIdList[$branchID] = $branchID;
if(!empty($projectStories[$productID][$branchID]) or !empty($projectBranches[$productID][$branchID]))
{
if($branchID == BRANCH_MAIN) $unmodifiableMainBranches[$productID] = $branchID;
array_push($unmodifiableProducts, $productID);
array_push($unmodifiableBranches, $branchID);
}
}
}
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed', $linkedBranchIdList);
if($this->config->systemMode == 'ALM')
{
$topProgramID = $project->parent ? $this->program->getTopByPath($project->path) : 0;
$productsGroupByProgram = $this->product->getProductsGroupByProgram();
$currentProducts = array();
$otherProducts = array();
foreach($productsGroupByProgram as $programID => $programProducts)
{
if($programID != $topProgramID)
{
foreach($programProducts as $productID => $productName)
{
if(!empty($branchGroups[$productID]))
{
foreach($branchGroups[$productID] as $branchID => $branchName)
{
if(isset($linkedProducts[$productID]) and isset($linkedBranches[$productID][$branchID])) continue;
$otherProducts["{$productID}_{$branchID}"] = $productName . '_' . $branchName;
}
}
else
{
if(isset($linkedProducts[$productID])) continue;
$otherProducts[$productID] = $productName;
}
}
}
else
{
$currentProducts += $programProducts;
}
}
$this->view->currentProducts = $currentProducts;
$this->view->otherProducts = $otherProducts;
}
/* Assign. */
$this->view->title = $this->lang->project->manageProducts . $this->lang->colon . $project->name;
$this->view->project = $project;
$this->view->linkedProducts = $linkedProducts;
$this->view->linkedBranches = $linkedBranches;
$this->view->branches = $branches;
$this->view->project = $project;
$this->view->unmodifiableProducts = $unmodifiableProducts;
$this->view->unmodifiableBranches = $unmodifiableBranches;
$this->view->unmodifiableMainBranches = $unmodifiableMainBranches;
$this->view->branchGroups = $branchGroups;
$this->view->executions = $executions;
$this->view->allBranches = $this->branch->getByProducts(array_keys($allProducts), 'ignoreNormal');
$this->view->allProducts = $allProducts;
$this->display();
$this->projectZen->dealLinkProduct($projectID, $project);
$this->projectZen->buildMangedProductForm($projectID, $project, $executions);
}
/**
* 获取项目页面中下拉执行列表
* AJAX: get executions of a project in html select.
*
* @param int $projectID
* @param string $projectID
* @param int $executionID
* @param string $mode
* @param string $type all|sprint|stage|kanban
* @param string $type all|sprint|stage|kanban
*
* @access public
* @return void
*/
public function ajaxGetExecutions($projectID, $executionID = 0, $mode = '', $type = 'all')
public function ajaxGetExecutions(string $projectID, int $executionID = 0, string $mode = '', string $type = 'all'): mixed
{
$project = $this->project->getById($projectID);
$project = $this->project->getByID($projectID);
$disabled = $project->multiple ? '' : 'disabled';
$executions = array('' => '') + $this->loadModel('execution')->getPairs($projectID, $type, $mode);
if($this->app->getViewType() == 'json') return print(json_encode($executionList));
if($this->app->getViewType() == 'json') return print(json_encode($executions));
$disabled = $project->multiple ? '' : 'disabled';
return print(html::select('execution', $executions, $executionID, "class='form-control $disabled' $disabled"));
}
/**
* 根据执行ID获取对应的项目下拉列表
* AJAX: get a project by execution id.
*
* @param string $executionID
*
* @access public
* @return string
*/
public function ajaxGetPairsByExecution($executionID)
public function ajaxGetPairsByExecution(string $executionID): string
{
$execution = $this->loadModel('execution')->getByID($executionID);
$execution = $this->loadModel('execution')->getByID((int)$executionID);
$projectPairs = $this->loadModel('project')->getPairsByIdList($execution->project);
if($this->app->getViewType() == 'json')
+15
View File
@@ -488,4 +488,19 @@ class projectTao extends projectModel
return $parentProgram;
}
/**
* 将旧的产品替换成新的
* replace oldProduct
*
* @param array $executionIDs
*
* @access protected
* @return bool
*/
protected function replaceOldProduct(array $executionIDs): bool
{
$oldExecutionProducts = $this->dao->select('project,product')->from(TABLE_PROJECTPRODUCT)->where('project')->in($executionIDs)->fetchGroup('project', 'product');
return !dao::isError();
}
}
+31 -21
View File
@@ -6,32 +6,38 @@ su('admin');
function initData()
{
#scrum
#project1 对应product1 对应execution1,3 对应文档库2
#project3 对应product2,3 对应execution2,4 对应文档库3
#waterfall
#kanban/stage
#无迭代项目
$project = zdTable('project')->config('project')->gen(5);
$project = zdTable('project')->config('project')->gen(6);
$product = zdTable('product');
$product->id->range('1-3');
$product->gen(3);
$projectproduct = zdTable('projectproduct')->config('projectproduct')->gen(3);
$projectproduct = zdTable('projectproduct')->config('projectproduct')->gen(5);
$doclib = zdTable('doclib');
$doclib->id->range('1');
$doclib->execution->range('2');
$doclib->project->range('1');
$doclib->gen(1);
}
/**
title=测试 projectModel->deleteByTableName();
timeout=0
cid=1
pid=1
- #删除项目编号为1,同时删除项目下文档库 @1
- #删除项目编号为1,同时删除项目下的一个执行1-2 @1
- #删除项目编号为3,同时删除项目下的全部执行3-4 3-5 @1
- #删除项目编号为1,同时删除项目下关联的第一个产品 @1
- #删除项目编号为1,同时删除项目下关联的全部产品 @1
*/
@@ -40,14 +46,18 @@ $tester->loadModel('project');
initData();
$executions = $tester->loadModel('execution')->getPairs(1);
$project1 = $tester->project->deleteByTableName('zt_doclib', 2);
$project2 = $tester->project->deleteByTableName('zt_product', 2);
$project3 = $tester->project->deleteByTableName('zt_project', 2);
$project4 = $tester->project->deleteByTableName('zt_project', $executions);
$execution = $tester->loadModel('execution')->getPairs(1);
$executions = $tester->loadModel('execution')->getPairs(3);
$product = $tester->loadModel('product')->getProductIDByProject(1);
$products = $tester->loadModel('product')->getProductIDByProject(1, false);
$project1 = $tester->project->deleteByTableName('zt_doclib', 1);
$project2 = $tester->project->deleteByTableName('zt_project', array_keys($execution));
$project3 = $tester->project->deleteByTableName('zt_project', array_keys($executions));
$project4 = $tester->project->deleteByTableName('zt_product', $product);
$project5 = $tester->project->deleteByTableName('zt_product', $products);
a($project1);die;
r($project1) && p('1:program,name') && e('1,正常产品1'); #删除项目编号为2,同时删除项目下文档库
r($project2) && p('2:program,name') && e('1,正常产品2'); #删除项目编号为2,同时删除项目下的一个产品
r($project3) && p('3:program,name') && e('1,正常产品3'); #删除项目编号为2,同时删除项目下的一个执行
r($project4) && p('4:program,name') && e('1,正常产品4'); #删除项目编号为1,同时删除项目下关联的全部产品
r($project1) && p() && e(1); #删除项目编号为1,同时删除项目下文档库
r($project2) && p() && e(1); #删除项目编号为1,同时删除项目下的一个执行1-2
r($project3) && p() && e(1); #删除项目编号为3,同时删除项目下的全部执行3-4 3-5
r($project4) && p() && e(1); #删除项目编号为1,同时删除项目下关联的第一个产品
r($project5) && p() && e(1); #删除项目编号为1,同时删除项目下关联的全部产品
@@ -3,8 +3,8 @@
include dirname(__FILE__, 5) . "/test/lib/init.php";
su('admin');
$project = zdTable('project');
$project->gen(5);
$project = zdTable('project')->config('project');
$project->gen(4);
/**
@@ -12,7 +12,7 @@ title=测试 projectModel->getListByCurrentUser();
timeout=0
cid=1
- 执行projectModel模块的getListByCurrentUser方法 @1
- 执行projectModel模块的getListByCurrentUser方法 @0
- 执行projectModel模块的getListByCurrentUser方法 @1
@@ -27,6 +27,9 @@ cid=1
global $tester;
$projectModel = $tester->loadModel('project');
r(count($projectModel->getListByCurrentUser())) && p() && e('1');
$tester->app->user->admin = true;
$tester->app->config->vision = 'lite';
r(count($projectModel->getListByCurrentUser())) && p() && e('0');
$tester->app->config->vision = 'rnd';
r(count($projectModel->getListByCurrentUser())) && p() && e('1');
r($projectModel->getListByCurrentUser()) && p('11:id,name') && e('11,项目1');
@@ -3,16 +3,22 @@ author: liuhong
version: "1.0"
fields:
- field: id
range: 1-5
range: 1-6
- field: project
range: 0, 1, 0, 3, 3
range: 0, 1, 0, 3, 3, 0
- field: model
range: 'scrum, ,waterfall, , ,'
range: 'scrum, ,waterfall, , ,scrum'
- field: type
range: 'project,sprint,project,stage,stage'
range: 'project,sprint,project,stage,stage,project'
- field: status
range: 'wait,doing,closed,suspended'
- field: parent
range: 0, 1, 0, 3, 3
range: 0, 1, 0, 3, 3, 0
- field: path
range: `,1,`, `,1,2,`, `,3,`, `,3,4,`, `,3,4,5,`
range: '`,1,`, `,1,2,`, `,3,`, `,3,4,`, `,3,4,5,`, `,6,`'
- field: hasProduct
range: 1, 1, 1, 1, 1, 0
- field: name
range: '项目1, 执行1-2, 项目3, 执行3-4, 执行3-5, 无迭代无产品项目6'
- field: code
range: 'project1, sprint1-2, project3, sprint3-4, sprint3-5, project6'
@@ -3,6 +3,6 @@ author: liuhong
version: "1.0"
fields:
- field: project
range: 1{1},2{2}
range: 1{3},2{2}
- field: product
range: 1, 2, 3
@@ -0,0 +1,16 @@
title: zt_project
author: liuhong
version: "1.0"
fields:
- field: type
range: 'project,sprint,project,stage'
- field: status
range: 'wait,doing,closed,suspended'
- field: deleted
range: 0,1,1,0
- field: vision
range: rnd,rnd,rnd,lite
- field: openedDate
range: "20220101 000000:1W" # 生成从2021年1月1日0时0分0秒到当前时间的数据,步长为1周
type: timestamp
format: "YY/MM/DD hh:mm:ss"
+216 -3
View File
@@ -566,12 +566,11 @@ class projectZen extends project
*
* @param int $projectID
* @param array $changes
* @param string $comment
*
* @access protected
* @return void
*/
protected function responseAfterActivate(int $projectID, array $changes, string $comment): void
protected function responseAfterActivate(int $projectID, array $changes): void
{
if($this->post->comment != '' or !empty($changes))
{
@@ -637,7 +636,7 @@ class projectZen extends project
* 从项目中删除所有关联的产品。
* removes all associated products from the be deleted project
*
* @param object $projectID
* @param object $project
*
* @access protected
* @return void
@@ -651,4 +650,218 @@ class projectZen extends project
$this->project->deleteByTableName('zt_product', $productID);
}
}
/**
* 处理并合并项目下的新旧产品
* mergeProducts
*
* @param int $projectID
* @param object $project
* @param int|array $executionIDs
* @param array $postData
*
* @access protected
* @return void
*/
protected function mergeProducts(int $projectID, object $project, int|array $executionIDs, array $postData): mixed
{
$this->loadModel('product');
$this->loadModel('execution');
$oldProducts = $this->product->getProducts($projectID);
$this->project->updateProducts($projectID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
//判断是否为项目型项目并更新关联产品
if(empty($project->multiple))
{
$executionID = $this->execution->getNoMultipleID($projectID);
if($executionID) $this->execution->updateProducts($executionID);
}
//将项目下关联的新旧产品合并
$newProducts = $this->product->getProducts($projectID);
$oldProductIDs = array_keys($oldProducts);
$newProductIDs = array_keys($newProducts);
$diffProducts = array_merge(array_diff($oldProductIDs, $newProductIDs), array_diff($newProductIDs, $oldProductIDs));
if($diffProducts) $this->loadModel('action')->create('project', $projectID, 'Managed', '', !empty($postData->rawdata->products) ? implode(',', $postData->rawdata->products) : '');
//判断是否为产品型项目并更新关联产品
if(empty($project->division))
{
foreach($executionIDs as $executionID)
{
$this->execution->updateProducts($executionID);
if($diffProducts) $this->loadModel('action')->create('execution', $executionID, 'Managed', '', implode(',', array_keys($newProducts)));
}
}
//处理非瀑布及产品型项目
$this->dealExecutionProduct($project, $oldProducts, $newProductIDs, $executionIDs);
}
/**
* 处理项目执行下关联产品
* deal execution product
*
* @param object $project
* @param object $oldProducts
* @param array $newProductIDs
* @param int|array $executionIDs
*
* @access protected
* @return void
*/
protected function dealExecutionProduct(object $project, object $oldProducts, array $newProductIDs, array $executionIDs): void
{
//处理非瀑布及产品型项目
if($project->multiple and $project->model != 'waterfall' and $project->model != 'waterfallplus')
{
$oldExecutionProducts = $this->projectTao->replaceOldProduct($executionIDs);
$unlinkedProducts = array_diff(array_keys($oldProducts), $newProductIDs);
if(!empty($unlinkedProducts))
{
$unlinkedProductPairs = array();
foreach($unlinkedProducts as $unlinkedProduct) $unlinkedProductPairs[$unlinkedProduct] = $oldProducts[$unlinkedProduct]->name;
$unlinkExecutions = array();
foreach($oldExecutionProducts as $executionID => $executionProducts)
{
$unlinkExecutionProducts = array_intersect_key($unlinkedProductPairs, $executionProducts);
if($unlinkExecutionProducts) $unlinkExecutions[$executionID] = $unlinkExecutionProducts;
}
foreach($unlinkExecutions as $executionID => $unlinkExecutionProducts) $this->loadModel('action')->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkExecutionProducts));
}
}
}
/**
* 处理项目关联需求的产品
* dealLinkProduct
*
* @param int $projectID
* @param object $project
*
* @access protected
* @return void
*/
protected function dealLinkProduct(int $projectID, object $project): void
{
$this->loadModel('product');
$this->loadModel('program');
$linkedBranches = array();
$linkedBranchIdList = array();
$branches = $this->project->getBranchesByProject($projectID);
$linkedProductIdList = empty($branches) ? '' : array_keys($branches);
$allProducts = $this->program->getProductPairs($project->parent, 'all', 'noclosed', $linkedProductIdList);
$linkedProducts = $this->product->getProducts($projectID, 'all', '', true, $linkedProductIdList);
$projectStories = $this->project->getStoriesByProject($projectID);
$projectBranches = $this->project->getBranchGroupByProject($projectID, array_keys($linkedProducts));
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed', $linkedBranchIdList);
/* If the story of the product which linked the project,don't allow to remove the product. */
$unmodifiableProducts = array();
$unmodifiableBranches = array();
$unmodifiableMainBranches = array();
foreach($linkedProducts as $productID => $linkedProduct)
{
$linkedBranches[$productID] = array();
foreach($branches[$productID] as $branchID => $branch)
{
$linkedBranches[$productID][$branchID] = $branchID;
$linkedBranchIdList[$branchID] = $branchID;
if(!empty($projectStories[$productID][$branchID]) or !empty($projectBranches[$productID][$branchID]))
{
if($branchID == BRANCH_MAIN) $unmodifiableMainBranches[$productID] = $branchID;
array_push($unmodifiableProducts, $productID);
array_push($unmodifiableBranches, $branchID);
}
}
}
$this->dealOtherLinkProduct($project, $branchGroups, $linkedBranches);
$this->view->allBranches = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal');
$this->view->allProducts = $allProducts;
$this->view->unmodifiableProducts = $unmodifiableProducts;
$this->view->unmodifiableBranches = $unmodifiableBranches;
$this->view->unmodifiableMainBranches = $unmodifiableMainBranches;
$this->view->linkedBranches = $linkedBranches;
$this->view->branchGroups = $branchGroups;
}
/**
* dealOtherLinkProduct
*
* @param object $project
* @param object $branchGroups
* @param array $linkedBranches
*
* @access protected
* @return void
*/
protected function dealOtherLinkProduct(object $project, object $branchGroups, array $linkedBranches): void
{
$linkedProducts = $this->product->getProducts($projectID, 'all', '', true, $linkedProductIdList);
if($this->config->systemMode == 'ALM')
{
$topProgramID = $project->parent ? $this->program->getTopByPath($project->path) : 0;
$productsGroupByProgram = $this->product->getProductsGroupByProgram();
$currentProducts = array();
$otherProducts = array();
foreach($productsGroupByProgram as $programID => $programProducts)
{
if($programID != $topProgramID)
{
foreach($programProducts as $productID => $productName)
{
if(!empty($branchGroups[$productID]))
{
foreach($branchGroups[$productID] as $branchID => $branchName)
{
if(isset($linkedProducts[$productID]) and isset($linkedBranches[$productID][$branchID])) continue;
$otherProducts["{$productID}_{$branchID}"] = $productName . '_' . $branchName;
}
}
else
{
if(isset($linkedProducts[$productID])) continue;
$otherProducts[$productID] = $productName;
}
}
}
else
{
$currentProducts += $programProducts;
}
}
$this->view->currentProducts = $currentProducts;
$this->view->otherProducts = $otherProducts;
}
$this->view->linkedProducts = $linkedProducts;
}
/**
* buildMangedProductForm
*
* @param int $projectID
* @param object $project
*
* @access protected
* @return void
*/
protected function buildMangedProductForm(int $projectID, $project, $executions): void
{
$this->view->title = $this->lang->project->manageProducts . $this->lang->colon . $project->name;
$this->view->project = $project;
$this->view->executions = $executions;
$this->view->branches = $this->project->getBranchesByProject($projectID);
$this->display();
}
}
+1 -1
View File
@@ -2399,7 +2399,7 @@ class story extends control
public function tasks($storyID, $executionID = 0)
{
$this->loadModel('task');
$tasks = $this->task->getStoryTasks($storyID, $executionID);
$tasks = $this->task->getListByStory($storyID, $executionID);
$this->view->tasks = $tasks;
$this->view->users = $this->user->getPairs('noletter');
$this->view->summary = $this->execution->summary($tasks);
+3 -3
View File
@@ -5463,7 +5463,7 @@ class storyModel extends model
$stories[$id]->title = $story->title;
$stories[$id]->cases = $this->loadModel('testcase')->getStoryCases($id);
$stories[$id]->bugs = $this->loadModel('bug')->getStoryBugs($id);
$stories[$id]->tasks = $this->loadModel('task')->getStoryTasks($id);
$stories[$id]->tasks = $this->loadModel('task')->getListByStory($id);
if($this->config->edition == 'max')
{
$stories[$id]->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)
@@ -5537,7 +5537,7 @@ class storyModel extends model
$stories[$id]->title = $story->title;
$stories[$id]->cases = $this->loadModel('testcase')->getStoryCases($id);
$stories[$id]->bugs = $this->loadModel('bug')->getStoryBugs($id);
$stories[$id]->tasks = $this->loadModel('task')->getStoryTasks($id, 0, $projectID);
$stories[$id]->tasks = $this->loadModel('task')->getListByStory($id, 0, $projectID);
if($this->config->edition == 'max')
{
$stories[$id]->designs = $this->dao->select('id, name')->from(TABLE_DESIGN)
@@ -5581,7 +5581,7 @@ class storyModel extends model
$track[$id]->case = $this->loadModel('testcase')->getStoryCases($id);
$track[$id]->bug = $this->loadModel('bug')->getStoryBugs($id);
$track[$id]->story = $this->getByID($id);
$track[$id]->task = $this->loadModel('task')->getStoryTasks($id);
$track[$id]->task = $this->loadModel('task')->getListByStory($id);
if($this->config->edition == 'max')
{
$track[$id]->design = $this->dao->select('id, name')->from(TABLE_DESIGN)
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
su('admin');
function initData()
{
$task = zdTable('task');
$task->id->range('1-5');
$task->name->prefix('任务')->range('1-5');
$task->parent->range('`-1`,1,1,0,0');
$task->execution->range('6,7,8,9,10');
$task->project->range('1,2,3,4,5');
$task->gen(5);
$project = zdTable('project');
$project->id->range('1-10');
$project->name->prefix('project')->range('1-10');
$project->project->range('0,0,0,0,0,1,2,3,4,5');
$project->gen(10);
}
function insertDate($taskID, $estStarted, $deadline)
{
}
function getByID($taskID)
{
global $tester;
return $tester->dao->select('estStarted,deadline,lastEditedBy')->from(TABLE_TASK)->where('id')->eq($taskID)->fetch();
}
/**
title=测试updatetaskesdatebygantt
cid=1
*/
initData();
$postData = new stdClass();
$postData->id = 1;
$postData->startDate = '2023-04-20';
$postData->endDate = '2023-04-24';
$postData->type = 'task';
$tester->loadModel('task');
$taskIDList = range(1,5);
$taskList = $tester->task->getByList($taskIDList);
$tester->task->updateTaskEsDateByGantt($taskIDList[1], $postData);
$tester->task->updateTaskEsDateByGantt($taskIDList[2], $postData);
$tester->task->updateTaskEsDateByGantt($taskIDList[3], $postData);
$tester->task->updateTaskEsDateByGantt($taskIDList[4], $postData);
$tester->task->updateTaskEsDateByGantt($taskIDList[5], $postData);
+6
View File
@@ -43,3 +43,9 @@ $config->todo->objectList['bug'] = 'bugs';
$config->todo->objectList['task'] = 'tasks';
$config->todo->objectList['story'] = 'stories';
$config->todo->objectList['testtask'] = 'testtasks';
$config->todo->sessionUri = array();
$config->todo->sessionUri['bugList'] = 'qa';
$config->todo->sessionUri['taskList'] = 'execution';
$config->todo->sessionUri['storyList'] = 'product';
$config->todo->sessionUri['testtaskList'] = 'qa';
+13 -1
View File
@@ -39,4 +39,16 @@ $config->todo->batchClose->form['todoIDList'] = array('required' => true, 'type'
$config->todo->batchEdit = new stdClass;
$config->todo->batchEdit->form = array();
$config->todo->batchEdit->form['todoIDList'] = array('required' => true, 'type' => 'array');
$config->todo->batchEdit->form['names'] = array('required' => true, 'type' => 'array');
$config->todo->batchFinish = new stdclass;
$config->todo->batchFinish->form = array();
$config->todo->batchFinish->form['todoIDList'] = array('required' => true, 'type' => 'array');
$config->todo->editDate = new stdClass;
$config->todo->editDate->form = array();
$config->todo->editDate->form['date'] = array('required' => true, 'type' => 'string');
$config->todo->editDate->form['todoIDList'] = array('required' => true, 'type' => 'array');
$config->todo->export = new stdClass;
$config->todo->export->form = array();
$config->todo->export->form['exportType'] = array('required' => true, 'type' => 'string');
+101 -128
View File
@@ -35,9 +35,9 @@ class todo extends control
* @param string $date
* @param string $from todo|feedback|block
* @access public
* @return int
* @return void
*/
public function create(string $date = 'today', string $from = 'todo'): int
public function create(string $date = 'today', string $from = 'todo')
{
if($date == 'today') $date = date::today();
@@ -46,11 +46,11 @@ class todo extends control
$formData = form::data($this->config->todo->create->form);
$todo = $this->todoZen->beforeCreate($formData);
$todoID = $this->todo->create($todo);
$todoID = $this->todo->create($todo, $formData);
if($todoID === false) return print(js::error(dao::getError()));
$todo->id = $todoID;
$this->todoZen->afterCreate($todo);
$this->todoZen->afterCreate($todo, $formData);
if(!empty($_POST['objectID'])) return $this->send(array('result' => 'success'));
@@ -64,12 +64,12 @@ class todo extends control
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $todoID));
if($this->viewType == 'xhtml') return print(js::locate($this->createLink('todo', 'view', "todoID=$todoID", 'html'), 'parent'));
if(isonlybody()) return print(js::closeModal('parent.parent'));
return print(js::locate($this->createLink('my', 'todo', "type=all&userID=&status=all&orderBy=id_desc"), 'parent'));
return print(js::locate($this->createLink('my', 'todo', 'type=all&userID=&status=all&orderBy=id_desc'), 'parent'));
}
unset($this->lang->todo->typeList['cycle']);
$this->buildCreateView($date);
$this->todoZen->buildCreateView($date);
}
/**
@@ -173,19 +173,24 @@ class todo extends control
*
* @param string $from example:myTodo, todoBatchEdit.
* @param string $type
* @param int $userID
* @param string $userID
* @param string $status
* @access public
* @return void
*/
public function batchEdit(string $from = '', string $type = 'today', string $userID = '', string $status = 'all')
{
$formData = form::data($this->config->todo->batchEdit->form);
$userID = (int)$userID;
/* Get form data for my-todo. */
if($from == 'myTodo') $this->todoZen->batchEditFromMyTodo($type, $userID, $status);
if($from == 'myTodo') $this->todoZen->batchEditFromMyTodo($formData, $type, $userID, $status);
if($from == 'todoBatchEdit')
{
$formData = form::data($this->config->todo->batchEdit->form);
$this->todoZen->batchEditFromTodoBatchEdit($formData);
$todos = $this->todoZen->beforeBatchEdit($formData);
$allChanges = $this->todo->batchUpdate($todos, $formData->data->todoIDList);
$this->todoZen->afterBatchEdit($allChanges);
return print(js::locate($this->session->todoList, 'parent'));
}
}
@@ -204,7 +209,7 @@ class todo extends control
if($todo->status == 'wait')
{
this->todo->start($todoID);
$this->todo->start($todoID);
if(dao::isError()) return print(js::error(dao::getError()));
}
if(in_array($todo->type, array('bug', 'task', 'story'))) return $this->todoZen->printStartConfirm($todo);
@@ -258,7 +263,7 @@ class todo extends control
if(defined('RUN_MODE') && RUN_MODE == 'api')
{
$this->send(array('status' => 'success'));
return;
return 1; /* A function with return type must return a value. */
}
if(isonlybody()) return print(js::reload('parent.parent'));
@@ -272,9 +277,9 @@ class todo extends control
*
* @param string $todoID
* @access public
* @return int
* @return void
*/
public function assignTo(string $todoID): int
public function assignTo(string $todoID)
{
$todoID = (int)$todoID;
if(!empty($_POST))
@@ -289,13 +294,7 @@ class todo extends control
return print(js::reload('parent.parent'));
}
$this->view->todo = $this->todo->getByID($todoID);
$this->view->members = $this->loadModel('user')->getPairs('noclosed|noempty|nodeleted');
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
$this->view->actions = $this->loadModel('action')->getList('todo', $todoID);
$this->view->users = $this->user->getPairs('noletter');
$this->view->time = date::now();
$this->display();
$this->todoZen->buildAssignToView($todoID);
}
/**
@@ -306,9 +305,9 @@ class todo extends control
* @param string $from my|company
*
* @access public
* @return void
* @return int
*/
public function view(string $todoID, string $from = 'company')
public function view(string $todoID, string $from = 'company'): int
{
$todo = $this->todo->getByID((int)$todoID, true);
@@ -321,15 +320,7 @@ class todo extends control
$account = $this->app->user->account;
if($todo->private and $todo->account != $account) return print(js::error((string)$this->lang->todo->thisIsPrivate) . (string)js::locate('back'));
/* Save the session. */
if(!isonlybody())
{
$url = $this->app->getURI(true);
$this->session->set('bugList', $url, 'qa');
$this->session->set('taskList', $url, 'execution');
$this->session->set('storyList', $url, 'product');
$this->session->set('testtaskList', $url, 'qa');
}
if(!isonlybody()) $this->todoZen->setSessionUri($this->app->getURI(true));
/* Fix bug #936. */
if($account != $todo->account and $account != $todo->assignedTo and !common::hasPriv('my', 'team'))
@@ -341,6 +332,7 @@ class todo extends control
if(!isset($this->session->project)) $this->session->set('project', (int)key($projects));
$this->todoZen->buildAssignToTodoView((object)$todo, (int)$this->session->project, (array)$projects, (string)$account, $from);
return 1;
}
/**
@@ -350,36 +342,30 @@ class todo extends control
* @param string $todoID
* @param string $confirm yes|no
* @access public
* @return void
* @return int
*/
public function delete(string $todoID, string $confirm = 'no')
public function delete(string $todoID, string $confirm = 'no'): int
{
$todoID = (int)$todoID;
if($confirm == 'no')
{
return print(js::confirm($this->lang->todo->confirmDelete, $this->createLink('todo', 'delete', "todoID={$todoID}&confirm=yes")));
}
else
{
$this->todo->delete(TABLE_TODO, $todoID);
if($confirm == 'no') return print(js::confirm($this->lang->todo->confirmDelete, $this->createLink('todo', 'delete', "todoID={$todoID}&confirm=yes")));
$this->todo->delete(TABLE_TODO, $todoID);
if(helper::isAjaxRequest())
if(helper::isAjaxRequest())
{
$response = array('result' => 'success', 'message' => '');
if(dao::isError())
{
$response = array('result' => 'success', 'message' => '');
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = dao::getError();
}
return $this->send($response);
$response['result'] = 'fail';
$response['message'] = dao::getError();
}
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
if(isonlybody()) return print(js::reload('parent.parent'));
$browseLink = $this->session->todoList ? $this->session->todoList : $this->createLink('my', 'todo');
return print(js::locate($browseLink, 'parent'));
return $this->send($response);
}
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
if(isonlybody()) return print(js::reload('parent.parent'));
$browseLink = $this->session->todoList ? $this->session->todoList : $this->createLink('my', 'todo');
return print(js::locate($browseLink, 'parent'));
}
/**
@@ -388,14 +374,21 @@ class todo extends control
*
* @param string $todoID
* @access public
* @return void
* @return int|false
*/
public function finish(string $todoID)
public function finish(string $todoID): int|false
{
$todo = $this->todo->getByID((int)$todoID);
if($todo->status != 'done' && $todo->status != 'closed') $this->todo->finish((int)$todoID);
$todoID = (int)$todoID;
$todo = $this->todo->getByID($todoID);
if($todo->status != 'done' && $todo->status != 'closed')
{
$result = $this->todo->finish($todoID);
if(!$result) return false;
}
if(in_array($todo->type, array('bug', 'task', 'story')))
$types = $this->config->todo->moduleList;
array_pop($types);
if(in_array($todo->type, $types))
{
$confirmNote = 'confirm' . ucfirst($todo->type);
$okTarget = isonlybody() ? 'parent' : 'window.parent.$.apps.open';
@@ -404,6 +397,7 @@ class todo extends control
if($todo->type == 'bug') $app = 'qa';
if($todo->type == 'task') $app = 'execution';
if($todo->type == 'story') $app = 'product';
$cancelURL = $this->server->http_referer;
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->objectID), 'locate' => $confirmURL));
return print(strpos($cancelURL, 'calendar') ? json_encode(array(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL)) : js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
@@ -411,11 +405,10 @@ class todo extends control
if(defined('RUN_MODE') && RUN_MODE == 'api')
{
$this->send(array('status' => 'success'));
return;
return $this->send(array('status' => 'success'));
}
if(isonlybody()) return print(js::reload('parent.parent'));
echo js::reload('parent');
return print(js::reload('parent'));
}
/**
@@ -423,23 +416,21 @@ class todo extends control
* Batch finish todos.
*
* @access public
* @return void
* @return int|false
*/
public function batchFinish()
public function batchFinish(): int|false
{
if($this->post->todoIDList)
$todoIDList = form::data($this->config->todo->batchFinish->form)->get('todoIDList');
$todoList = $this->todo->getByList($todoIDList);
foreach($todoList as $todoID => $todo)
{
$todoList = $this->todo->getByList((array)$this->post->todoIDList);
foreach($todoList as $todoID => $todo)
{
if($todo->status == 'done' || $todo->status == 'closed') unset($todoList[$todoID]);
}
$isBatchFinished = $this->todo->batchFinish(array_keys($todoList));
if(!$isBatchFinished) return false;
return print(js::reload('parent'));
if($todo->status == 'done' || $todo->status == 'closed') unset($todoList[$todoID]);
}
$isBatchFinished = $this->todo->batchFinish(array_keys($todoList));
if(!$isBatchFinished) return false;
return print(js::reload('parent'));
}
/**
@@ -473,18 +464,21 @@ class todo extends control
* @access public
* @return void
*/
public function import2Today(string $todoID = '')
public function import2Today(string $todoID = ''): void
{
$todoIDList = $_POST ? $this->post->todoIDList : array($todoID);
$date = !empty($_POST['date']) ? $_POST['date'] : date::today();
if(!$date || !$todoIDList) return $this->locate((string)$this->session->todoList);
if(!$_POST) $this->locate($this->createLink('my', 'todo'));
$formData = form::data($this->config->todo->editDate->form);
$todoIDList = !empty($formData->rawdata->todoIDList) ? $formData->rawdata->todoIDList : array($todoID);
$date = !empty($formData->rawdata->date) ? $formData->rawdata->date : date::today();
if(!$todoIDList) $this->locate((string)$this->session->todoList);
$this->todo->editDate((array)$todoIDList, (string)$date);
return $this->locate((string)$this->session->todoList);
$this->locate((string)$this->session->todoList);
}
/**
* Get data to export
* Get data to export.
*
* @param int $userID
* @param string $orderBy
@@ -495,57 +489,35 @@ class todo extends control
{
if($_POST)
{
$user = $this->loadModel('user')->getById($userID, 'id');
$account = $user->account;
$todoLang = $this->lang->todo;
$user = $this->todoZen->getUserById((int)$userID);
$account = (string)$user->account;
$todoLang = (object)$this->lang->todo;
$configTime = $this->config->todo->times;
/* Create field lists. */
$fields = $this->todoZen->exportFields(explode(',', $this->config->todo->list->exportFields), (object)$todoLang);
$formData = form::data($this->config->todo->export->form);
$todos = $this->todo->getByExportList($orderBy, (object)$formData);
/* Get bugs. */
$todos = $this->dao->select('*')->from(TABLE_TODO)->where($this->session->todoReportCondition)
->beginIF($this->post->exportType == 'selected')->andWhere('id')->in($this->cookie->checkedItem)->fi()
->orderBy($orderBy)->fetchAll('id');
list($todos, $fields) = $this->todoZen->exportTodoInfo((array)$todos, (string)$this->config->todo->list->exportFields, $todoLang);
list($users, $bugs, $stories, $tasks, $testTasks) = $this->todoZen->exportAssociated('default', $account);
/* Get users, bugs, tasks and times. */
list($users, $bugs, $stories, $tasks, $testTasks) = $this->todoZen->exportInfo('default', $account);
$times = date::buildTimeList((int)$configTime->begin, (int)$configTime->end, (int)$configTime->delta);
if($this->config->edition == 'max') list($issues, $risks, $opportunities) = $this->todoZen->exportInfo($this->config->edition, $account);
if(isset($this->config->qcVersion)) $reviews = $this->todoZen->exportInfo('qcVersion', $account);
$times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
foreach($todos as $todo)
$assemble = new stdClass();
$assemble->users = $users;
$assemble->bugs = $bugs;
$assemble->stories = $stories;
$assemble->tasks = $tasks;
$assemble->testTasks = $testTasks;
if($this->config->edition == 'max')
{
/* fill some field with useful value. */
$todo->begin = $todo->begin == '2400' ? '' : (isset($times[$todo->begin]) ? $times[$todo->begin] : $todo->begin);
$todo->end = $todo->end == '2400' ? '' : (isset($times[$todo->end]) ? $times[$todo->end] : $todo->end);
$type = $todo->type;
if(isset($users[$todo->account])) $todo->account = $users[$todo->account];
if($type == 'bug') $todo->name = isset($bugs[$todo->objectID]) ? $bugs[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'story') $todo->name = isset($stories[$todo->objectID]) ? $stories[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'task') $todo->name = isset($tasks[$todo->objectID]) ? $tasks[$todo->objectID] . "(#$todo->objectID)" : '';
if($this->config->edition == 'max')
{
if($type == 'issue') $todo->name = isset($issues[$todo->objectID]) ? $issues[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'risk') $todo->name = isset($risks[$todo->objectID]) ? $risks[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'opportunity') $todo->name = isset($opportunities[$todo->objectID]) ? $opportunities[$todo->objectID] . "(#$todo->objectID)" : '';
}
if($type == 'testtask') $todo->name = isset($testTasks[$todo->objectID]) ? $testTasks[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'review' && isset($this->config->qcVersion)) $todo->name = isset($reviews[$todo->objectID]) ? $reviews[$todo->objectID] . "(#$todo->objectID)" : '';
if(isset($todoLang->typeList[$type])) $todo->type = $todoLang->typeList[$type];
if(isset($todoLang->priList[$todo->pri])) $todo->pri = $todoLang->priList[$todo->pri];
if(isset($todoLang->statusList[$todo->status])) $todo->status = $todoLang->statusList[$todo->status];
if($todo->private == 1) $todo->desc = $this->lang->todo->thisIsPrivate;
/* drop some field that is not needed. */
unset($todo->objectID);
unset($todo->private);
$iroData = $this->todoZen->exportInfo((string)$this->config->edition, $account);
$assemble->issues = $iroData[0];
$assemble->risks = $iroData[1];
$assemble->opportunities = $iroData[2];
}
if($this->config->edition != 'open') list($fields, $todos) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $todos);
if(isset($this->config->qcVersion)) $assemble->reviews = $this->todoZen->exportInfo('qcVersion', $account);
$todos = $this->todoZen->assembleExportData((array)$todos, $assemble, $todoLang, (array)$times);
$this->post->set('fields', $fields);
$this->post->set('rows', $todos);
@@ -594,6 +566,7 @@ class todo extends control
*/
public function ajaxGetExecutionPairs($projectID)
{
$projectID = (int)$projectID;
$this->session->set('project', $projectID);
$project = $this->loadModel('project')->getByID($projectID);
+2
View File
@@ -0,0 +1,2 @@
.form-row .items-center {align-items: center;}
.form-row .form-group.pl-3 {padding-left: 0.75rem;}
+81 -83
View File
@@ -149,80 +149,43 @@ class todoModel extends model
}
/**
* Batch update todos.
* 更新批量编辑待办数据。
* Update batch edit todo data.
*
* @access public
* @return array
* @param array $todos
* @param array $todoIdList
* @access protected
* @return array|int
*/
public function batchUpdate()
public function batchUpdate(array $todos, array $todoIdList): array|int
{
$todos = array();
if(empty($todos)) return $todos;
$allChanges = array();
$data = fixer::input('post')->get();
$todoIDList = $this->post->todoIDList ? $this->post->todoIDList : array();
if(!empty($todoIDList))
/* Initialize todos from the post data. */
$oldTodos = $this->getTodosByIdList($todoIdList);
foreach($todos as $todoID => $todo)
{
/* Initialize todos from the post data. */
$oldTodos = $this->dao->select('*')->from(TABLE_TODO)->where('id')->in(array_keys($todos))->fetchAll('id');
foreach($todoIDList as $todoID)
$oldTodo = $oldTodos[$todoID];
if(in_array($todo->type, $this->config->todo->moduleList)) $oldTodo->name = '';
$this->updateTodoDataByID($todoID, $todo);
if($oldTodo->status != 'done' and $todo->status == 'done') $this->loadModel('action')->create('todo', $todoID, 'finished', '', 'done');
if(!dao::isError())
{
$oldTodo = $oldTodos[$todoID];
$todo = new stdclass();
$todo->date = $data->dates[$todoID];
$todo->type = $data->types[$todoID];
$todo->pri = $data->pris[$todoID];
$todo->status = $data->status[$todoID];
$todo->name = !in_array($todo->type, $this->config->todo->moduleList) ? $data->names[$todoID] : '';
$todo->begin = isset($data->begins[$todoID]) ? $data->begins[$todoID] : 2400;
$todo->end = isset($data->ends[$todoID]) ? $data->ends[$todoID] : 2400;
$todo->assignedTo = isset($data->assignedTos[$todoID]) ? $data->assignedTos[$todoID] : $oldTodo->assignedTo;
if(in_array($todo->type, $this->config->todo->moduleList))
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->objectID && !isset($feedbacks[$todo->objectID]))
{
$todo->objectID = isset($data->{$this->config->todo->objectList[$todo->type]}[$todoID]) ? $data->{$this->config->todo->objectList[$todo->type]}[$todoID] : 0;
$feedbacks[$todo->objectID] = $todo->objectID;
$this->loadModel('feedback')->updateStatus('todo', $todo->objectID, $todo->status);
}
if($todo->end < $todo->begin) return print(js::alert(sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin)));
$todos[$todoID] = $todo;
$allChanges[$todoID] = common::createChanges($oldTodo, $todo);
}
foreach($todos as $todoID => $todo)
else
{
$oldTodo = $oldTodos[$todoID];
if(in_array($todo->type, $this->config->todo->moduleList)) $oldTodo->name = '';
$this->dao->update(TABLE_TODO)->data($todo)
->autoCheck()
->checkIF(!in_array($todo->type, $this->config->todo->moduleList), $this->config->todo->edit->requiredFields, 'notempty')
->checkIF($todo->type == 'bug' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'task' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'story' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'issue' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'risk' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'opportunity' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'review' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'testtask' and $todo->objectID == 0, 'objectID', 'notempty')
->checkIF($todo->type == 'feedback' and $todo->objectID == 0, 'objectID', 'notempty')
->where('id')->eq($todoID)
->exec();
if($oldTodo->status != 'done' and $todo->status == 'done') $this->loadModel('action')->create('todo', $todoID, 'finished', '', 'done');
if(!dao::isError())
{
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->objectID && !isset($feedbacks[$todo->objectID]))
{
$feedbacks[$todo->objectID] = $todo->objectID;
$this->loadModel('feedback')->updateStatus('todo', $todo->objectID, $todo->status);
}
$allChanges[$todoID] = common::createChanges($oldTodo, $todo);
}
else
{
return print(js::error('todo#' . $todoID . dao::getError(true)));
}
return print(js::error('todo#' . $todoID . dao::getError(true)));
}
}
@@ -578,44 +541,41 @@ class todoModel extends model
*/
public function assignTo(object $todo): bool
{
$res = $this->todoTao->updateRow((int)$todo->id, $todo);
if(!$res) return false;
$todoID = (int)$todo->id;
$result = $this->todoTao->updateRow($todoID, $todo);
if(!$result) return false;
$this->loadModel('action')->create('todo', (int)$todo->id, 'assigned', '', $todo->assignedTo);
$this->loadModel('action')->create('todo', $todoID, 'assigned', '', $todo->assignedTo);
return !dao::isError();
}
/**
* 获取待办事项的数量。
* Get todo count.
*
* @param string $account
* @access public
* @return int
*/
public function getCount($account = '')
public function getCount(string $account = ''): int
{
if(empty($account)) $account = $this->app->user->account;
return $this->dao->select('count(*) as count')->from(TABLE_TODO)
->where('cycle')->eq('0')
->andWhere('deleted')->eq('0')
->andWhere('vision')->eq($this->config->vision)
->andWhere('account', true)->eq($account)
->orWhere('assignedTo')->eq($account)
->orWhere('finishedBy')->eq($account)
->markRight(1)
->fetch('count');
return $this->todoTao->getTodoCountByAccount($account);
}
/**
* 获取待办事项对象的项目ID。
* Gets the project ID of the to-do object.
*
* @param array $todoList
* @access public
* @return array
*/
public function getTodoProjects($todoList = array())
public function getTodoProjects(array $todoList = array()): array
{
$projectIdList = array();
foreach($todoList as $type => $todos)
{
$todoIdList = array_keys($todos);
@@ -626,13 +586,8 @@ class todoModel extends model
}
$todoIdList = array_unique($todoIdList);
if($type == 'task') $projectIdList[$type] = $this->dao->select('id,project')->from(TABLE_TASK)->where('id')->in($todoIdList)->fetchPairs('id', 'project');
if($type == 'bug') $projectIdList[$type] = $this->dao->select('id,project')->from(TABLE_BUG)->where('id')->in($todoIdList)->fetchPairs('id', 'project');
if($type == 'issue') $projectIdList[$type] = $this->dao->select('id,project')->from(TABLE_ISSUE)->where('id')->in($todoIdList)->fetchPairs('id', 'project');
if($type == 'risk') $projectIdList[$type] = $this->dao->select('id,project')->from(TABLE_RISK)->where('id')->in($todoIdList)->fetchPairs('id', 'project');
if($type == 'opportunity') $projectIdList[$type] = $this->dao->select('id,project')->from(TABLE_OPPORTUNITY)->where('id')->in($todoIdList)->fetchPairs('id', 'project');
if($type == 'review') $projectIdList[$type] = $this->dao->select('id,project')->from(TABLE_REVIEW)->where('id')->in($todoIdList)->fetchPairs('id', 'project');
if($type == 'testtask') $projectIdList[$type] = $this->dao->select('id,project')->from(TABLE_TESTTASK)->where('id')->in($todoIdList)->fetchPairs('id', 'project');
$typeTable = array('task' => TABLE_TASK,'bug' => TABLE_BUG,'issue' => TABLE_ISSUE,'risk' => TABLE_RISK,'opportunity' => TABLE_OPPORTUNITY,'review' => TABLE_REVIEW,'testtask' => TABLE_TESTTASK);
$projectIdList[$type] = $this->dao->select('id,project')->from($typeTable[$type])->where('id')->in($todoIdList)->fetchPairs('id', 'project');
}
return $projectIdList;
@@ -680,4 +635,47 @@ class todoModel extends model
{
return $this->todoTao->updateDate($todoIDList, $date);
}
/**
* 获取导出的待办数据。
* Get data for export todo.
*
* @param string $orderBy
* @param object $formData
* @access public
* @return array
*/
public function getByExportList(string $orderBy, object $formData): array
{
return $this->dao->select('*')->from(TABLE_TODO)
->where($this->session->todoReportCondition)
->beginIF($formData->rawdata->exportType == 'selected')->andWhere('id')->in($this->cookie->checkedItem)->fi()
->orderBy($orderBy)->fetchAll('id');
}
/**
* 根据待办ID获取多条待办。
* Get todo data by id list.
*
* @param array $todoIdList
* @access public
* @return array
*/
public function getTodosByIdList(array $todoIdList): array
{
return $this->todoTao->fetchRows($todoIdList);
}
/**
* 根据待办ID更新待办数据。
* Update todo data by id.
*
* @param array $todoIdList
* @access public
* @return bool
*/
public function updateTodoDataByID(int $todoID, object $todo): bool
{
return $this->todoTao->updateRow($todoID, $todo);
}
}
+39 -5
View File
@@ -4,8 +4,8 @@ declare(strict_types=1);
class todoTao extends todoModel
{
/**
* 获取单条待办。
* Get a todo.
* 获取单条待办.
*
* @param int $todoID
* @param object $todo
@@ -16,6 +16,18 @@ class todoTao extends todoModel
return $this->dao->select('*')->from(TABLE_TODO)->where('id')->eq($todoID)->fetch();
}
/**
* 获取多条待办。
* Get a todo.
*
* @param array $todoIdList
* @return array
*/
protected function fetchRows(array $todoIdList): array
{
return $this->dao->select('*')->from(TABLE_TODO)->where('id')->in(array_keys($todoIdList))->fetchAll('id');
}
/**
* 插入待办数据
* Insert todo data.
@@ -48,8 +60,8 @@ class todoTao extends todoModel
{
$this->dao->update(TABLE_TODO)->data($todo)
->autoCheck()
->checkIF(in_array($todo->type, array('custom', 'feedback')), $this->config->todo->edit->requiredFields, 'notempty')
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->objectID == 0, 'objectID', 'notempty')
->checkIF(isset($todo->type) && in_array($todo->type, array('custom', 'feedback')), $this->config->todo->edit->requiredFields, 'notempty')
->checkIF(isset($todo->type) && in_array($todo->type, $this->config->todo->moduleList) && $todo->objectID == 0, 'objectID', 'notempty')
->where('id')->eq($todoID)
->exec();
@@ -82,10 +94,11 @@ class todoTao extends todoModel
* Process the data for the todo to be created.
*
* @param object $todoData
* @param object $formData
* @access protected
* @return object|false
*/
protected function processCreateData(object $todoData): object|false
protected function processCreateData(object $todoData, object $formData): object|false
{
if(!isset($todoData->pri) and in_array($todoData->type, $this->config->todo->moduleList) and !in_array($todoData->type, array('review', 'feedback')))
{
@@ -117,7 +130,7 @@ class todoTao extends todoModel
}
if(empty($todoData->cycle)) unset($todoData->config);
return $this->loadModel('file')->processImgURL($todoData, $this->config->todo->editor->create['id'], $this->post->uid);
return $this->loadModel('file')->processImgURL($todoData, $this->config->todo->editor->create['id'], $formData->rawdata->uid);
}
/**
@@ -323,4 +336,25 @@ class todoTao extends todoModel
$this->dao->update(TABLE_TODO)->set('date')->eq($date)->where('id')->in($todoIdList)->exec();
return !dao::isError();
}
/**
* 获取用户的待办事项数量。
* Get todo count on the account.
*
* @param string $account
* @access protected
* @return int
*/
protected function getTodoCountByAccount(string $account): int
{
return $this->dao->select('count(*) as count')->from(TABLE_TODO)
->where('cycle')->eq('0')
->andWhere('deleted')->eq('0')
->andWhere('vision')->eq($this->config->vision)
->andWhere('account', true)->eq($account)
->orWhere('assignedTo')->eq($account)
->orWhere('finishedBy')->eq($account)
->markRight(1)
->fetch('count');
}
}
+7 -20
View File
@@ -6,20 +6,7 @@ su('admin');
function initData()
{
$project = zdTable('todo');
$project->id->range('1-5');
$project->account->range('admin');
$project->date->prefix('2023-04-2')->range('1-9');
$project->begin->range('1000-1100');
$project->end->range('1200-1300');
$project->type->range("custom");
$project->cycle->range("0");
$project->pri->range("3");
$project->name->prefix('我的待办')->range("1-5");
$project->desc->prefix('这是我的描述')->range("1-5");
$project->status->range("wait");
$project->gen(5);
zdTable('todo')->config('assignto')->gen(5);
}
/**
@@ -28,29 +15,29 @@ title=测试 todoModel->assignTo();
timeout=0
cid=1
- 执行todo模块的assignTo方法,参数是$todoIDList[0], $todo1
- 指派todo 1给test1 选择待定
- 属性assignedTo @test1
- 属性date @20300101
- 属性begin @1000
- 属性end @1400
- 执行todo模块的assignTo方法,参数是$todoIDList[1], $todo2
- 指派todo 2给test1 暂时不设定时间
- 属性assignedTo @test1
- 属性begin @2400
- 属性end @2400
- 执行todo模块的assignTo方法,参数是$todoIDList[2], $todo3
- 指派todo 3给test1
- 属性assignedTo @test1
- 属性begin @1002
- 属性end @1402
- 执行todo模块的assignTo方法,参数是$todoIDList[3], $todo4
- 指派todo 4给admin future=on 验证 date默认值
- 属性assignedTo @admin
- 属性date @20300101
- 属性begin @1200
- 属性end @1502
- 执行todo模块的assignTo方法,参数是$todoIDList[4], $todo5
- 指派todo 5给admin future=on lblDisableDate=on 验证date,begin,end默认值
- 属性assignedTo @admin
- 属性date @20300101
- 属性begin @2400
@@ -62,7 +49,7 @@ cid=1
initData();
$todoIDList = array('1', '2', '3', '4', '5');
$todoIDList = range(1,5);
$todo1 = new stdclass();
$todo1->assignedTo = 'test1';
+8 -20
View File
@@ -6,20 +6,7 @@ su('admin');
function initData()
{
$project = zdTable('todo');
$project->id->range('1-100');
$project->account->range('admin');
$project->date->prefix('2023-04-2')->range('1-9');
$project->begin->range('1000-1100');
$project->end->range('1200-1300');
$project->type->range("custom");
$project->cycle->range("0");
$project->pri->range("3");
$project->name->prefix('我的待办')->range("1-5");
$project->desc->prefix('这是我的描述')->range("1-5");
$project->status->range("wait");
$project->gen(10);
zdTable('todo')->config('batchfinish')->gen(10);
}
/**
@@ -28,21 +15,22 @@ title=测试批量完成待办 todoModel->batchFinish();
timeout=0
cid=1
- 执行todo模块的getById方法,参数是$todoIDList[0]属性status @done
- 批量完成todo验证状态wait->done属性status @done
- 执行todo模块的getById方法,参数是$todoIDList[1]属性status @done
- 批量完成todo验证状态donging->done属性status @done
- 执行todo模块的getById方法,参数是$todoIDList[2]属性status @done
- 批量完成todo验证状态done属性status @done
*/
$todoIDList = array('1', '2', '3');
initData();
$todoIDList = range(1,3);
$todo = new todoTest();
$todo->batchFinishTest($todoIDList);
r($todo->getByIdTest($todoIDList[0])) && p('status') && e('done'); // 批量完成todo验证状态done
r($todo->getByIdTest($todoIDList[1])) && p('status') && e('done'); // 批量完成todo验证状态done
r($todo->getByIdTest($todoIDList[0])) && p('status') && e('done'); // 批量完成todo验证状态wait->done
r($todo->getByIdTest($todoIDList[1])) && p('status') && e('done'); // 批量完成todo验证状态donging->done
r($todo->getByIdTest($todoIDList[2])) && p('status') && e('done'); // 批量完成todo验证状态done
+1 -7
View File
@@ -16,13 +16,7 @@ pid=1
global $tester;
$tester->loadModel('todo');
$todo = zdTable('todo');
$todo->id->range('1');
$todo->name->prefix("待办")->range('1');
$todo->date->range('`2023-04-23`');
$todo->type->range('custom');
$todo->status->range('wait');
$todo->gen(1, '', true);
zdTable('todo')->config('close')->gen(1);
r($tester->todo->getByID(1)) && p('status') && e('wait');
r($tester->todo->close(1)) && p() && e(1);
+3 -16
View File
@@ -6,20 +6,7 @@ su('admin');
function initData()
{
$project = zdTable('todo');
$project->id->range('1-100');
$project->account->range('admin');
$project->date->prefix('2023-04-2')->range('1-9');
$project->begin->range('1000-1100');
$project->end->range('1200-1300');
$project->type->range("custom");
$project->cycle->range("0");
$project->pri->range("3");
$project->name->prefix('我的待办')->range("1-5");
$project->desc->prefix('这是我的描述')->range("1-5");
$project->status->range("wait");
$project->gen(10);
zdTable('todo')->config('delete')->gen(10);
}
/**
@@ -28,11 +15,11 @@ title=测试删除todo todoModel->delete();
timeout=0
cid=1
- 执行todo模块的delete方法,参数是8, no
- 删除指定id的待办,取消确认
- 属性id @8
- 属性deleted @0
- 执行todo模块的getById方法,参数是8属性deleted @1
- 验证删除id不存在的todo信息属性deleted @1
+4 -15
View File
@@ -1,20 +1,10 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/todo.class.php';
su('admin');
function initData()
{
$project = zdTable('todo');
$project->id->range('1-5');
$project->name->prefix("自定义的待办")->range('1-5');
$project->type->range(1);
$project->status->range("wait,doing,done,closed,closed");
$project->gen(5);
}
/**
title=测试 todoModel->editDateTest();
@@ -27,8 +17,7 @@ pid=1
global $tester;
$tester->loadModel('todo');
initData();
zdTable('todo')->config('editdate')->gen(5);
r($tester->todo->editDate(array(1), '2023-06-07')) && p() && e(true); // 获取id为1的待办的日期
r($tester->todo->editDate(array(2, 3), '2023-04-27')) && p() && e(true); // 获取id 为1,2待办的日期
#r($tester->todo->editDate(array(9), '2023-04-17')) && p() && e('0'); // 修改不存在的待办的日期
r($tester->todo->editDate(array(1), '2023-06-07')) && p() && e(true); // 修改id为1的待办的日期
r($tester->todo->editDate(array(2, 3), '2023-04-27')) && p() && e(true); // 修改id为2,3的待办的日期
+4 -17
View File
@@ -6,20 +6,7 @@ su('admin');
function initData()
{
$project = zdTable('todo');
$project->id->range('1-100');
$project->account->range('admin');
$project->date->prefix('2023-04-2')->range('1-9');
$project->begin->range('1000-1100');
$project->end->range('1200-1300');
$project->type->range("custom");
$project->cycle->range("0");
$project->pri->range("3");
$project->name->prefix('我的待办')->range("1-5");
$project->desc->prefix('这是我的描述')->range("1-5");
$project->status->range("wait,doing,done");
$project->gen(10);
zdTable('todo')->config('finish')->gen(10);
}
/**
@@ -28,11 +15,11 @@ title=测试完成待办 todoModel->finish();
timeout=0
cid=1
- 执行todo模块的finish方法,参数是$todoIDList[0]属性status @done
- 结束一个状态为wait的todo属性status @done
- 执行todo模块的finish方法,参数是$todoIDList[1]属性status @done
- 结束一个状态为doing的todo属性status @done
- 执行todo模块的finish方法,参数是$todoIDList[2]属性status @done
- 结束一个状态为done的todo属性status @done
+8 -13
View File
@@ -1,23 +1,19 @@
#!/usr/bin/env php
<?php
declare(strict_types=1);
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/todo.class.php';
su('admin');
function initData()
function initData ()
{
$project = zdTable('todo');
$project->id->range('1-5');
$project->name->prefix("自定义的待办")->range('1-5');
$project->type->range(1);
$project->status->range("wait,doing,done,closed,closed");
$project->gen(5);
zdTable('todo')->config('getbyid')->gen(5);
}
/**
title=测试 todoModel->getById();
title=测试 todoModel->getByID();
cid=1
pid=1
@@ -29,7 +25,6 @@ $todo = new todoTest();
initData();
r($todo->getByIdTest($todoIDList[0])) && p('name,status') && e('自定义的待办1,wait'); // 获取id为1的todo信息
r($todo->getByIdTest($todoIDList[1])) && p('name,status') && e('自定义的待办2,doing'); // 获取id为2的todo信息
r($todo->getByIdTest($todoIDList[3])) && p('name,status') && e('自定义的待办5,closed'); // 获取id为5的todo信息
r($todo->getByIdTest($todoIDList[4])) && p() && e('0'); // 获取id不存在的todo信息
r($todo->getByIDTest($todoIDList[0])) && p('name,status') && e('自定义的待办1,wait'); // 获取id为1的todo信息
r($todo->getByIDTest($todoIDList[1])) && p('name,status') && e('自定义的待办2,doing'); // 获取id为2的todo信息
r($todo->getByIDTest($todoIDList[3])) && p('name,status') && e('自定义的待办5,closed'); // 获取id为5的todo信息
@@ -0,0 +1,33 @@
title: zt_assignto
author: liuchenglong
version: "1.0"
fields:
- field: id
range: 1-5
- field: account
range: 'admin'
- field: date
range: 1-9
prefix: '2023-04-2'
- field: begin
range: 1000-1100
- field: end
range: 1200-1300
- field: type
range: 'custom'
- field: cycle
range: 0
- field: pri
range: 3
- field: name
range: 1-5
prefix: '我的待办'
- field: desc
range: 1-5
prefix: '这是待办描述'
- field: status
range: 'wait'
@@ -0,0 +1,32 @@
title: zt_batchfinish
author: liuchenglong
version: "1.0"
fields:
- field: id
range: 1-100
- field: account
range: 'admin'
- field: date
range: 1-9
prefix: '2023-04-2'
- field: begin
range: 1000-1100
- field: end
range: 1200-1300
- field: type
range: 'custom'
- field: cycle
range: 0
- field: pri
range: 3
- field: name
range: 1-5
prefix: '我的待办'
- field: desc
range: 1-5
prefix: '这是待办描述'
- field: status
range: 'wait,doing,done'
@@ -0,0 +1,15 @@
title: Create todos for todoModel::close UTC.
desc: Create todos for todoModel::close UTC.
version: 1.0.0
fields:
- field: id
range: 1
- field: date
range: '`2023-04-23`'
- field: type
range: custom
- field: status
range: wait
- field: id
range: 1
@@ -0,0 +1,32 @@
title: zt_delete
author: liuchenglong
version: "1.0"
fields:
- field: id
range: 1-100
- field: account
range: 'admin'
- field: date
range: 1-9
prefix: '2023-04-2'
- field: begin
range: 1000-1100
- field: end
range: 1200-1300
- field: type
range: 'custom'
- field: cycle
range: 0
- field: pri
range: 3
- field: name
range: 1-5
prefix: '我的待办'
- field: desc
range: 1-5
prefix: '这是待办描述'
- field: status
range: 'wait,doing,done'
@@ -0,0 +1,13 @@
title: Create todos for todoModel::close UTC.
desc: Create todos for todoModel::close UTC.
version: 1.0.0
fields:
- field: id
range: 1-5
- field: date
range: '`2023-05-03`'
- field: type
range: custom
- field: status
range: wait
@@ -0,0 +1,32 @@
title: zt_finish
author: liuchenglong
version: "1.0"
fields:
- field: id
range: 1-100
- field: account
range: 'admin'
- field: date
range: 1-9
prefix: '2023-04-2'
- field: begin
range: 1000-1100
- field: end
range: 1200-1300
- field: type
range: 'custom'
- field: cycle
range: 0
- field: pri
range: 3
- field: name
range: 1-5
prefix: '我的待办'
- field: desc
range: 1-5
prefix: '这是待办描述'
- field: status
range: 'wait,doing,done'
@@ -0,0 +1,31 @@
title: zt_getbyid
author: jukui
version: "1.0"
fields:
- field: id
range: 1-5
- field: account
range: 'admin'
- field: date
range: 1-9
prefix: '2023-04-2'
- field: begin
range: 1000-1100
- field: end
range: 1200-1300
- field: type
range: 'custom'
- field: cycle
range: 0
- field: pri
range: 3
- field: name
range: 1-5
prefix: '自定义的待办'
- field: desc
range: 1-5
prefix: '这是待办描述'
- field: status
range: 'wait,doing,done,closed,closed'
+274 -75
View File
@@ -11,7 +11,7 @@ class todoZen extends todo
* @access protected
* @return void
*/
protected function buildCreateView(string $date): void
protected function buildCreateView(string $date)
{
$this->view->title = $this->lang->todo->common . $this->lang->colon . $this->lang->todo->create;
$this->view->date = date('Y-m-d', strtotime($date));
@@ -41,6 +41,26 @@ class todoZen extends todo
$this->display();
}
/**
* 生成指派待办视图数据。
* Build assignTo form data.
*
* @param int $todoID
* @access protected
* @return void
*/
protected function buildAssignToView(int $todoID): void
{
$this->view->todo = $this->todo->getByID($todoID);
$this->view->members = $this->loadModel('user')->getPairs('noclosed|noempty|nodeleted');
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
$this->view->actions = $this->loadModel('action')->getList('todo', $todoID);
$this->view->users = $this->user->getPairs('noletter');
$this->view->time = date::now();
$this->display();
}
/**
* 处理请求数据
* Processing request data.
@@ -51,11 +71,12 @@ class todoZen extends todo
*/
protected function beforeCreate(object $formData): object
{
$objectType = $this->post->type;
$rowData = $formData->rawdata;
$objectType = $rowData->type;
$hasObject = in_array($objectType, $this->config->todo->moduleList);
$objectID = 0;
if($hasObject && $objectType) $objectID = $this->post->uid ? $this->post->$objectType : $this->post->objectID;
if($hasObject && $objectType) $objectID = $rowData->uid ? $rowData->$objectType : $rowData->objectID;
$data = $formData->add('account', $this->app->user->account)
->setDefault('objectID', 0)
@@ -65,11 +86,11 @@ class todoZen extends todo
->setDefault('assignedDate', helper::now())
->cleanInt('pri, begin, end, private')
->setIF($hasObject && $objectType, 'objectID', $objectID)
->setIF($this->post->date == false, 'date', '2030-01-01')
->setIF($this->post->begin == false, 'begin', '2400')
->setIF($this->post->begin == false or $this->post->end == false, 'end', '2400')
->setIF($this->post->status == 'done', 'finishedBy', $this->app->user->account)
->setIF($this->post->status == 'done', 'finishedDate', helper::now())
->setIF($rowData->date == false, 'date', '2030-01-01')
->setIF($rowData->begin == false, 'begin', '2400')
->setIF($rowData->begin == false or $rowData->end == false, 'end', '2400')
->setIF($rowData->status == 'done', 'finishedBy', $this->app->user->account)
->setIF($rowData->status == 'done', 'finishedDate', helper::now())
->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)
->remove(implode(',', $this->config->todo->moduleList) . ',uid')
->get();
@@ -82,12 +103,13 @@ class todoZen extends todo
* Create a todo after data processing.
*
* @param object $todo
* @param object $formData
* @access protected
* @return object
*/
protected function afterCreate(object $todo): object
protected function afterCreate(object $todo, object $formData): object
{
$this->loadModel('file')->updateObjectID($this->post->uid, $todo->id, 'todo');
$this->loadModel('file')->updateObjectID($formData->rawdata->uid, $todo->id, 'todo');
$this->loadModel('score')->create('todo', 'create', $todo->id);
@@ -156,7 +178,7 @@ class todoZen extends todo
}
/**
* 编辑完成待办后数据处理
* 编辑完成待办后数据处理。
* Handle data after edit todo.
*
* @param object $todo
@@ -171,89 +193,180 @@ class todoZen extends todo
$this->action->logHistory($actionID, $changes);
}
protected function batchEditFromMyTodo($type, $userID, $status)
/**
* 批量编辑页面渲染。
* Batch edit view display.
*
* @param object $formData
* @param string $type
* @param int $userID
* @param string $status
* @access protected
* @return void
*/
protected function batchEditFromMyTodo(object $formData, string $type, int $userID, string $status): void
{
/* Initialize vars. */
$editedTodos = array();
$todoIDList = array();
$reviews = array();
$columns = 7;
$editedTodos = $objectIdList = $reviews = array();
$columns = 7;
unset($this->lang->todo->typeList['cycle']);
if($userID == '') $userID = $this->app->user->id;
if(empty($userID)) $userID = $this->app->user->id;
$user = $this->loadModel('user')->getById($userID, 'id');
$account = $user->account;
if($this->config->edition == 'max') $reviews = $this->loadModel('review')->getUserReviewPairs($account);
$allTodos = $this->todo->getList($type, $account, $status);
if($this->post->todoIDList) $todoIDList = $this->post->todoIDList;
list($editedTodos, $objectIdList) = $this->getBatchEditInitTodos($formData, $type, $account, $status);
/* Initialize todos whose need to edited. */
foreach($allTodos as $todo)
{
if(in_array($todo->id, $todoIDList))
{
$editedTodos[$todo->id] = $todo;
if($todo->type != 'custom')
{
if(!isset($objectIDList[$todo->type])) $objectIDList[$todo->type] = array();
$objectIDList[$todo->type][$todo->objectID] = $todo->objectID;
}
}
}
$bugs = $this->bug->getUserBugPairs($account, true, 0, '', '', isset($objectIDList['bug']) ? $objectIDList['bug'] : '');
$tasks = $this->task->getUserTaskPairs($account, 'wait,doing', '', isset($objectIDList['task']) ? $objectIDList['task'] : '');
$storys = $this->loadModel('story')->getUserStoryPairs($account, 10, 'story', '', isset($objectIDList['story']) ? $objectIDList['story'] : '');
if($this->config->edition != 'open') $this->view->feedbacks = $this->loadModel('feedback')->getUserFeedbackPairs($account, '', isset($objectIDList['feedback']) ? $objectIDList['feedback'] : '');
$bugs = $this->bug->getUserBugPairs($account, true, 0, '', '', isset($objectIdList['bug']) ? $objectIdList['bug'] : '');
$tasks = $this->task->getUserTaskPairs($account, 'wait,doing', '', isset($objectIdList['task']) ? $objectIdList['task'] : '');
$storys = $this->loadModel('story')->getUserStoryPairs($account, 10, 'story', '', isset($objectIdList['story']) ? $objectIdList['story'] : '');
$users = $this->loadModel('user')->getPairs('noclosed|nodeleted|noempty');
$testtasks = $this->loadModel('testtask')->getUserTestTaskPairs($account);
if($this->config->edition == 'biz' || $this->config->edition == 'max') $feedbacks = $this->loadModel('feedback')->getUserFeedbackPairs($account, '', isset($objectIdList['feedback']) ? $objectIdList['feedback'] : '');
if($this->config->edition == 'max')
{
$issues = $this->loadModel('issue')->getUserIssuePairs($account);
$risks = $this->loadmodel('risk')->getUserRiskPairs($account);
$opportunities = $this->loadmodel('opportunity')->getUserOpportunityPairs($account);
$reviews = $this->loadModel('review')->getUserReviewPairs($account);
}
$testtasks = $this->loadModel('testtask')->getUserTestTaskPairs($account);
/* Judge whether the edited todos is too large. */
$countInputVars = count($editedTodos) * $columns;
$showSuhosinInfo = common::judgeSuhosinSetting($countInputVars);
unset($this->lang->todo->typeList['cycle']);
/* Set Custom*/
foreach(explode(',', $this->config->todo->list->customBatchEditFields) as $field) $customFields[$field] = $this->lang->todo->$field;
$this->view->customFields = $customFields;
$this->view->showFields = $this->config->todo->custom->batchEditFields;
/* Assign. */
$title = $this->lang->todo->common . $this->lang->colon . $this->lang->todo->batchEdit;
$position[] = html::a($this->createLink('my', 'todo'), $this->lang->my->todo);
$position[] = $this->lang->todo->common;
$position[] = $this->lang->todo->batchEdit;
if($showSuhosinInfo) $this->view->suhosinInfo = extension_loaded('suhosin') ? sprintf($this->lang->suhosinInfo, $countInputVars) : sprintf($this->lang->maxVarsInfo, $countInputVars);
$this->view->bugs = $bugs;
$this->view->tasks = $tasks;
$this->view->storys = $storys;
$this->view->bugs = $bugs;
$this->view->tasks = $tasks;
$this->view->storys = $storys;
$this->view->reviews = $reviews;
$this->view->testtasks = $testtasks;
$this->view->editedTodos = $editedTodos;
$this->view->users = $users;
if($this->config->edition == 'biz' || $this->config->edition == 'max') $this->view->feedback = $feedbacks;
if($this->config->edition == 'max')
{
$this->view->issues = $issues;
$this->view->risks = $risks;
$this->view->opportunities = $opportunities;
}
$this->view->reviews = $reviews;
$this->view->testtasks = $testtasks;
$this->view->editedTodos = $editedTodos;
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
$this->view->time = date::now();
$this->view->title = $title;
$this->view->position = $position;
$this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted|noempty');
$this->buildBatchEditView();
return;
}
/**
* 获取批量编辑页面初始化待办数据。
* Get batch edit page initialization todo data.
*
* @param object $formData
* @param string $type
* @param string $account
* @param string $status
* @access protected
* @return array
*/
private function getBatchEditInitTodos(object $formData, string $type, string $account, string $status): array
{
$editedTodos = array();
$objectIdList = array();
$todoIdList = array();
$allTodos = $this->todo->getList($type, $account, $status);
if($formData->data->todoIDList) $todoIdList = $formData->data->todoIDList;
/* Initialize todos whose need to edited. */
foreach($allTodos as $todo)
{
if(in_array($todo->id, $todoIdList))
{
$editedTodos[$todo->id] = $todo;
if($todo->type != 'custom')
{
if(!isset($objectIdList[$todo->type])) $objectIdList[$todo->type] = array();
$objectIdList[$todo->type][$todo->objectID] = $todo->objectID;
}
}
}
return array($editedTodos, $objectIdList);
}
/**
* 生成批量创建待办视图数据。
* Build batch edit view.
*
* @access private
* @return void
*/
private function buildBatchEditView(): void
{
/* Set Custom*/
foreach(explode(',', $this->config->todo->list->customBatchEditFields) as $field) $customFields[$field] = $this->lang->todo->$field;
$this->view->customFields = $customFields;
$this->view->showFields = $this->config->todo->custom->batchEditFields;
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
$this->view->time = date::now();
$this->view->title = $this->lang->todo->common . $this->lang->colon . $this->lang->todo->batchEdit;
$this->display();
}
protected function batchEditFromTodoBatchEdit($formData)
/**
* 处理批量编辑待办数据。
* Build batch edit view.
*
* @param object $formData
* @access protected
* @return array
*/
protected function beforeBatchEdit(object $formData): array
{
$todos = array();
$data = $formData->rawdata;
$todoIdList = $formData->data->todoIDList ? $formData->data->todoIDList : array();
if(!empty($todoIdList))
{
/* Initialize todos from the post data. */
$oldTodos = $this->todo->getTodosByIdList($todoIdList);
foreach($todoIdList as $todoID)
{
$oldTodo = $oldTodos[$todoID];
$todo = new stdclass();
$todo->date = $data->dates[$todoID];
$todo->type = $data->types[$todoID];
$todo->pri = $data->pris[$todoID];
$todo->status = $data->status[$todoID];
$todo->name = !in_array($todo->type, $this->config->todo->moduleList) ? $data->names[$todoID] : '';
$todo->begin = isset($data->begins[$todoID]) ? $data->begins[$todoID] : 2400;
$todo->end = isset($data->ends[$todoID]) ? $data->ends[$todoID] : 2400;
$todo->assignedTo = isset($data->assignedTos[$todoID]) ? $data->assignedTos[$todoID] : $oldTodo->assignedTo;
if(in_array($todo->type, $this->config->todo->moduleList))
{
$todo->objectID = isset($data->{$this->config->todo->objectList[$todo->type]}[$todoID]) ? $data->{$this->config->todo->objectList[$todo->type]}[$todoID] : 0;
}
if($todo->end < $todo->begin) return print(js::alert(sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin)));
$todos[$todoID] = $todo;
}
}
return $todos;
}
/**
* 批量编辑完成待办后数据处理。
* After Batch edit todo data.
*
* @param array $allChanges
* @access protected
* @return void
*/
protected function afterBatchEdit(array $allChanges): void
{
$allChanges = $this->todo->batchUpdate();
foreach($allChanges as $todoID => $changes)
{
if(empty($changes)) continue;
@@ -261,8 +374,6 @@ class todoZen extends todo
$actionID = $this->loadModel('action')->create('todo', $todoID, 'edited');
$this->action->logHistory($actionID, $changes);
}
return print(js::locate($this->session->todoList, 'parent'));
}
/**
@@ -412,7 +523,7 @@ class todoZen extends todo
}
/**
* 处理指派待办请求数据.
* 处理指派待办请求数据。
* Process assign todo request data.
*
* @param object $formData
@@ -434,7 +545,7 @@ class todoZen extends todo
}
/**
* 指派待办.
* 指派待办。
* Assign a todo.
*
* @param object $todo
@@ -446,16 +557,47 @@ class todoZen extends todo
return $this->todo->assignTo($todo);
}
/**
* 获取导出待办的字段。
* 获取用户信息。
* Get user info.
*
* @param array $fields
* @param array $todoLang
* @param int $userID
* @access protected
* @return object|false
*/
protected function getUserById(int $userID): object|false
{
return $this->loadModel('user')->getById($userID, 'id');
}
/**
* 记录当前页面uri参数链接。
* Set uri to session.
*
* @param string $uri
* @access protected
* @return true
*/
protected function setSessionUri(string $uri): bool
{
foreach($this->config->todo->sessionUri as $key => $value) $this->session->set($key, $uri, $value);
return true;
}
/**
* 获取导出待办的字段和字段。
* Get fields and info for export todo.
*
* @param array $todos
* @param string $fields
* @param array $todoLang
* @access protected
* @return array
*/
protected function exportFields(array $fields, object $todoLang): array
protected function exportTodoInfo(array $todos, string $fields, object $todoLang): array
{
$fields = explode(',', $fields);
foreach($fields as $key => $fieldName)
{
$fieldName = trim($fieldName);
@@ -463,10 +605,21 @@ class todoZen extends todo
unset($fields[$key]);
}
unset($fields['objectID'], $fields['private']);
return $fields;
if($this->config->edition != 'open') list($fields, $todos) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $todos);
return array($todos, $fields);
}
public function exportInfo($type, $account)
/**
* 获取待办关联的信息。
* Get associated info for export todo.
*
* @param string $type
* @param string $account
* @access protected
* @return array
*/
protected function exportAssociated(string $type, string $account): array
{
if($type == 'max')
{
@@ -476,7 +629,7 @@ class todoZen extends todo
$this->loadModel('opportunity')->getUserOpportunityPairs($account),
);
}
else if($type == 'qcVersion')
elseif($type == 'qcVersion')
{
return $this->loadModel('review')->getUserReviewPairs($account, 0, 'wait');
}
@@ -491,4 +644,50 @@ class todoZen extends todo
);
}
}
/**
* 处理导出数据。
* Deal with export data.
*
* @param array $todos
* @param object $assemble
* @param object $todoLang
* @param array $times
* @access protected
* @return array
*/
protected function assembleExportData(array $todos, object $assemble, object $todoLang, array $times): array
{
foreach($todos as $todo)
{
/* fill some field with useful value. */
$todo->begin = $todo->begin == '2400' ? '' : (isset($times[$todo->begin]) ? $times[$todo->begin] : $todo->begin);
$todo->end = $todo->end == '2400' ? '' : (isset($times[$todo->end]) ? $times[$todo->end] : $todo->end);
$type = $todo->type;
if(isset($assemble->users[$todo->account])) $todo->account = $assemble->users[$todo->account];
if($type == 'bug') $todo->name = isset($assemble->bugs[$todo->objectID]) ? $assemble->bugs[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'task') $todo->name = isset($assemble->tasks[$todo->objectID]) ? $assemble->tasks[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'story') $todo->name = isset($assemble->stories[$todo->objectID]) ? $assemble->stories[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'testtask') $todo->name = isset($assemble->testTasks[$todo->objectID]) ? $assemble->testTasks[$todo->objectID] . "(#$todo->objectID)" : '';
if($this->config->edition == 'max')
{
if($type == 'issue') $todo->name = isset($assemble->issues[$todo->objectID]) ? $assemble->issues[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'risk') $todo->name = isset($assemble->risks[$todo->objectID]) ? $assemble->risks[$todo->objectID] . "(#$todo->objectID)" : '';
if($type == 'opportunity') $todo->name = isset($assemble->opportunities[$todo->objectID]) ? $assemble->opportunities[$todo->objectID] . "(#$todo->objectID)" : '';
}
if($type == 'review' && isset($this->config->qcVersion)) $todo->name = isset($assemble->reviews[$todo->objectID]) ? $assemble->reviews[$todo->objectID] . "(#$todo->objectID)" : '';
if(isset($todoLang->typeList[$type])) $todo->type = $todoLang->typeList[$type];
if(isset($todoLang->priList[$todo->pri])) $todo->pri = $todoLang->priList[$todo->pri];
if(isset($todoLang->statusList[$todo->status])) $todo->status = $todoLang->statusList[$todo->status];
if($todo->private == 1) $todo->desc = $this->lang->todo->thisIsPrivate;
/* drop some field that is not needed. */
unset($todo->objectID, $todo->private);
}
return $todos;
}
}
+17 -16
View File
@@ -1,6 +1,7 @@
title: zt_bug
desc: Bug表
version: 1.0
desc: "Bug表"
author: automated export
version: "1.0"
fields:
- field: id
range: 1-10000
@@ -33,29 +34,29 @@ fields:
- field: title2
range: 1-10000
- field: keywords
range: []
range: "[]"
- field: severity
range: 1-4
- field: pri
range: 1-4
- field: type
range: [codeerror,config,install,security,performance,standard,automation,designdefect,others]
range: "[codeerror,config,install,security,performance,standard,automation,designdefect,others]"
- field: os
range: []{2},[win10,windows,android,ios]
range: "[]{2},[win10,windows,android,ios]"
- field: browser
range: []
range: "[]"
- field: hardware
range: []
range: "[]"
- field: found
range: []
range: "[]"
- field: steps
range: [<p>【步骤】</p><br/><p>【结果】</p><br/><p>【期望】</p><br/>,【步骤】进入成果展示<br/>【结果】乱码<br/>【期望】正常显示<br/>]
range: "[<p>【步骤】</p><br/><p>【结果】</p><br/><p>【期望】</p><br/>,【步骤】进入成果展示<br/>【结果】乱码<br/>【期望】正常显示<br/>]"
- field: status
range: active{50},resolved{30},closed{20}
- field: subStatus
range: []
range: "[]"
- field: color
range: [#3da7f5,#75c941,#2dbdb2,#797ec9,#ffaf38,#ff4e3e]
range: "[#3da7f5,#75c941,#2dbdb2,#797ec9,#ffaf38,#ff4e3e]"
- field: confirmed
range: 0,1
- field: activatedCount
@@ -71,7 +72,7 @@ fields:
- field: openedBuild
range: 1,0,1,trunk{97}
- field: assignedTo
range: [admin,dev1,test1]{30},[]{20},[admin,dev1,test1]{20},[]{10},closed{20}
range: "[admin,dev1,test1]{30},[]{20},[admin,dev1,test1]{20},[]{10},closed{20}"
- field: assignedDate
range: "(-1M)-(+1w):-1D"
type: timestamp
@@ -84,11 +85,11 @@ fields:
loop: 0
format: "YYYY-MM-DD"
- field: resolvedBy
range: []{50},$assignedTo{30},admin{20}
range: "[]{50},$assignedTo{30},admin{20}"
- field: resolution
range: []{50},bydesign{5},duplicate{5},external{5},fixed{5},notrepro{2},postponed{3},willnotfix{5},fixed{10},bydesign,external,notrepro,postponed,willnotfix,duplicate{5}
range: "[]{50},bydesign{5},duplicate{5},external{5},fixed{5},notrepro{2},postponed{3},willnotfix{5},fixed{10},bydesign,external,notrepro,postponed,willnotfix,duplicate{5}"
- field: resolvedBuild
range: []{55},trunk{15},[]{25},trunk{5}
range: "[]{55},trunk{15},[]{25},trunk{5}"
- field: resolvedDate
range: "(+1w)-(-2w):-1D"
type: timestamp
@@ -97,7 +98,7 @@ fields:
loop: 0
format: "YYYY-MM-DD"
- field: closedBy
range: []{50},admin{30}
range: "[]{50},admin{30}"
- field: closedDate
range:
- field: duplicateBug
+5 -4
View File
@@ -65,8 +65,11 @@ fields:
range: ""
- field: scriptedDate
note: "脚本创建日期"
from: common.date.v1.yaml
use: dateB
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
postfix: ""
format: "YY/MM/DD"
- field: scriptStatus
note: "脚本状态"
range: ""
@@ -81,8 +84,6 @@ fields:
range: ""
- field: color
note: "标题颜色"
from: common.color.v1.yaml
use: color
- field: frequency
note: "使用频率"
range: 1-3
+5 -10
View File
@@ -59,40 +59,35 @@ fields:
format: "YYYY-MM-DD hh:mm:ss"
- field: editedBy
note: "由谁编辑"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: editedDate
note: "编辑者"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: assignedTo
note: "指派给"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: assignedBy
note: "由谁指派"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: assignedDate
note: "指派日期"
from: common.date.v1.yaml
use: dateA
range: ""
prefix: ""
postfix: ""
loop: 0
+3 -4
View File
@@ -147,12 +147,11 @@ fields:
format: ""
- field: editedDate
note: "编辑日期"
from: common.date.v1.yaml
use: dateA
range: Y-m-d
prefix: ""
type: timestamp
postfix: ""
loop: 0
format: ""
format: "YYYY-MM-DD"
- field: acl
note: "权限"
range: open,custom,private
+2 -8
View File
@@ -83,20 +83,14 @@ fields:
format: ""
- field: editedBy
note: "编辑者"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: editedDate
note: "编辑日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
- field: deleted
note: "是否删除"
range: 0
+7 -12
View File
@@ -12,16 +12,12 @@ fields:
format: ""
- field: pathname
note: "路径名称"
from: common.file.v1.yaml
use: pathname
loop: 0
format: ""
range: ""
- field: title
note: "文件标题"
from: common.file.v1.yaml
use: title
range: 1-1000000
prefix: "文件标题"
postfix: ""
loop: 0
format: ""
- field: extension
note: "文件后缀"
@@ -60,12 +56,11 @@ fields:
format: ""
- field: addedDate
note: "添加时间"
from: common.date.v1.yaml
use: dateA
prefix: ""
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
postfix: ""
loop: 0
format: ""
format: "YY/MM/DD"
- field: downloads
note: "下载次数"
range: "0-100"
+8 -13
View File
@@ -105,40 +105,35 @@ fields:
format: ""
- field: createdBy
note: "创建者"
from: common.user.v1.yaml
use: user
range: admin
prefix: ""
postfix: ""
loop: 0
format: ""
- field: createdDate
note: "创建日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
postfix: ""
loop: 0
format: ""
format: "YY/MM/DD"
- field: editedBy
note: "编辑者"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: editedDate
note: "编辑日期"
from: common.date.v1.yaml
use: dateA
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: lastExec
note: "最后执行时间"
from: common.date.v1.yaml
use: dateA
range: ""
prefix: ""
postfix: ""
loop: 0
+16 -37
View File
@@ -114,31 +114,28 @@ fields:
format: ""
- field: color
note: "标题颜色"
from: common.color.v1.yaml
use: color
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: stage
note: "所处阶段"
range: [],wait,[],planned,[],projected,[],developing,[],developed,[],testing,[],tested,[],verified,[],released,[],closed
range: "[],wait,[],planned,[],projected,[],developing,[],developed,[],testing,[],tested,[],verified,[],released,[],closed"
prefix: ""
postfix: ""
loop: 0
format: ""
- field: stagedBy
note: "设置阶段者"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: mailto
note: "抄送给"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
@@ -156,12 +153,11 @@ fields:
format: ""
- field: openedDate
note: "创建日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
postfix: ""
loop: 0
format: ""
format: "YY/MM/DD"
- field: assignedTo
note: "指派给"
fields:
@@ -175,28 +171,21 @@ fields:
format: ""
- field: assignedDate
note: "指派日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
postfix: ""
loop: 0
format: ""
format: "YY/MM/DD"
- field: lastEditedBy
note: "最后修改者"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: lastEditedDate
note: "最后修改日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
- field: reviewedBy
note: "评审者"
fields:
@@ -209,12 +198,7 @@ fields:
format: ""
- field: reviewedDate
note: "评审日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
- field: closedBy
note: "关闭者"
fields:
@@ -228,12 +212,7 @@ fields:
format: ""
- field: closedDate
note: "关闭日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
- field: closedReason
note: "关闭原因"
range: done,subdivided,duplicate,postponed,willnotdo,cancel,bydesign
+24 -83
View File
@@ -120,7 +120,6 @@ fields:
range: "(+1w)-(-1M):-1D"
prefix: ""
postfix: ""
loop: 0
type: timestamp
format: "YY/MM/DD"
- field: status
@@ -139,20 +138,14 @@ fields:
format: ""
- field: color
note: "标题颜色"
from: common.color.v1.yaml
use: color
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: mailto
note: "抄送给"
from: common.user.v1.yaml
use: user
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
- field: desc
note: "任务描述"
range: 1-10000
@@ -169,20 +162,17 @@ fields:
format: ""
- field: openedBy
note: "由谁创建"
from: common.user.v1.yaml
use: user
range: admin
prefix: ""
postfix: ""
loop: 0
format: ""
- field: openedDate
note: "创建日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: ""
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
format: "YY/MM/DD"
- field: assignedTo
note: "指派给"
range: ""
@@ -192,12 +182,10 @@ fields:
format: ""
- field: assignedDate
note: "指派日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: ""
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
format: "YY/MM/DD"
- field: estStarted
note: "预计开始"
range: "2022-01-27"
@@ -208,72 +196,39 @@ fields:
format: "YY/MM/DD"
- field: realStarted
note: "实际开始"
from: common.date.v1.yaml
use: dateB
prefix: ""
postfix: ""
loop: 0
format: "YY/MM/DD"
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
format: "YY/MM/DD"
- field: finishedBy
note: "由谁完成"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: finishedDate
note: "完成日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: "YY/MM/DD"
type: timestamp
range: ""
- field: finishedList
note: "完成者列表"
from: common.user.v1.yaml
use: user
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
- field: canceledBy
note: "由谁取消"
from: common.user.v1.yaml
use: user
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
- field: canceledDate
note: "取消日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: "YY/MM/DD"
type: timestamp
range: ""
- field: closedBy
note: "由谁关闭"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: closedDate
note: "关闭日期"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: "YY/MM/DD"
type: timestamp
range: ""
- field: realDuration
note: "实际持续时长"
range: 1
@@ -297,30 +252,16 @@ fields:
format: ""
- field: lastEditedBy
note: "最后修改者"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: lastEditedDate
note: "最后修改时间"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: "YY/MM/DD"
type: timestamp
range: ""
- field: activatedDate
note: "重新激活日期"
from: common.date.v1.yaml
use: dateB
prefix: ""
postfix: ""
loop: 0
format: "YY/MM/DD"
type: timestamp
range: ""
- field: deleted
note: "是否删除"
range: 0
+2 -4
View File
@@ -30,16 +30,14 @@ fields:
format: ""
- field: estStarted
note: "预计开始"
from: common.date.v1.yaml
use: dateB
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: deadline
note: "截止时间"
from: common.date.v1.yaml
use: dateB
range: ""
prefix: ""
postfix: ""
loop: 0
+7 -15
View File
@@ -16,7 +16,7 @@ fields:
- field: account1
range: admin,user{99},test{100},dev{100},pm{100},po{100},td{100},pd{100},qd{100},top{100},outside{100}
- field: account2
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100
range: "[],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100"
prefix: ""
postfix: ""
loop: 0
@@ -108,7 +108,7 @@ fields:
- field: ass1
range: admin,user{99},test{100},dev{100},pm{100},po{100},td{100},pd{100},qd{100},top{100},outside{100}
- field: ass2
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100
range: "[],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100"
prefix: ""
postfix: ""
format: ""
@@ -118,7 +118,7 @@ fields:
- field: ass1
range: admin,user{99},test{100},dev{100},pm{100},po{100},td{100},pd{100},qd{100},top{100},outside{100}
- field: ass2
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100
range: "[],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100"
prefix: ""
postfix: ""
format: ""
@@ -131,33 +131,25 @@ fields:
format: "YY-MM-DD hh:mm:ss"
- field: finishedBy
note: "由谁完成"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: finishedDate
note: "完成时间"
from: common.date.v1.yaml
use: dateA
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: closedBy
note: "由谁关闭"
from: common.user.v1.yaml
use: user
range: ""
prefix: ""
postfix: ""
loop: 0
format: ""
- field: closedDate
note: "关闭时间"
from: common.date.v1.yaml
use: dateA
prefix: ""
postfix: ""
loop: 0
format: ""
range: ""
+7 -8
View File
@@ -44,7 +44,7 @@ fields:
- field: realname1
range: admin,用户{99},测试{100},开发{100},项目经理{100},产品经理{100},研发主管{100},产品主管{100},测试主管{100},高层管理{100},外用户{100},其他{100},A,BB,CCC,非常长非常长的用户名怎么这么长?
- field: realname2
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}
range: "[],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}"
- field: nickname
note: "昵称"
- field: commiter
@@ -56,7 +56,7 @@ fields:
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}
- field: avatar
note: ""
range: []
range: ""
format: ""
- field: birthday
note: "生日"
@@ -123,12 +123,11 @@ fields:
note: "邮编"
- field: join
note: "入职日期"
from: common.date.v1.yaml
use: dateB
prefix: ""
range: "(M)-(w)"
type: timestamp
prefix: "DateTime"
postfix: ""
loop: 0
format: ""
format: "YY/MM/DD"
- field: visits
note: "访问次数"
range: 0-10000:R
@@ -165,7 +164,7 @@ fields:
- field: account1
range: admin,user{99},test{100},dev{100},pm{100},po{100},td{100},pd{100},qd{100},top{100},outside{100},others{100},a,bb,ccc,qwuiadsd?!2as@#%$aasd~aj1!@#1
- field: account2
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}
range: "[],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}"
- field: score
note: "积分"
range: 1-10000:R
+2 -3
View File
@@ -102,9 +102,6 @@ function p($keys = '', $delimiter = ',')
{
global $_result;
$_keys = $keys;
$_delimiter = $delimiter;
if(empty($_result)) return print(implode("\n", array_fill(0, substr_count($keys, $delimiter) + 1, 0)) . "\n");
if(is_array($_result) and isset($_result['code']) and $_result['code'] == 'fail') return print((string) $_result['message'] . "\n");
@@ -117,6 +114,8 @@ function p($keys = '', $delimiter = ',')
foreach($parts as $part)
{
$values = getValues($_result, $part, $delimiter);
if(!is_array($values)) continue;
foreach($values as $value) echo $value . "\n";
}
+33 -30
View File
@@ -341,21 +341,6 @@ class yaml
$this->insertDB($yamlFile, $this->tableName, $rows, $isClear);
}
/**
* 打印zendata生成的sql和导入数据库产生的错误.
* Print sql and error.
*
* @param int $rows
* @param bool $isClear Truncate table if set isClear to true.
* @param bool $debug Print sql and error if set isClear to true.
* @access public
* @return void
*/
public function debug($rows, $isClear = true)
{
$yamlFile = $this->mergeYaml();
$this->insertDB($yamlFile, $this->tableName, $rows, $isClear, true);
}
/**
* Insert the data into database.
*
@@ -363,11 +348,10 @@ class yaml
* @param string $tableName
* @param int $rows
* @param bool $isClear Truncate table if set isClear to true.
* @param bool $debug
* @access public
* @return string
*/
function insertDB($yamlFile, $tableName, $rows, $isClear = true, $debug = false)
function insertDB($yamlFile, $tableName, $rows, $isClear = true)
{
$tableSqlDir = "{$_SERVER['PWD']}/data/sql";
@@ -385,32 +369,51 @@ class yaml
$dbUser = $this->config->db->user;
$dbPWD = $this->config->db->password;
$command = "$zdPath -c %s -d %s -n %d -t %s -dns mysql://%s:%s@%s:%s/%s#utf8";
$command = "mysql -u%s -p%s -h%s -P%s -D%s < %s";
$genSQL = "$zdPath -c %s -d %s -n %d -t %s -o %s";
if($isClear === true)
{
/* Truncate table to reset auto increment number. */
system(sprintf("mysql -u%s -p%s -h%s -P%s %s -e 'truncate %s' 2>/dev/null", $dbUser, $dbPWD, $dbHost, $dbPort, $dbName, $tableName));
$command .= ' --clear';
}
$sqlPath = "{$tableSqlDir}/{$tableName}_zd.sql";
$execYaml = sprintf($command, $configYaml, $yamlFile, $rows, $tableName, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName);
$execYaml = sprintf($command, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName, $sqlPath);
$execDump = sprintf($dumpCommand, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName, $tableName);
$execGenSQL = sprintf($genSQL, $configYaml, $yamlFile, $rows, $tableName, $sqlPath);
system($execGenSQL);
if($debug)
{
echo "\n" . file_get_contents($sqlPath) . "\n";
$tmpl = "mysql -u%s -p%s -h%s -P%s -D%s < %s";
system(sprintf($tmpl, $dbUser, $dbPWD, $dbHost, $dbPort, $dbName, $sqlPath));
return;
}
system($execDump);
system($execYaml);
$stderr = '';
$this->exec_with_stderr($execYaml, $stderr);
if(empty($stderr)) return;
$errors = explode(PHP_EOL, $stderr);
$errors = array_filter($errors, function($error)
{
return !empty($error) && !strpos($error, 'Using a password on the command line interface can be insecure');
});
if(!empty($errors)) echo implode(PHP_EOL, $errors) . PHP_EOL;
}
/**
* 执行系统命令,并捕捉stderror
* exec command and catch stderror.
*
* @param string $cmd
* @param string $stderr
* @access private
* @return string
*/
private function exec_with_stderr($cmd, &$stderr=null)
{
$proc = proc_open($cmd, array(2 => array('pipe', 'w')), $pipes);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
proc_close($proc);
}
/**
+922 -61
View File
@@ -1,4 +1,5 @@
<?php
/**
* The functions of zin of ZenTaoPMS.
*
@@ -17,65 +18,925 @@ require_once __DIR__ . DS . 'zui' . DS . 'zui.func.php';
require_once __DIR__ . DS . 'zentao' . DS . 'zentao.func.php';
/* Form */
function input() {return createWg('input', func_get_args());}
function textarea() {return createWg('textarea', func_get_args());}
function radio() {return createWg('radio', func_get_args());}
function switcher() {return createWg('switcher', func_get_args());}
function checkbox() {return createWg('checkbox', func_get_args());}
function form() {return createWg('form', func_get_args());}
function formPanel() {return createWg('formPanel', func_get_args());}
function control() {return createWg('control', func_get_args());}
function select() {return createWg('select', func_get_args());}
function formLabel() {return createWg('formLabel', func_get_args());}
function formGroup() {return createWg('formGroup', func_get_args());}
function formRow() {return createWg('formRow', func_get_args());}
function inputControl() {return createWg('inputControl', func_get_args());}
function inputGroup() {return createWg('inputGroup', func_get_args());}
function checkList() {return createWg('checkList', func_get_args());}
function radioList() {return createWg('radioList', func_get_args());}
function colorPicker() {return createWg('colorPicker', func_get_args());}
function datePicker() {return createWg('datePicker', func_get_args());}
function datetimePicker() {return createWg('datetimePicker', func_get_args());}
function timePicker() {return createWg('timePicker', func_get_args());}
function fileInput() {return createWg('fileInput', func_get_args());}
function pageForm() {return createWg('pageForm', func_get_args());}
function icon() {return createWg('icon', func_get_args());}
function btn() {return createWg('btn', func_get_args());}
function pageBase() {return createWg('pageBase', func_get_args());}
function page() {return createWg('page', func_get_args());}
function fragment() {return createWg('fragment', func_get_args());}
function btnGroup() {return createWg('btnGroup', func_get_args());}
function mainMenu() {return createWg('mainMenu', func_get_args());}
function row() {return createWg('row', func_get_args());}
function col() {return createWg('col', func_get_args());}
function column() {return createWg('column', func_get_args());}
function center() {return createWg('center', func_get_args());}
function cell() {return createWg('cell', func_get_args());}
function actionItem() {return createWg('actionItem', func_get_args());}
function nav() {return createWg('nav', func_get_args());}
function label() {return createWg('label', func_get_args());}
function dtable() {return createWg('dtable', func_get_args());}
function menu() {return createWg('menu', func_get_args());}
function dropdown() {return createWg('dropdown', func_get_args());}
function header() {return createWg('header', func_get_args());}
function heading() {return createWg('heading', func_get_args());}
function navbar() {return createWg('navbar', func_get_args());}
function main() {return createWg('main', func_get_args());}
function sidebar() {return createWg('sidebar', func_get_args());}
function featureBar() {return createWg('featureBar', func_get_args());}
function avatar() {return createWg('avatar', func_get_args());}
function userAvatar() {return createWg('userAvatar', func_get_args());}
function pager() {return createWg('pager', func_get_args());}
function modal() {return createWg('modal', func_get_args());}
function modalTrigger(){return createWg('modalTrigger', func_get_args());}
function modalDialog() {return createWg('modalDialog', func_get_args());}
function tabs() {return createWg('tabs', func_get_args());}
function panel() {return createWg('panel', func_get_args());}
function tooltip() {return createWg('tooltip', func_get_args());}
function toolbar() {return createWg('toolbar', func_get_args());}
function searchForm() {return createWg('searchForm', func_get_args());}
function searchToggle(){return createWg('searchToggle', func_get_args());}
function programMenu() {return createWg('programMenu', func_get_args());}
function moduleMenu() {return createWg('moduleMenu', func_get_args());}
function history() {return createWg('history', func_get_args());}
/**
* html input.
*
* string type='text'
* string name
* string id?
* string class='form-control'
* string value?
* bool required?
* string placeholder?
* bool autofocus?
* bool autocomplete=false
* bool disabled
*/
function input()
{
return createWg('input', func_get_args());
}
/**
* html textarea.
*
* string name
* string id?
* string class='form-control'
* string value?
* bool required?
* string placeholder?
* int rows
* int cols
*/
function textarea()
{
return createWg('textarea', func_get_args());
}
/**
* radio widget.
*
* string text?
* bool checked?
* string name?
* bool primary=true
* string id
* bool disabled?
* string value?
* string typeClass?
* string rootClass?
*/
function radio()
{
return createWg('radio', func_get_args());
}
/**
* switcher widget.
*
* string text?
* bool checked?
* string name?
* bool primary=true
* string id
* bool disabled?
* string value
* string typeClass?
* string rootClass?
*/
function switcher()
{
return createWg('switcher', func_get_args());
}
/**
* checkbox widget.
*
* string text?
* bool checked?
* string name?
* bool primary=true
* string id
* bool disabled?
* string value?
* string typeClass?
* string rootClass?
*/
function checkbox()
{
return createWg('checkbox', func_get_args());
}
/**
* form widget.
*
* string method='post'
* string url?
* array actions?
* string target?
* array items?
* bool grid?
* int labelWidth?
* string submitBtnText?
* string cancelBtnText?
*/
function form()
{
return createWg('form', func_get_args());
}
/**
* form panel widget.
*
* string method?
* string url?
* array actions?
* string target?
* array items?
* bool grid?
* int labelWidth?
*/
function formPanel()
{
return createWg('formPanel', func_get_args());
}
/**
* control widget.
* Dynamically create html input.
*
* string type - it can be text, password, email, number, date, time, datetime, month, url, search, tel, color, picker, select, checkbox, radio, checkboxList, radioList, checkboxListInline, radioListInline, file, textarea
* string name
* string id?
* string value?
* bool required?
* string placeholder?
* bool disabled?
* string form?
* array items?
*/
function control()
{
return createWg('control', func_get_args());
}
/**
* html select.
*
* string name
* string id?
* string class="form-control"
* string value?
* bool required?
* bool disabled?
* bool multiple?
* array items?
* int size?
*/
function select()
{
return createWg('select', func_get_args());
}
/**
* html label which use id form.
*
* string text?
* bool required?
* string for?
*/
function formLabel()
{
return createWg('formLabel', func_get_args());
}
/**
* form group widget.
*
* string|array
* string name?
* string|bool label?
* string labelClass?
* bool|string required='auto'
* string tip?
* string|array tipClass?
* array tipProps?
* array|string control?
* string width?
* bool strong?
* string|array value?
* bool disabled?
* array items?
* string placeholder?
*/
function formGroup()
{
return createWg('formGroup', func_get_args());
}
/**
* form row widget.
*
* string width?
* array items?
* bool hidden?
*/
function formRow()
{
return createWg('formRow', func_get_args());
}
/**
* html input with prefix or suffix.
*
* mixed prefix
* mixed suffix
* string|int prefixWidth
* string|int suffixWidth
*/
function inputControl()
{
return createWg('inputControl', func_get_args());
}
/**
* input group widget.
*
* array items?
* bool seg?
*/
function inputGroup()
{
return createWg('inputGroup', func_get_args());
}
/**
* checkbox list widget.
*
* bool primary=true
* string name?
* string|array value?
* array items
* bool inline?
*/
function checkList()
{
return createWg('checkList', func_get_args());
}
/**
* radio list widget.
*
* bool primary=true
* string name?
* string|array value?
* array items
* bool inline?
*/
function radioList()
{
return createWg('radioList', func_get_args());
}
/**
* color picker widget which extends input.
*
* string name
* string id?
* string class?
* string value?
* bool required?
* string placeholder?
* bool autofocus?
* bool autocomplete=false
* bool disabled?
*/
function colorPicker()
{
return createWg('colorPicker', func_get_args());
}
/**
* date picker widget which extends input.
*
* string name
* string id?
* string class?
* string value?
* bool required?
* string placeholder?
* bool autofocus?
* bool autocomplete=false
* bool disabled?
*/
function datePicker()
{
return createWg('datePicker', func_get_args());
}
/**
* datetime picker widget which extends input.
*
* string name
* string id?
* string class?
* string value?
* bool required?
* string placeholder?
* bool autofocus?
* bool autocomplete=false
* bool disabled?
*/
function datetimePicker()
{
return createWg('datetimePicker', func_get_args());
}
/**
* time picker widget which extends input.
*
* string name
* string id?
* string class?
* string value?
* bool required?
* string placeholder?
* bool autofocus?
* bool autocomplete=false
* bool disabled?
*/
function timePicker()
{
return createWg('timePicker', func_get_args());
}
/**
* html file input which extends input.
*
* string name
* string id?
* string class?
* string value?
* bool required?
* string placeholder?
* bool autofocus?
* bool autocomplete=false
* bool disabled?
*/
function fileInput()
{
return createWg('fileInput', func_get_args());
}
/**
* page form widget which extends page.
*
* array formPanel?
* string|array metas=array('<meta charset="utf-8">', '<meta http-equiv="X-UA-Compatible" content="IE=edge">', '<meta name="viewport" content="width=device-width, initial-scale=1">', '<meta name="renderer" content="webkit">')
* string title?
* array bodyProps?
* array|string bodyClass?
* bool zui=true
* bool display=true
*
* ====== blocks ======
* head = array()
* header = array('map' => 'header')
* main = array('map' => 'main')
* footer = array()
* ====================
*/
function pageForm()
{
return createWg('pageForm', func_get_args());
}
/**
* icon widget.
*
* string name
* string|int size?
*/
function icon()
{
return createWg('icon', func_get_args());
}
/**
* button widget.
*
* string icon?
* string text?
* bool square?
* bool disabled?
* bool active?
* string url?
* string target?
* string|int size?
* string trailingIcon?
* string|bool caret?
* string hint?
* string type?
* string btnType?
*/
function btn()
{
return createWg('btn', func_get_args());
}
/**
* page base widget.
*
* string|array metas=array('<meta charset="utf-8">', '<meta http-equiv="X-UA-Compatible" content="IE=edge">', '<meta name="viewport" content="width=device-width, initial-scale=1">', '<meta name="renderer" content="webkit">')
* string title?
* array bodyProps?
* array|string bodyClass?
* bool zui=false
* bool display=true
*/
function pageBase()
{
return createWg('pageBase', func_get_args());
}
/**
* page widget.
*
* string|array metas=array('<meta charset="utf-8">', '<meta http-equiv="X-UA-Compatible" content="IE=edge">', '<meta name="viewport" content="width=device-width, initial-scale=1">', '<meta name="renderer" content="webkit">')
* string title?
* array bodyProps?
* array|string bodyClass?
* bool zui=true
* bool display=true
*
* ====== blocks ======
* head = array()
* header = array('map' => 'header')
* main = array('map' => 'main')
* footer = array()
* ====================
*/
function page()
{
return createWg('page', func_get_args());
}
/**
* fragment widget.
* lets you group elements without a wrapper node.
*/
function fragment()
{
return createWg('fragment', func_get_args());
}
/**
* button group widget.
*
* array items?
* bool disabled?
* string size?
*/
function btnGroup()
{
return createWg('btnGroup', func_get_args());
}
/**
* zentao main menu widget.
*
* array statuses?
* array btnGroup?
* array others?
*/
function mainMenu()
{
return createWg('mainMenu', func_get_args());
}
/**
* row widget.
*
* string justify?
* string align?
*/
function row()
{
return createWg('row', func_get_args());
}
/**
* col widget.
*
* string justify?
* string align?
*/
function col()
{
return createWg('col', func_get_args());
}
function column()
{
return createWg('column', func_get_args());
}
/**
* center widget.
*/
function center()
{
return createWg('center', func_get_args());
}
/**
* cell widget.
* flex item.
*
* int order
* int grow
* string shrink
* string|int width 'auto'|'flex-start'|'flex-end'|'center'|'baseline'|'stretch'
* string align
* string flex
*/
function cell()
{
return createWg('cell', func_get_args());
}
/**
* action item widget.
*
* string name='action'
* string type='item'
* string outerTag='li'
* string tagName='a'
* string icon?
* string text?
* string url?
* string target?
* bool active?
* bool disabled?
* string trailingIcon?
* array outerProps?
* string outerClass?
* props array?
* string|array|object badge?
*/
function actionItem()
{
return createWg('actionItem', func_get_args());
}
/**
* nav widget.
*
* array items?
*/
function nav()
{
return createWg('nav', func_get_args());
}
/**
* label widget.
*
* string text?
*/
function label()
{
return createWg('label', func_get_args());
}
/**
* dtable widget.
*/
function dtable()
{
return createWg('dtable', func_get_args());
}
/**
* menu widget.
*
* array items?
*/
function menu()
{
return createWg('menu', func_get_args());
}
/**
* dropdown widget.
*
* array items?
* string placement?
* string strategy?
* int offset?
* bool flip?
* string subMenuTrigger?
* string arrow?
* string trigger?
* array menuProps?
* string target?
* string id?
* string menuClass?
* bool hasIcons?
* bool staticMenu?
*/
function dropdown()
{
return createWg('dropdown', func_get_args());
}
/**
* header widget.
*
* ====== blocks ======
* heading = array('map' => 'toolbar')
* navbar = array('map' => 'nav')
* toolbar = array('map' => 'btn')
* ====================
*/
function header()
{
return createWg('header', func_get_args());
}
/**
* heading widget.
*
* array items
* bool showAppName=true
*/
function heading()
{
return createWg('heading', func_get_args());
}
/**
* navbar widget.
*
* array items?
*/
function navbar()
{
return createWg('navbar', func_get_args());
}
/**
* main widget.
*
* ====== blocks ======
* menu = array('map' => 'featureBar,nav,toolbar')
* sidebar = array('map' => 'sidebar')
* ====================
*/
function main()
{
return createWg('main', func_get_args());
}
/**
* zentao sidebar widget.
*
* string side='left'
* bool showToggle=true
*/
function sidebar()
{
return createWg('sidebar', func_get_args());
}
/**
* zentao feature bar widget.
*
* array items?
* string current?
* string link?
* string linkParams?
*
* ====== blocks ======
* nav = array('map' => 'nav')
* leading = array()
* trailing = array()
* ====================
*/
function featureBar()
{
return createWg('featureBar', func_get_args());
}
/**
* avatar widget.
*
* string className?
* array style?
* int size=32
* bool circle=true
* string|int rounded?
* string background?
* string foreColor
* string text?
* string code?
* int maxTextLength=2
* int hueDistance=43
* int saturation=0.4
* int lightness=0.6
* string src?
*/
function avatar()
{
return createWg('avatar', func_get_args());
}
/**
* zentao user avatar widget.
*
* string className?
* array style?
* int size=32
* bool circle=true
* string|int rounded
* string background
* string foreColor
* string text
* string code?
* int maxTextLength=2
* int hueDistance=43
* int saturation=0.4
* int lightness=0.6
* string src?
* string avatar?
* string account?
* string realname?
* array|object user?
*/
function userAvatar()
{
return createWg('userAvatar', func_get_args());
}
/**
* pager widget.
*/
function pager()
{
return createWg('pager', func_get_args());
}
/**
* modal widget.
*
* string id="$GID"
* array modalProps=array()
*/
function modal()
{
return createWg('modal', func_get_args());
}
/**
* modal trigger widget.
*
* string target?
* string|int|object|function position?
* string|int|object size?
* bool|string backdrop?
* bool keyboard?
* bool moveable?
* bool animation?
* int transTime?
* bool responsive?
* string type?
* string loadingText?
* int loadTimeout?
* string failedTip?
* string timeoutTip?
* string title?
* string content?
* object custom?
* string url?
* object request?
* string dataType?
*
* ====== blocks ======
* trigger = array('map' => 'btn,a')
* modal = array('map' => 'modal')
* ====================
*/
function modalTrigger()
{
return createWg('modalTrigger', func_get_args());
}
/**
* modal dialog widget.
*
* string title?
* int itemID?
* string headerClass?
* array headerProps?
* array actions?
* bool|array closeBtn=true
* array footerActions
* string footerClass
* array footerProps
*/
function modalDialog()
{
return createWg('modalDialog', func_get_args());
}
/**
* tabs widget.
*
* string direction='h'
* array items
* string activeId?
*/
function tabs()
{
return createWg('tabs', func_get_args());
}
/**
* panel widget.
*
* string class='rounded shadow ring-0 canvas'
* string size?
* string title?
* string titleClass?
* array titleProps?
* string headingClass?
* array headingProps?
* array headingActions?
* string bodyClass?
* array bodyProps?
* array footerActions?
* string footerClass?
* array footerProps?
*/
function panel()
{
return createWg('panel', func_get_args());
}
/**
* tooltip widget.
*/
function tooltip()
{
return createWg('tooltip', func_get_args());
}
/**
* toolbar widget.
*
* array items?
* string btnClass?
* array btnProps?
*/
function toolbar()
{
return createWg('toolbar', func_get_args());
}
/**
* zentao search form widget.
*/
function searchForm()
{
return createWg('searchForm', func_get_args());
}
/**
* zentao search toggle widget.
*
* bool open?
*/
function searchToggle()
{
return createWg('searchToggle', func_get_args());
}
/**
* zentao program menu widget.
*
* array programs?
* string activeClass?
* string activeIcon?
* string activeKey?
* string closeLink?
*/
function programMenu()
{
return createWg('programMenu', func_get_args());
}
/**
* zentao module menu widget.
*
* int productID
* int activeKey
* string closeLink
*/
function moduleMenu()
{
return createWg('moduleMenu', func_get_args());
}
/**
* zentao history records widget.
*
* array actions?
* array users?
* string methodName?
*/
function history()
{
return createWg('history', func_get_args());
}
+1 -2
View File
@@ -8,8 +8,7 @@ require_once dirname(__DIR__) . DS . 'btngroup' . DS . 'v1.php';
class actionItem extends wg
{
static $defineProps = array
(
static $defineProps = array(
'name:string="action"',
'type:string="item"',
'outerTag:string="li"',
+9 -10
View File
@@ -3,21 +3,20 @@ namespace zin;
class avatar extends wg
{
protected static $defineProps = array
(
protected static $defineProps = array(
'className?:string',
'style?:array',
'size?:number=32',
'size?:int=32',
'circle?:bool=true',
'rounded?:string|number',
'rounded?:string|int',
'background?:string',
'foreColor?:string',
'text?:string',
'code?:string',
'maxTextLength?:number=2',
'hueDistance?:number=43',
'saturation?:number=0.4',
'lightness?:number=0.6',
'maxTextLength?:int=2',
'hueDistance?:int=43',
'saturation?:int=0.4',
'lightness?:int=0.6',
'src?:string'
);
@@ -133,8 +132,8 @@ class avatar extends wg
* Convert HSL values to RGB value.
*
* @param int $h
* @param number $s
* @param number $l
* @param int $s
* @param int $l
* @access private
* @return array
*/
+3 -5
View File
@@ -3,8 +3,7 @@ namespace zin;
class btn extends wg
{
static $defineProps = array
(
static $defineProps = array(
'icon?:string',
'text?:string',
'square?:bool',
@@ -12,7 +11,7 @@ class btn extends wg
'active?:bool',
'url?:string',
'target?:string',
'size?:string|number',
'size?:string|int',
'trailingIcon?:string',
'caret?:string|bool',
'hint?:string',
@@ -80,8 +79,7 @@ class btn extends wg
$trailingIcon = $this->prop('trailingIcon');
$onlyCaret = empty($text) && !empty($caret) && empty($icon) && empty($trailingIcon);
$classList = array
(
$classList = array(
'btn' => true,
'disabled' => $this->prop('disabled'),
'active' => $this->prop('active'),
+8 -1
View File
@@ -4,7 +4,14 @@ namespace zin;
class cell extends wg
{
static $defineProps = 'order,grow,shrink,width,align,flex';
static $defineProps = array(
'order:int',
'grow:int',
'shrink:int',
'width:string|int',
'align:string', //'auto'|'flex-start'|'flex-end'|'center'|'baseline'|'stretch'
'flex:string'
);
protected function build()
{
+4 -1
View File
@@ -4,7 +4,10 @@ namespace zin;
class col extends wg
{
static $defineProps = 'justify?:string,align?:string';
static $defineProps = array(
'justify?:string',
'align?:string'
);
protected function build()
{
+16 -1
View File
@@ -6,7 +6,22 @@ require_once dirname(__DIR__) . DS . 'btn' . DS . 'v1.php';
class dropdown extends wg
{
static $defineProps = 'items?:array, placement?:string, strategy?:string, offset?: number, flip?: bool, subMenuTrigger?: string, arrow?: string, trigger?: string, menuProps?: array, target?: string, id?: string, menuClass?: string, hasIcons?: bool, staticMenu?: bool';
static $defineProps = array(
'items?:array',
'placement?:string',
'strategy?:string',
'offset?: int',
'flip?: bool',
'subMenuTrigger?: string',
'arrow?: string',
'trigger?: string',
'menuProps?: array',
'target?: string',
'id?: string',
'menuClass?: string',
'hasIcons?: bool',
'staticMenu?: bool'
);
static $defineBlocks = array
(
+4 -1
View File
@@ -3,7 +3,10 @@ namespace zin;
class dtable extends wg
{
static $defineProps = 'className?:string="shadow-sm rounded", id?:string';
static $defineProps = array(
'className?:string="shadow-sm rounded"',
'id?:string'
);
static $dtableID = 0;
+7 -2
View File
@@ -5,7 +5,12 @@ require_once dirname(__DIR__) . DS . 'nav' . DS . 'v1.php';
class featureBar extends wg
{
static $defineProps = 'items?:array, current?:string, link?:string, linkParams?:string';
static $defineProps = array(
'items?:array',
'current?:string',
'link?:string',
'linkParams?:string'
);
static $defineBlocks = array
(
@@ -28,7 +33,7 @@ class featureBar extends wg
$rawItems = \customModel::getFeatureMenu($app->rawModule, $app->rawMethod);
if(!is_array($rawItems)) return NULL;
$current = $this->prop('current', data('browseType', ''));
$current = $this->prop('current', data('browseType'));
$recTotal = data('recTotal');
$items = array();
$link = $this->prop('link');
+1 -1
View File
@@ -13,7 +13,7 @@ class form extends wg
'target?: string',
'items?: array',
'grid?: bool',
'labelWidth?: number',
'labelWidth?: int',
'submitBtnText?: string',
'cancelBtnText?: string',
);
+1 -2
View File
@@ -6,8 +6,7 @@ require_once dirname(__DIR__) . DS . 'control' . DS . 'v1.php';
class formGroup extends wg
{
protected static $defineProps = array
(
protected static $defineProps = array(
'name?: string',
'label?:string|bool',
'labelClass?: string',
+5 -1
View File
@@ -3,7 +3,11 @@ namespace zin;
class formLabel extends wg
{
protected static $defineProps = 'text?:string, required?:bool, for?: string';
protected static $defineProps = array(
'text?:string',
'required?:bool',
'for?:string'
);
public function onAddChild($child)
{
+1 -1
View File
@@ -15,7 +15,7 @@ class formPanel extends panel
'target?: string',
'items?: array',
'grid?: bool',
'labelWidth?: number',
'labelWidth?: int',
);
protected static $defaultProps = array(
+5 -1
View File
@@ -5,7 +5,11 @@ require_once dirname(__DIR__) . DS . 'formgroup' . DS . 'v1.php';
class formRow extends wg
{
static $defineProps = 'width?: string, items?: array, hidden?: boolean';
static $defineProps = array(
'width?: string',
'items?: array',
'hidden?: boolean'
);
public function onBuildItem($item)
{
+1 -2
View File
@@ -8,8 +8,7 @@ require_once dirname(__DIR__) . DS . 'useravatar' . DS . 'v1.php';
class header extends wg
{
static $defineBlocks = array
(
static $defineBlocks = array(
'heading' => array('map' => 'toolbar'),
'navbar' => array('map' => 'nav'),
'toolbar' => array('map' => 'btn')
+4 -1
View File
@@ -5,7 +5,10 @@ require_once dirname(__DIR__) . DS . 'toolbar' . DS . 'v1.php';
class heading extends wg
{
static $defineProps = 'items?:array, showAppName?:bool=true';
static $defineProps = array(
'items?:array',
'showAppName?:bool=true'
);
protected function buildAppName()
{
+4 -1
View File
@@ -3,7 +3,10 @@ namespace zin;
class icon extends wg
{
protected static $defineProps = 'name:string, size?:string|number';
protected static $defineProps = array(
'name:string',
'size?:string|int'
);
public function onAddChild($child)
{
+2 -2
View File
@@ -8,8 +8,8 @@ class inputControl extends wg
protected static $defineProps = array(
'prefix?: mixed',
'suffix?: mixed',
'prefixWidth?: string|number',
'suffixWidth?: string|number',
'prefixWidth?: string|int',
'suffixWidth?: string|int',
);
public static $defineBlocks = array(
+1 -2
View File
@@ -6,8 +6,7 @@ require_once dirname(__DIR__) . DS . 'featurebar' . DS . 'v1.php';
class main extends wg
{
static $defineBlocks = array
(
static $defineBlocks = array(
'menu' => array('map' => 'featureBar,nav,toolbar'),
'sidebar' => array('map' => 'sidebar')
);
+5 -1
View File
@@ -4,7 +4,11 @@ namespace zin;
class mainMenu extends wg
{
static $defineProps = 'statuses?:array,btnGroup?:array,others?:array';
static $defineProps = array(
'statuses?:array',
'btnGroup?:array',
'others?:array'
);
protected function buildOther($item)
{
+4 -1
View File
@@ -5,7 +5,10 @@ require_once dirname(__DIR__) . DS . 'modaldialog' . DS . 'v1.php';
class modal extends modalDialog
{
static $defineProps = 'id?: string="$GID", modalProps?: array=[]';
static $defineProps = array(
'id?: string="$GID"',
'modalProps?: array=array()'
);
protected function build()
{

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