Merge branch 'sprint/168_tianshujie_43426' into 'sprint/168'

* Refactoring the Kanban function.

See merge request easycorp/zentaopms!145
This commit is contained in:
李玉春
2021-10-26 02:51:13 +00:00
11 changed files with 401 additions and 14 deletions
+7 -5
View File
@@ -223,11 +223,13 @@ define('TABLE_JOB', '`' . $config->db->prefix . 'job`');
define('TABLE_COMPILE', '`' . $config->db->prefix . 'compile`');
define('TABLE_MR', '`' . $config->db->prefix . 'mr`');
define('TABLE_REPO', '`' . $config->db->prefix . 'repo`');
define('TABLE_RELATION', '`' . $config->db->prefix . 'relation`');
define('TABLE_REPOHISTORY', '`' . $config->db->prefix . 'repohistory`');
define('TABLE_REPOFILES', '`' . $config->db->prefix . 'repofiles`');
define('TABLE_REPOBRANCH', '`' . $config->db->prefix . 'repobranch`');
define('TABLE_REPO', '`' . $config->db->prefix . 'repo`');
define('TABLE_RELATION', '`' . $config->db->prefix . 'relation`');
define('TABLE_REPOHISTORY', '`' . $config->db->prefix . 'repohistory`');
define('TABLE_REPOFILES', '`' . $config->db->prefix . 'repofiles`');
define('TABLE_REPOBRANCH', '`' . $config->db->prefix . 'repobranch`');
define('TABLE_KANBANLANE', '`' . $config->db->prefix . 'kanbanlane`');
define('TABLE_KANBANCOLUMN', '`' . $config->db->prefix . 'kanbancolumn`');
if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`');
if(!defined('TABLE_PROJECTSPEC')) define('TABLE_PROJECTSPEC', '`' . $config->db->prefix . 'projectspec`');
+26
View File
@@ -0,0 +1,26 @@
-- DROP TABLE IF EXISTS `zt_kanbanlane`;
CREATE TABLE IF NOT EXISTS `zt_kanbanlane` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`execution` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`order` smallint(6) NOT NULL DEFAULT '0',
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_kanbancolumn`;
CREATE TABLE IF NOT EXISTS `zt_kanbancolumn` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`lane` mediumint(8) NOT NULL DEFAULT '0',
`parent` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`limit` smallint(6) NOT NULL DEFAULT '-1',
`order` mediumint(8) NOT NULL DEFAULT '0',
`cards` text NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+25
View File
@@ -595,6 +595,31 @@ CREATE TABLE IF NOT EXISTS `zt_job` (
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_kanbanlane`;
CREATE TABLE IF NOT EXISTS `zt_kanbanlane` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`execution` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`order` smallint(6) NOT NULL DEFAULT '0',
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_kanbancolumn`;
CREATE TABLE IF NOT EXISTS `zt_kanbancolumn` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`lane` mediumint(8) NOT NULL DEFAULT '0',
`parent` mediumint(8) NOT NULL DEFAULT '0',
`type` char(30) NOT NULL,
`name` varchar(255) NOT NULL DEFAULT '',
`color` char(30) NOT NULL,
`limit` smallint(6) NOT NULL DEFAULT '-1',
`order` mediumint(8) NOT NULL DEFAULT '0',
`cards` text NULL,
`deleted` enum('0','1') NOT NULL default '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_lang`;
CREATE TABLE IF NOT EXISTS `zt_lang` (
`id` mediumint(8) unsigned NOT NULL auto_increment,
+3 -1
View File
@@ -1575,7 +1575,9 @@ class bugModel extends model
->beginIF($type == 'noclosed')->andWhere('status')->ne('closed')->fi()
->beginIF($build)->andWhere("CONCAT(',', openedBuild, ',') like '%,$build,%'")->fi()
->beginIF($excludeBugs)->andWhere('id')->notIN($excludeBugs)->fi()
->orderBy($orderBy)->page($pager)->fetchAll();
->orderBy($orderBy)
->page($pager)
->fetchAll('id');
}
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'bug');
+1
View File
@@ -75,6 +75,7 @@ $lang->file = new stdclass();
$lang->misc = new stdclass();
$lang->acl = new stdclass();
$lang->curd = new stdclass();
$lang->kanban = new stdclass();
$lang->projectbuild = new stdclass();
$lang->projectrelease = new stdclass();
+9 -6
View File
@@ -1834,17 +1834,20 @@ class execution extends control
{
/* Save to session. */
$uri = $this->app->getURI(true);
$this->app->session->set('taskList', $uri, 'execution');
$this->app->session->set('bugList', $uri, 'qa');
$this->app->session->set('taskList', $uri, 'execution');
$this->app->session->set('bugList', $uri, 'qa');
/* Compatibility IE8*/
/* Compatibility IE8. */
if(strpos($this->server->http_user_agent, 'MSIE 8.0') !== false) header("X-UA-Compatible: IE=EmulateIE7");
$kanban = $this->loadModel('kanban')->getExecutionKanban($executionID);
if(empty($kanban)) $this->kanban->createLanes($executionID);
$this->execution->setMenu($executionID);
$execution = $this->loadModel('execution')->getById($executionID);
$tasks = $this->execution->getKanbanTasks($executionID, "id");
$bugs = $this->loadModel('bug')->getExecutionBugs($executionID);
$stories = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, $orderBy);
$tasks = $this->execution->getKanbanTasks($executionID, "id");
$bugs = $this->loadModel('bug')->getExecutionBugs($executionID);
$stories = $this->loadModel('story')->getExecutionStories($executionID);
/* Determines whether an object is editable. */
$canBeChanged = common::canModify('execution', $execution);
+4 -2
View File
@@ -78,7 +78,7 @@ class executionModel extends model
global $lang;
$this->app->loadLang('project');
$lang->executionCommon = $lang->project->stage;
include $this->app->getModulePath('execution') . 'lang/' . $this->app->getClientLang() . '.php';
include $this->app->getModulePath('', 'execution') . 'lang/' . $this->app->getClientLang() . '.php';
}
if($execution and $execution->lifetime == 'ops')
@@ -379,6 +379,8 @@ class executionModel extends model
$creatorExists = false;
$teamMembers = array();
$this->loadModel('kanban')->createLanes($executionID);
/* Save order. */
$this->dao->update(TABLE_EXECUTION)->set('`order`')->eq($executionID * 5)->where('id')->eq($executionID)->exec();
$this->file->updateObjectID($this->post->uid, $executionID, 'execution');
@@ -3163,7 +3165,7 @@ class executionModel extends model
->andWhere('t1.parent')->ge(0)
->orderBy($orderBy)
->page($pager)
->fetchAll();
->fetchAll('id');
$this->loadModel('common')->saveQueryCondition($this->dao->get(), 'task');
+19
View File
@@ -0,0 +1,19 @@
<?php
global $lang;
$config->kanban = new stdclass();
$config->kanban->default = new stdclass();
$config->kanban->default->story = new stdclass();
$config->kanban->default->story->name = $lang->SRCommon;
$config->kanban->default->story->color = '#7ec5ff';
$config->kanban->default->story->order = '5';
$config->kanban->default->bug = new stdclass();
$config->kanban->default->bug->name = $lang->bug->common;
$config->kanban->default->bug->color = '#ba55d3';
$config->kanban->default->bug->order = '10';
$config->kanban->default->task = new stdclass();
$config->kanban->default->task->name = $lang->task->common;
$config->kanban->default->task->color = '#4169e1';
$config->kanban->default->task->order = '15';
+35
View File
@@ -0,0 +1,35 @@
<?php
$lang->kanban = new stdClass();
$lang->kanban->storyColumn = array();
$lang->kanban->storyColumn['backlog'] = 'Backlog';
$lang->kanban->storyColumn['ready'] = '准备好';
$lang->kanban->storyColumn['develop'] = '开发';
$lang->kanban->storyColumn['developing'] = '进行中';
$lang->kanban->storyColumn['developed'] = '完成';
$lang->kanban->storyColumn['test'] = '测试';
$lang->kanban->storyColumn['testing'] = '进行中';
$lang->kanban->storyColumn['tested'] = '完成';
$lang->kanban->storyColumn['verified'] = '已验收';
$lang->kanban->storyColumn['released'] = '已发布';
$lang->kanban->storyColumn['closed'] = '已关闭';
$lang->kanban->bugColumn = array();
$lang->kanban->bugColumn['unconfirmed'] = '待确认';
$lang->kanban->bugColumn['confirmed'] = '已确认';
$lang->kanban->bugColumn['resolving'] = '解决中';
$lang->kanban->bugColumn['fixing'] = '进行中';
$lang->kanban->bugColumn['fixed'] = '完成';
$lang->kanban->bugColumn['test'] = '测试';
$lang->kanban->bugColumn['testing'] = '进行中';
$lang->kanban->bugColumn['tested'] = '完成';
$lang->kanban->bugColumn['closed'] = '已关闭';
$lang->kanban->taskColumn = array();
$lang->kanban->taskColumn['wait'] = '未开始';
$lang->kanban->taskColumn['develop'] = '开发';
$lang->kanban->taskColumn['developing'] = '研发中';
$lang->kanban->taskColumn['developed'] = '研发完毕';
$lang->kanban->taskColumn['pause'] = '已暂停';
$lang->kanban->taskColumn['canceled'] = '已取消';
$lang->kanban->taskColumn['closed'] = '已关闭';
+268
View File
@@ -0,0 +1,268 @@
<?php
/**
* The model file of kanban module of ZenTaoPMS.
*
* @copyright Copyright 2009-2021 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Shujie Tian <tianshujie@easycorp.ltd>
* @package kanban
* @version $Id: model.php 5118 2021-10-22 10:18:41Z $
* @link https://www.zentao.net
*/
?>
<?php
class kanbanModel extends model
{
/**
* Get Kanban by execution id.
*
* @param int $executionID
* @param string $objectType all|story|bug|task
* @access public
* @return array
*/
public function getExecutionKanban($executionID, $objectType = 'all')
{
$lanes = $this->dao->select('*')->from(TABLE_KANBANLANE)
->where('execution')->eq($executionID)
->andWhere('deleted')->eq(0)
->beginIF($objectType != 'all')->andWhere('type')->eq($objectType)
->fetchAll('id');
if(empty($lanes)) return array();
$columns = $this->dao->select('*')->from(TABLE_KANBANCOLUMN)
->where('deleted')->eq(0)
->andWhere('lane')->in(array_keys($lanes))
->fetchGroup('lane', 'id');
foreach($columns as $laneID => $cols)
{
foreach($cols as $colID => $col)
{
if($col->parent > 0)
{
$cols[$col->parent]->childs[$colID] = $col;
unset($cols[$colID]);
}
}
}
foreach($lanes as $laneID => $lane) $lane->columns = $columns[$laneID];
return $lanes;
}
/**
* Add execution Kanban lanes and columns.
*
* @param int $executionID
* @access public
* @return void
*/
public function createLanes($executionID)
{
foreach($this->config->kanban->default as $type => $lane)
{
$lane->type = $type;
$lane->execution = $executionID;
$this->dao->insert(TABLE_KANBANLANE)->data($lane)->exec();
$laneID = $this->dao->lastInsertId();
$this->createColumns($laneID, $type, $executionID);
}
}
/**
* createColumn
*
* @param int $laneID
* @param string $type story|bug|task
* @param int $executionID
* @access public
* @return void
*/
public function createColumns($laneID, $type, $executionID)
{
$objects = array();
if($type == 'story') $objects = $this->loadModel('story')->getExecutionStories($executionID, 0, 0, 't2.id_desc');
if($type == 'bug') $objects = $this->loadModel('bug')->getExecutionBugs($executionID);
if($type == 'task') $objects = $this->loadModel('execution')->getKanbanTasks($executionID);
$devColumnID = $testColumnID = $resolvingColumnID = 0;
if($type == 'story')
{
foreach($this->lang->kanban->storyColumn as $colType => $name)
{
$data = new stdClass();
$data->lane = $laneID;
$data->name = $name;
$data->type = $colType;
$data->cards = '';
if(strpos(',developing,developed,', $colType) !== false) $data->parent = $devColumnID;
if(strpos(',testing,tested,', $colType) !== false) $data->parent = $testColumnID;
if(strpos(',ready,develop,test,', $colType) === false)
{
foreach($objects as $storyID => $story)
{
if($colType == 'backlog' and $story->status == 'active' and $story->stage == 'projected') $data->cards .= $storyID . ',';
if($colType == 'closed' and $story->status == 'closed' and $story->stage == 'closed') $data->cards .= $storyID . ',';
if($story->stage == $colType and strpos(',backlog,closed,', $colType) === false and $story->status == 'active') $data->cards .= $storyID . ',';
}
if(!empty($data->cards)) $data->cards = ',' . $data->cards;
}
$this->dao->insert(TABLE_KANBANCOLUMN)->data($data)->exec();
if($colType == 'develop') $devColumnID = $this->dao->lastInsertId();
if($colType == 'test') $testColumnID = $this->dao->lastInsertId();
}
}
elseif($type == 'bug')
{
foreach($this->lang->kanban->bugColumn as $colType => $name)
{
$data = new stdClass();
$data->lane = $laneID;
$data->name = $name;
$data->type = $colType;
$data->cards = '';
if(strpos(',fixing,fixed,', $colType) !== false) $data->parent = $resolvingColumnID;
if(strpos(',testing,tested,', $colType) !== false) $data->parent = $testColumnID;
if(strpos(',resolving,fixing,test,testing,tested,', $colType) === false)
{
foreach($objects as $bugID => $bug)
{
if($colType == 'unconfirmed' and $bug->status == 'active' and $bug->confirmed == 0) $data->cards .= $bugID . ',';
if($colType == 'confirmed' and $bug->status == 'active' and $bug->confirmed == 1) $data->cards .= $bugID . ',';
if($colType == 'fixed' and $bug->status == 'resolved') $data->cards .= $bugID . ',';
if($colType == 'closed' and $bug->status == 'closed') $data->cards .= $bugID . ',';
}
$this->dao->insert(TABLE_KANBANCOLUMN)->data($data)->exec();
if($colType == 'resolving') $resolvingColumnID = $this->dao->lastInsertId();
if($colType == 'test') $testColumnID = $this->dao->lastInsertId();
}
}
}
elseif($type == 'task')
{
foreach($this->lang->kanban->taskColumn as $colType => $name)
{
$data = new stdClass();
$data->lane = $laneID;
$data->name = $name;
$data->type = $colType;
$data->cards = '';
if(strpos(',developing,developed,', $colType) !== false) $data->parent = $devColumnID;
if(strpos(',develop,', $colType) === false)
{
foreach($objects as $taskID => $task)
{
if($colType == 'developing' and $task->status == 'doing') $data->cards .= $taskID . ',';
if($colType == 'developed' and $task->status == 'done') $data->cards .= $taskID . ',';
if(strpos(',wait,pause,canceled,closed,', $colType) !== false and $task->status == $colType) $data->cards .= $taskID . ',';
}
$this->dao->insert(TABLE_KANBANCOLUMN)->data($data)->exec();
if($colType == 'develop') $devColumnID = $this->dao->lastInsertId();
}
}
}
}
/**
* Update column cards.
*
* @param int $executionID
* @param string $objectType story|bug|task
* @param object $columns
* @access public
* @return void
*/
public function updateCards($executionID, $objectType, $columns)
{
$objects = array();
if($objectType == 'story') $objects = $this->loadModel('story')->getExecutionStories($executionID);
if($objectType == 'bug') $objects = $this->loadModel('bug')->getExecutionBugs($executionID);
if($objectType == 'task') $objects = $this->loadModel('execution')->getKanbanTasks($executionID);
if($objectType == 'story')
{
$data = new stdClass();
foreach($columns as $colID => $col)
{
foreach($objects as $storyID => $story)
{
if($col->type == 'backlog' and $story->status == 'active' and $story->stage == 'projected') $data->cards .= $storyID . ',';
if($colType == 'closed' and $story->status == 'closed' and $story->stage == 'closed') $data->cards .= $storyID . ',';
if($story->stage == $colType and strpos(',backlog,closed,', $colType) === false and $story->status == 'active') $data->cards .= $storyID . ',';
}
if(!empty($data->cards)) $data->cards = ',' . $data->cards;
}
$this->dao->insert(TABLE_KANBANCOLUMN)->data($data)->exec();
if($colType == 'develop') $devColumnID = $this->dao->lastInsertId();
if($colType == 'test') $testColumnID = $this->dao->lastInsertId();
}
elseif($type == 'bug')
{
foreach($this->lang->kanban->bugColumn as $colType => $name)
{
$data = new stdClass();
$data->lane = $laneID;
$data->name = $name;
$data->type = $colType;
$data->cards = '';
if(strpos(',fixing,fixed,', $colType) !== false) $data->parent = $resolvingColumnID;
if(strpos(',testing,tested,', $colType) !== false) $data->parent = $testColumnID;
if(strpos(',resolving,fixing,test,testing,tested,', $colType) === false)
{
foreach($objects as $bugID => $bug)
{
if($colType == 'unconfirmed' and $bug->status == 'active' and $bug->confirmed == 0) $data->cards .= $bugID . ',';
if($colType == 'confirmed' and $bug->status == 'active' and $bug->confirmed == 1) $data->cards .= $bugID . ',';
if($colType == 'fixed' and $bug->status == 'resolved') $data->cards .= $bugID . ',';
if($colType == 'closed' and $bug->status == 'closed') $data->cards .= $bugID . ',';
}
$this->dao->insert(TABLE_KANBANCOLUMN)->data($data)->exec();
if($colType == 'resolving') $resolvingColumnID = $this->dao->lastInsertId();
if($colType == 'test') $testColumnID = $this->dao->lastInsertId();
}
}
}
elseif($type == 'task')
{
foreach($this->lang->kanban->taskColumn as $colType => $name)
{
$data = new stdClass();
$data->lane = $laneID;
$data->name = $name;
$data->type = $colType;
$data->cards = '';
if(strpos(',developing,developed,', $colType) !== false) $data->parent = $devColumnID;
if(strpos(',develop,', $colType) === false)
{
foreach($objects as $taskID => $task)
{
if($colType == 'developing' and $task->status == 'doing') $data->cards .= $taskID . ',';
if($colType == 'developed' and $task->status == 'done') $data->cards .= $taskID . ',';
if(strpos(',wait,pause,canceled,closed,', $colType) !== false and $task->status == $colType) $data->cards .= $taskID . ',';
}
$this->dao->insert(TABLE_KANBANCOLUMN)->data($data)->exec();
if($colType == 'develop') $devColumnID = $this->dao->lastInsertId();
}
}
}
}
}
+4
View File
@@ -725,6 +725,10 @@ class upgradeModel extends model
$this->saveLogs('Execute 15_6');
$this->execSQL($this->getUpgradeFile('15.6'));
$this->appendExec('15_6');
case '15_7':
$this->saveLogs('Execute 15_7');
$this->execSQL($this->getUpgradeFile('15.7'));
$this->appendExec('15_7');
}
$this->deletePatch();