Merge branch '15.0.beta3' of https://gitlab.zcorp.cc/easycorp/zentaopms into 15.0.beta3

This commit is contained in:
wangyidong
2021-05-20 16:56:04 +08:00
27 changed files with 159 additions and 90 deletions
+7 -7
View File
@@ -585,13 +585,13 @@ INSERT INTO `zt_searchindex` (`id`, `objectType`, `objectID`, `title`, `content`
(40, 'task', 16, ' 21806 21518 26381 21153 30340 35774 35745', ' 21806 21518 26381 21153 30340 35774 35745', '2021-04-28 13:16:15', '2021-04-28 13:16:15'),
(41, 'task', 17, ' 21806 21518 26381 21153 30340 24320 21457', ' 21806 21518 26381 21153 30340 24320 21457', '2021-04-28 13:16:15', '2021-04-28 13:16:15');
INSERT INTO `zt_story` (`id`, `parent`, `product`, `branch`, `module`, `plan`, `source`, `sourceNote`, `fromBug`, `title`, `keywords`, `type`, `pri`, `estimate`, `status`, `subStatus`, `color`, `stage`, `stagedBy`, `mailto`, `openedBy`, `openedDate`, `assignedTo`, `assignedDate`, `lastEditedBy`, `lastEditedDate`, `reviewedBy`, `reviewedDate`, `closedBy`, `closedDate`, `closedReason`, `toBug`, `childStories`, `linkStories`, `duplicateStory`, `version`, `URChanged`, `deleted`) VALUES
(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'),
(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0');
(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'),
(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0');
INSERT INTO `zt_storyspec` (`story`, `version`, `title`, `spec`, `verify`) VALUES
(1, 1, '首页设计和开发', '作为一名本公司的用户,我希望可以在首页看到该公司网站的基本内容,例如最新动态、部分成果展示、联系信息、工商信息等。<br />', '开发并通过验收<br />'),
(2, 1, '新闻中心的设计和开发。', '作为一名本公司的用户,我希望可以在新闻中心看到该公司网站的企业新闻,这样可以通过新闻了解企业的最新动态。<br />', ''),
+7 -7
View File
@@ -585,13 +585,13 @@ INSERT INTO `zt_searchindex` (`id`, `objectType`, `objectID`, `title`, `content`
(40, 'task', 16, ' 21806 21518 26381 21153 30340 35774 35745', ' 21806 21518 26381 21153 30340 35774 35745', '2021-04-28 13:16:15', '2021-04-28 13:16:15'),
(41, 'task', 17, ' 21806 21518 26381 21153 30340 24320 21457', ' 21806 21518 26381 21153 30340 24320 21457', '2021-04-28 13:16:15', '2021-04-28 13:16:15');
INSERT INTO `zt_story` (`id`, `parent`, `product`, `branch`, `module`, `plan`, `source`, `sourceNote`, `fromBug`, `title`, `keywords`, `type`, `pri`, `estimate`, `status`, `subStatus`, `color`, `stage`, `stagedBy`, `mailto`, `openedBy`, `openedDate`, `assignedTo`, `assignedDate`, `lastEditedBy`, `lastEditedDate`, `reviewedBy`, `reviewedDate`, `closedBy`, `closedDate`, `closedReason`, `toBug`, `childStories`, `linkStories`, `duplicateStory`, `version`, `URChanged`, `deleted`) VALUES
(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'),
(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0');
(1, 0, 1, 0, 1, '1', 'po', '', 0, '首页设计和开发', '', 'story', 1, 1, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:09:49', 'productManager', '0000-00-00 00:00:00', 'productManager', '2012-06-05 10:25:19', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(2, 0, 1, 0, 2, '1', 'po', '', 0, '新闻中心的设计和开发。', '', 'story', 1, 1, 'active', '', '', 'projected', '', '', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:16:37', 'productManager', '2012-06-05 10:25:33', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(3, 0, 1, 0, 3, '1', 'po', '', 0, '成果展示的设计和开发', '', 'story', 1, 0, 'active', '', '', 'developing', '', '', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:18:10', 'productManager', '2012-06-05 10:25:38', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 2, '0', '0'),
(4, 0, 1, 0, 4, '1', 'po', '', 0, '售后服务的设计和开发', '', 'story', 1, 1, 'active', '', '', 'developed', '', '', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:20:16', 'productManager', '2012-06-05 10:25:42', 'productManager, ', '2012-06-05 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(5, 0, 1, 0, 5, '1', 'po', '', 0, '诚聘英才的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:21:39', 'productManager', '2012-06-05 10:21:39', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(6, 0, 1, 0, 6, '1', 'po', '', 0, '合作洽谈的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:23:11', 'productManager', '2012-06-05 10:23:11', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0'),
(7, 0, 1, 0, 7, '1', 'po', '', 0, '关于我们的设计和开发', '', 'story', 1, 1, 'draft', '', '', 'planned', '', '', 'productManager', '2012-06-05 10:24:19', 'productManager', '2012-06-05 10:24:19', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', '0000-00-00 00:00:00', '', 0, '', '', 0, 1, '0', '0');
INSERT INTO `zt_storyspec` (`story`, `version`, `title`, `spec`, `verify`) VALUES
(1, 1, '首页设计和开发', '作为一名本公司的用户,我希望可以在首页看到该公司网站的基本内容,例如最新动态、部分成果展示、联系信息、工商信息等。<br />', '开发并通过验收<br />'),
(2, 1, '新闻中心的设计和开发。', '作为一名本公司的用户,我希望可以在新闻中心看到该公司网站的企业新闻,这样可以通过新闻了解企业的最新动态。<br />', ''),
+1
View File
@@ -23,5 +23,6 @@ ALTER TABLE `zt_project` CHANGE `lifetime` `lifetime` char(30) NOT NULL DEFAULT
ALTER TABLE `zt_story` ADD `category` varchar(30) NOT NULL DEFAULT 'feature' AFTER `type`;
ALTER TABLE `zt_testtask` ADD `type` varchar(255) NOT NULL DEFAULT '' AFTER `build`;
ALTER TABLE `zt_testtask` ADD `testreport` mediumint(8) unsigned NOT NULL AFTER `status`;
ALTER TABLE `zt_story` MODIFY COLUMN `reviewedDate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00';
INSERT INTO `zt_config` (`owner`, `module`, `section`, `key`, `value`) VALUES ('system', 'story', '', 'reivewRules', 'allpass');
+1 -1
View File
@@ -838,7 +838,7 @@ CREATE TABLE IF NOT EXISTS `zt_story` (
`lastEditedBy` varchar(30) NOT NULL default '',
`lastEditedDate` datetime NOT NULL,
`reviewedBy` varchar(255) NOT NULL,
`reviewedDate` date NOT NULL,
`reviewedDate` datetime NOT NULL default '0000-00-00 00:00:00',
`closedBy` varchar(30) NOT NULL default '',
`closedDate` datetime NOT NULL,
`closedReason` varchar(30) NOT NULL,
+23 -12
View File
@@ -8,22 +8,22 @@
* @package spliter
* @version $Id$
* @link http://www.chanzhi.org
* @see http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html
* @see http://www.cnblogs.com/chenwenbiao/archive/2011/08/11/2134503.html
* @see http://stackoverflow.com/questions/9361303/can-i-get-the-unicode-value-of-a-character-or-vise-versa-with-php
*/
class spliter
{
/**
* Split a utf-8 string into words, computing unicode for every word.
*
* @param string $string
*
* @param string $string
* @access public
* @return array
*/
public function utf8Split($string)
{
$string = strtolower($string);
$i = 0;
$i = 0;
$length = strlen($string);
$dict = array();
$words = '';
@@ -50,12 +50,16 @@ class spliter
$word .= $letter;
$i++;
}
/* Process intigers. */
if(is_numeric($word) and (strpos($word, '.') === false)) $word = "|" . $word . "|";
$word = str_pad(strtolower($word), 5, '_');
$words .= ' ' . $word;
}
elseif($ord == 32)
{
$words .= ' ';
}
continue;
}
@@ -76,7 +80,14 @@ class spliter
}
else
{
$words .= ' ' . $letter;
if(is_numeric(substr($words, strlen($words) - 1, 1)))
{
$words .= ' ' . $letter;
}
else
{
$words .= $letter;
}
}
$i += $offset;
}
@@ -86,13 +97,13 @@ class spliter
}
/**
* Return unicode value for a char.
*
* @param string $c
* Return unicode value for a char.
*
* @param string $c
* @access public
* @return int
*/
public function unicode($c)
public function unicode($c)
{
if(ord($c{0}) >= 0 && ord($c{0}) <= 127) return ord($c{0});
if(ord($c{0}) >= 192 && ord($c{0}) <= 223) return (ord($c{0}) - 192) * 64 + (ord($c{1}) - 128);
@@ -107,8 +118,8 @@ class spliter
/**
* Judge a char is Letter or not.
*
* @param string $letter
*
* @param string $letter
* @access public
* @return bool
*/
+23 -10
View File
@@ -220,8 +220,9 @@ class actionModel extends model
if($objectType == 'release') $record->project = $this->dao->select('project')->from(TABLE_BUILD)->where('id')->eq($record->build)->fetch('project');
if($objectType == 'team')
{
$team = $this->dao->select('type,root')->from(TABLE_TEAM)->where('id')->eq($objectID)->fetch();
$record->{$team->type} = $team->root;
$team = $this->dao->select('type')->from(TABLE_PROJECT)->where('id')->eq($objectID)->fetch();
$type = $team->type == 'project' ? 'project' : 'execution';
$record->$type = $objectID;
}
if($objectType == 'task')
{
@@ -627,7 +628,11 @@ class actionModel extends model
*/
if(empty($desc))
{
if(isset($this->lang->$objectType) && isset($this->lang->$objectType->action->$actionType))
if($action->objectType == 'story' and $action->action = 'reviewed' and strpos($action->extra, ',') !== false)
{
$desc = $this->lang->$objectType->action->rejectreviewed;
}
elseif(isset($this->lang->$objectType) && isset($this->lang->$objectType->action->$actionType))
{
$desc = $this->lang->$objectType->action->$actionType;
}
@@ -668,14 +673,23 @@ class actionModel extends model
/* Fix bug #741. */
if(isset($desc['extra'])) $desc['extra'] = $this->lang->$objectType->{$desc['extra']};
$actionDesc = '';
if(isset($desc['extra'][$extra]))
{
echo str_replace('$extra', $desc['extra'][$extra], $desc['main']);
$actionDesc = str_replace('$extra', $desc['extra'][$extra], $desc['main']);
}
else
{
echo str_replace('$extra', $action->extra, $desc['main']);
$actionDesc = str_replace('$extra', $action->extra, $desc['main']);
}
if($action->objectType == 'story' and $action->action = 'reviewed' and strpos($action->extra, ',') !== false)
{
list($extra, $reason) = explode(',', $extra);
$desc['reason'] = $this->lang->$objectType->{$desc['reason']};
$actionDesc = str_replace(array('$extra', '$reason'), array($desc['extra'][$extra], $desc['reason'][$reason]), $desc['main']);
}
echo $actionDesc;
}
else
{
@@ -944,16 +958,15 @@ class actionModel extends model
}
elseif($objectType == 'team')
{
$objectInfo = $this->dao->select('t1.id as projectID,t2.id,t1.team as name,t1.type')->from(TABLE_PROJECT)->alias('t1')
->leftJoin(TABLE_TEAM)->alias('t2')->on('t1.id=t2.root')
->where('t2.id')->in($objectIds)
$objectInfo = $this->dao->select('id,team,type')->from(TABLE_PROJECT)
->where('id')->in($objectIds)
->fetchAll();
$objectProject = array();
foreach($objectInfo as $object)
{
$objectName[$object->id] = $object->name;
if($object->type == 'project') $objectProject[$object->id] = $object->projectID;
$objectName[$object->id] = $object->team;
if($object->type == 'project') $objectProject[$object->id] = $object->id;
}
}
else
+2 -4
View File
@@ -2188,8 +2188,7 @@ class execution extends control
if(!empty($_POST))
{
$this->execution->manageMembers($executionID);
$teamID = $this->dao->select('id')->from(TABLE_TEAM)->where('root')->eq($executionID)->andWhere('type')->eq('execution')->fetch('id');
$this->loadModel('action')->create('team', $teamID, 'managedTeam');
$this->loadModel('action')->create('team', $executionID, 'managedTeam');
die(js::locate($this->createLink('execution', 'team', "executionID=$executionID"), 'parent'));
}
@@ -2258,8 +2257,7 @@ class execution extends control
$this->execution->unlinkMember($executionID, $account);
if(!dao::isError())
{
$teamID = $this->dao->select('id')->from(TABLE_TEAM)->where('root')->eq($executionID)->andWhere('type')->eq('execution')->fetch('id');
$this->loadModel('action')->create('team', $teamID, 'managedTeam');
$this->loadModel('action')->create('team', $executionID, 'managedTeam');
}
/* if ajax request, send result. */
+1
View File
@@ -39,6 +39,7 @@ function showNewEstimate()
$('.th-new-estimate').removeClass('hide');
$('.new-estimate').removeClass('hide');
$('.form-actions').removeClass('hide');
$('.empty-th').addClass('hide');
}
function selectRound(round)
+1
View File
@@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc
$lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}";
$lang->execution->recent = 'Recent visits: ';
$lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.';
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->start = 'Start';
$lang->execution->activate = 'Aktivieren';
+1
View File
@@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc
$lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}";
$lang->execution->recent = 'Recent visits: ';
$lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.';
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->start = 'Start';
$lang->execution->activate = 'Activate';
+1
View File
@@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc
$lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}";
$lang->execution->recent = 'Recent visits: ';
$lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.';
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->start = 'Démarrer';
$lang->execution->activate = 'Activer';
+1
View File
@@ -95,6 +95,7 @@ $lang->execution->oneProduct = "Only one stage can be linked {$lang->produc
$lang->execution->noLinkProduct = "Stage not linked {$lang->productCommon}";
$lang->execution->recent = 'Recent visits: ';
$lang->execution->copyNoExecution = 'There are no ' . $lang->executionCommon . 'available to copy.';
$lang->execution->noTeam = 'No team members at the moment';
$lang->execution->start = 'Bắt đầu';
$lang->execution->activate = 'Kích hoạt';
+1
View File
@@ -95,6 +95,7 @@ $lang->execution->oneProduct = "阶段只能关联一个{$lang->productComm
$lang->execution->noLinkProduct = "阶段没有关联{$lang->productCommon}";
$lang->execution->recent = '近期访问:';
$lang->execution->copyNoExecution = '没有可用的' . $lang->executionCommon . '来复制';
$lang->execution->noTeam = '暂时没有团队成员';
$lang->execution->start = "开始";
$lang->execution->activate = "激活";
+10 -3
View File
@@ -22,6 +22,11 @@
<div class="main-header">
<h2><?php echo $lang->execution->storyEstimate;?></h2>
</div>
<?php if(empty($team)):?>
<div class="table-empty-tip">
<p><span class="text-muted"><?php echo $lang->execution->noTeam;?></span></p>
</div>
<?php else:?>
<div class='btn-toolbar pull-left'>
<?php if(!empty($rounds)):?>
<div class='input-group space w-200px'>
@@ -37,9 +42,10 @@
<table class='table table-form'>
<thead>
<tr class='text-center'>
<th class='w-120px'><?php echo $lang->execution->team;?></th>
<th class='w-90px'> <?php echo $lang->story->estimate;?></th>
<th class='w-90px th-new-estimate hide'><?php echo $lang->execution->newEstimate;?></th>
<th><?php echo $lang->execution->team;?></th>
<th> <?php echo $lang->story->estimate;?></th>
<th class='th-new-estimate hide'><?php echo $lang->execution->newEstimate;?></th>
<th class='empty-th'></th>
</tr>
</thead>
<tbody>
@@ -76,5 +82,6 @@
</tfoot>
</table>
</form>
<?php endif;?>
</div>
<?php include '../../common/view/footer.html.php';?>
+1 -2
View File
@@ -1094,8 +1094,7 @@ class project extends control
if(!empty($_POST))
{
$this->project->manageMembers($projectID);
$teamID = $this->dao->select('id')->from(TABLE_TEAM)->where('root')->eq($projectID)->andWhere('type')->eq('project')->fetch('id');
$this->loadModel('action')->create('team', $teamID, 'ManagedTeam');
$this->loadModel('action')->create('team', $projectID, 'ManagedTeam');
$link = $this->createLink('project', 'manageMembers', "projectID=$projectID");
$this->send(array('message' => $this->lang->saveSuccess, 'result' => 'success', 'locate' => $link));
+1 -1
View File
@@ -60,7 +60,7 @@ adjustMenuWidth();
</section>
<footer class='table-footer'>
<?php echo str_replace($words, urlencode($words), $pager->get('right', 'short'));?>
<span class='execute-info text-muted'><?php printf($lang->search->executeInfo, $pager->recTotal, $consumed);?></span>
<span class='execute-info text-muted'><?php printf($lang->search->executeInfo, $pager->recTotal, $consumed);?></span>
</footer>
</div>
</div>
+1
View File
@@ -16,6 +16,7 @@ $config->story->review = new stdclass();
$config->story->create->requiredFields = 'title';
$config->story->change->requiredFields = 'title';
$config->story->close->requiredFields = 'closedReason';
$config->story->review->requiredFields = '';
$config->story->editor = new stdclass();
$config->story->editor->create = array('id' => 'spec,verify', 'tools' => 'simpleTools');
+9 -7
View File
@@ -609,9 +609,7 @@ class story extends control
/* Get users. */
$users = $this->user->getPairs('pofirst|nodeleted', "$story->assignedTo,$story->openedBy,$story->closedBy");
$reviewedBy = explode(',', trim($story->reviewedBy, ','));
$reivewerList = '';
foreach($reviewedBy as $reviewer) $reivewerList .= zget($users, $reviewer) . ' ';
$reviewerList = $this->dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->fetchPairs('reviewer');
$this->story->replaceURLang($story->type);
@@ -623,7 +621,7 @@ class story extends control
$this->view->product = $product;
$this->view->products = $myProducts + $othersProducts;
$this->view->branches = $product->type == 'normal' ? array() : $this->loadModel('branch')->getPairs($story->product);
$this->view->reviewers = $reivewerList;
$this->view->reviewers = implode(',', $reviewerList);
$this->display();
}
@@ -1004,9 +1002,11 @@ class story extends control
if($changes)
{
$result = $this->post->result;
$actionID = $this->action->create('story', $storyID, 'Reviewed', $this->post->comment, ucfirst($result));
if($result == 'reject') $actionID = $this->action->create('story', $storyID, 'Closed', '', ucfirst($this->post->closedReason));
$result = $this->post->result;
$reasonParam = $result == 'reject' ? ',' . $this->post->closedReason : '';
$storyStatus = $this->dao->findById($storyID)->from(TABLE_STORY)->fetch('status');
$actionID = $this->action->create('story', $storyID, 'Reviewed', $this->post->comment, ucfirst($result) . $reasonParam);
if($storyStatus == 'closed') $actionID = $this->action->create('story', $storyID, 'ReviewClosed');
$this->action->logHistory($actionID, $changes);
}
@@ -1041,8 +1041,10 @@ class story extends control
}
/* Set the review result options. */
$reviewers = $this->dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($story->version)->fetchAll('reviewer');
if($story->status == 'draft' and $story->version == 1) unset($this->lang->story->reviewResultList['revert']);
if($story->status == 'changed') unset($this->lang->story->reviewResultList['reject']);
if(count($reviewers) > 1) unset($this->lang->story->reviewResultList['revert']);
$this->view->title = $this->lang->story->review . "STORY" . $this->lang->colon . $story->title;
$this->view->position[] = html::a($this->createLink('product', 'browse', "product=$product->id&branch=$story->branch"), $product->name);
+2
View File
@@ -279,7 +279,9 @@ $lang->story->form->file = 'Wenn Dateien zu dieser Story gehören, laden Sie
$lang->story->action = new stdclass();
$lang->story->action->reviewed = array('main' => '$date, geprüft von <strong>$actor</strong>. Das Ergebnis ist <strong>$extra</strong>.', 'extra' => 'reviewResultList');
$lang->story->action->rejectreviewed = array('main' => '$date, geprüft von <strong>$actor</strong>. Das Ergebnis ist <strong>$extra</strong>, Der Grund ist <strong>$reason</strong>.', 'extra' => 'reviewResultList', 'reason' => 'reasonList');
$lang->story->action->closed = array('main' => '$date, geschlossen von <strong>$actor</strong>. Der Grund ist <strong>$extra</strong> $appendLink.', 'extra' => 'reasonList');
$lang->story->action->reviewclosed = array('main' => '$date, closed by <strong>System</strong>. The reasion is <strong>Review Failed</strong>.');
$lang->story->action->linked2plan = array('main' => '$date, verknüpft von <strong>$actor</strong> mit Plan <strong>$extra</strong>');
$lang->story->action->unlinkedfromplan = array('main' => '$date, Verknüpfung aufgelöst durch <strong>$actor</strong> von Plan <strong>$extra</strong>.');
$lang->story->action->linked2execution = array('main' => '$date, verknüpft von <strong>$actor</strong> mit ' . $lang->executionCommon . ' <strong>$extra</strong>.');
+2
View File
@@ -280,7 +280,9 @@ $lang->story->form->file = 'If any file that is linked to a story, please cl
$lang->story->action = new stdclass();
$lang->story->action->reviewed = array('main' => '$date, recorded by <strong>$actor</strong>. The result is <strong>$extra</strong>.', 'extra' => 'reviewResultList');
$lang->story->action->rejectreviewed = array('main' => '$date, recorded by <strong>$actor</strong>. The result is <strong>$extra</strong>. The reasion is <strong>$reason</strong>.', 'extra' => 'reviewResultList', 'reason' => 'reasonList');
$lang->story->action->closed = array('main' => '$date, closed by <strong>$actor</strong>. The reasion is <strong>$extra</strong> $appendLink.', 'extra' => 'reasonList');
$lang->story->action->reviewclosed = array('main' => '$date, closed by <strong>System</strong>. The reasion is <strong>Review Failed</strong>.');
$lang->story->action->linked2plan = array('main' => '$date, linked by <strong>$actor</strong> to Plan <strong>$extra</strong>');
$lang->story->action->unlinkedfromplan = array('main' => '$date, unlinked by <strong>$actor</strong> from Plan <strong>$extra</strong>.');
$lang->story->action->linked2execution = array('main' => '$date, linked by <strong>$actor</strong> to ' . $lang->executionCommon . ' <strong>$extra</strong>.');
+2
View File
@@ -279,7 +279,9 @@ $lang->story->form->file = 'Si certains fichiers sont associés à la story,
$lang->story->action = new stdclass();
$lang->story->action->reviewed = array('main' => '$date, validée par <strong>$actor</strong>. Le résultat est <strong>$extra</strong>.', 'extra' => 'reviewResultList');
$lang->story->action->rejectreviewed = array('main' => '$date, validée par <strong>$actor</strong>. Le résultat est <strong>$extra</strong>. La raison est <strong>$reason</strong>.', 'extra' => 'reviewResultList', 'reason' => 'reasonList');
$lang->story->action->closed = array('main' => '$date, Fermée par <strong>$actor</strong>. La raison est <strong>$extra</strong> $appendLink.', 'extra' => 'reasonList');
$lang->story->action->reviewclosed = array('main' => '$date, closed by <strong>System</strong>. The reasion is <strong>Review Failed</strong>.');
$lang->story->action->linked2plan = array('main' => '$date, planifiée par <strong>$actor</strong> au Plan <strong>$extra</strong>');
$lang->story->action->unlinkedfromplan = array('main' => '$date, déplanifiée par <strong>$actor</strong> du Plan <strong>$extra</strong>.');
$lang->story->action->linked2execution = array('main' => '$date, associée au ' . $lang->executionCommon . ' <strong>$extra</strong> par <strong>$actor</strong>.');
+3 -1
View File
@@ -279,7 +279,9 @@ $lang->story->form->file = 'Nếu bất kỳ tập tin mà liên kết tới
$lang->story->action = new stdclass();
$lang->story->action->reviewed = array('main' => '$date, ghi nhận bởi <strong>$actor</strong>. Kết quả là <strong>$extra</strong>.', 'extra' => 'reviewResultList');
$lang->story->action->closed = array('main' => '$date, được đóng bởi <strong>$actor</strong>.Lý do là <strong>$extra</strong> $appendLink.', 'extra' => 'reasonList');
$lang->story->action->rejectreviewed = array('main' => '$date, ghi nhận bởi <strong>$actor</strong>. Kết quả là <strong>$extra</strong>. Lý do là <strong>$reason</strong>', 'extra' => 'reviewResultList', 'reason' => 'reasonList');
$lang->story->action->closed = array('main' => '$date, được đóng bởi <strong>$actor</strong>. Lý do là <strong>$extra</strong> $appendLink.', 'extra' => 'reasonList');
$lang->story->action->reviewclosed = array('main' => '$date, closed by <strong>System</strong>. The reasion is <strong>Review Failed</strong>.');
$lang->story->action->linked2plan = array('main' => '$date, liên kết bởi <strong>$actor</strong> tới kế hoạch <strong>$extra</strong>');
$lang->story->action->unlinkedfromplan = array('main' => '$date, bị hủy bởi <strong>$actor</strong> từ kế hoạch <strong>$extra</strong>.');
$lang->story->action->linked2execution = array('main' => '$date, liên kết bởi <strong>$actor</strong> tới ' . $lang->executionCommon . ' <strong>$extra</strong>.');
+2
View File
@@ -280,7 +280,9 @@ $lang->story->form->file = "附件,如果该{$lang->SRCommon}有相关文
$lang->story->action = new stdclass();
$lang->story->action->reviewed = array('main' => '$date, 由 <strong>$actor</strong> 记录评审结果,结果为 <strong>$extra</strong>。', 'extra' => 'reviewResultList');
$lang->story->action->rejectreviewed = array('main' => '$date, 由 <strong>$actor</strong> 记录评审结果,结果为 <strong>$extra</strong>,原因为 <strong>$reason</strong>。', 'extra' => 'reviewResultList', 'reason' => 'reasonList');
$lang->story->action->closed = array('main' => '$date, 由 <strong>$actor</strong> 关闭,原因为 <strong>$extra</strong> $appendLink。', 'extra' => 'reasonList');
$lang->story->action->reviewclosed = array('main' => '$date, 由 <strong>系统</strong> 关闭,原因为 <strong>评审失败</strong>。');
$lang->story->action->linked2plan = array('main' => '$date, 由 <strong>$actor</strong> 关联到计划 <strong>$extra</strong>。');
$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 <strong>$actor</strong> 从计划 <strong>$extra</strong> 移除。');
$lang->story->action->linked2execution = array('main' => '$date, 由 <strong>$actor</strong> 关联到' . $lang->executionCommon . ' <strong>$extra</strong>。');
+2
View File
@@ -278,7 +278,9 @@ $lang->story->form->file = "附件,如果該{$lang->SRCommon}有相關檔
$lang->story->action = new stdclass();
$lang->story->action->reviewed = array('main' => '$date, 由 <strong>$actor</strong> 記錄評審結果,結果為 <strong>$extra</strong>。', 'extra' => 'reviewResultList');
$lang->story->action->rejectreviewed = array('main' => '$date, 由 <strong>$actor</strong> 記錄評審結果,結果為 <strong>$extra</strong>,原因為 <strong>$reason</strong>。', 'extra' => 'reviewResultList', 'reason' => 'reasonList');
$lang->story->action->closed = array('main' => '$date, 由 <strong>$actor</strong> 關閉,原因為 <strong>$extra</strong> $appendLink。', 'extra' => 'reasonList');
$lang->story->action->reviewclosed = array('main' => '$date, 由 <strong>系統</strong> 關閉,原因為 <strong>評審失敗</strong>。');
$lang->story->action->linked2plan = array('main' => '$date, 由 <strong>$actor</strong> 關聯到計劃 <strong>$extra</strong>。');
$lang->story->action->unlinkedfromplan = array('main' => '$date, 由 <strong>$actor</strong> 從計劃 <strong>$extra</strong> 移除。');
$lang->story->action->linked2execution = array('main' => '$date, 由 <strong>$actor</strong> 關聯到' . $lang->executionCommon . ' <strong>$extra</strong>。');
+51 -30
View File
@@ -670,7 +670,7 @@ class storyModel extends model
->join('mailto', ',')
->join('linkStories', ',')
->join('childStories', ',')
->remove('files,labels,comment,contactListMenu,stages')
->remove('files,labels,comment,contactListMenu,stages,reviewer')
->get();
if(isset($story->plan) and is_array($story->plan)) $story->plan = trim(join(',', $story->plan), ',');
@@ -785,6 +785,21 @@ class storyModel extends model
if(empty($oldStory->plan) or empty($story->plan)) $this->setStage($storyID); // Set new stage for this story.
}
/* Update story reviewer. */
$_POST['reviewer'] = array_filter($_POST['reviewer']);
$this->dao->delete()->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->andWhere('reviewer')->notin(implode(',', $_POST['reviewer']))->exec();
$oldReviewerList = $this->dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->fetchPairs('reviewer');
foreach($_POST['reviewer'] as $reviewer)
{
if(in_array($reviewer, $oldReviewerList)) continue;
$reviewData = new stdclass();
$reviewData->story = $storyID;
$reviewData->version = $oldStory->version;
$reviewData->reviewer = $reviewer;
$this->dao->insert(TABLE_STORYREVIEW)->data($reviewData)->exec();
}
unset($oldStory->parent);
unset($story->parent);
return common::createChanges($oldStory, $story);
@@ -1148,15 +1163,15 @@ class storyModel extends model
$now = helper::now();
$date = helper::today();
$story = fixer::input('post')
->setDefault('reviewedDate', $date)
->setDefault('lastEditedBy', $this->app->user->account)
->setDefault('lastEditedDate', $now)
->setIF($this->post->result == 'revert', 'version', $this->post->preVersion)
->setIF($this->post->result == 'revert', 'status', 'active')
->setIF(strpos($oldStory->reviewedBy, $this->app->user->account) === false, 'reviewedBy', $oldStory->reviewedBy . ',' . $this->app->user->account)
->removeIF($this->post->result != 'reject', 'closedReason, duplicateStory, childStories')
->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'duplicate', 'duplicateStory')
->removeIF($this->post->result == 'reject' and $this->post->closedReason != 'subdivided', 'childStories')
->add('reviewedDate', $now)
->add('reviewedBy', $oldStory->reviewedBy . ',' . $this->app->user->account)
->remove('result,preVersion,comment')
->get();
@@ -1166,36 +1181,41 @@ class storyModel extends model
$this->dao->update(TABLE_STORYREVIEW)->set('result')->eq($this->post->result)->set('reviewDate')->eq($now)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->andWhere('reviewer')->eq($this->app->user->account)->exec();
/* Update the story status by review rules. */
$passCount = 0;
$rejectCount = 0;
$reviewRule = $this->config->story->reviewRules;
$reviewerList = $this->dao->select('reviewer,result')->from(TABLE_STORYREVIEW)->where('story')->eq($storyID)->andWhere('version')->eq($oldStory->version)->fetchPairs('reviewer', 'result');
foreach($reviewerList as $reviewer => $result)
$reviewedBy = explode(',', trim($story->reviewedBy, ','));
if(!array_diff(array_keys($reviewerList), $reviewedBy))
{
$passCount = $result == 'pass' ? $passCount + 1 : $passCount;
$rejectCount = $result == 'reject' ? $rejectCount + 1 : $rejectCount;
}
if($reviewRule == 'allpass')
{
if($passCount == count($reviewerList)) $story->status = 'active';
if($rejectCount == count($reviewerList)) $story->status = 'closed';
}
if($reviewRule == 'halfpass')
{
if($passCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'active';
if($rejectCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'closed';
}
if($story->status == 'closed')
{
$story->closedBy = $this->app->user->account;
$story->closedDate = $now;
$story->assignedTo = 'closed';
$story->stage = 'closed';
if($this->post->closedReason == 'done') $story->stage = 'released';
$passCount = 0;
$rejectCount = 0;
$reviewRule = $this->config->story->reviewRules;
foreach($reviewerList as $reviewer => $result)
{
$passCount = $result == 'pass' ? $passCount + 1 : $passCount;
$rejectCount = $result == 'reject' ? $rejectCount + 1 : $rejectCount;
}
if($reviewRule == 'allpass')
{
if($passCount == count($reviewerList)) $story->status = 'active';
if($rejectCount == count($reviewerList)) $story->status = 'closed';
}
if($reviewRule == 'halfpass')
{
if($passCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'active';
if($rejectCount >= floor(count($reviewerList) / 2) + 1) $story->status = 'closed';
}
if($story->status == 'closed')
{
$story->closedBy = $this->app->user->account;
$story->closedDate = $now;
$story->assignedTo = 'closed';
$story->stage = 'closed';
if($this->post->closedReason == 'done') $story->stage = 'released';
}
}
$this->dao->update(TABLE_STORY)->data($story)
->autoCheck()
->batchCheck($this->config->story->review->requiredFields, 'notempty')
->checkIF($this->post->result == 'reject', 'closedReason', 'notempty')
->checkIF($this->post->result == 'reject' and $this->post->closedReason == 'duplicate', 'duplicateStory', 'notempty')
->where('id')->eq($storyID)->exec();
@@ -3225,10 +3245,11 @@ class storyModel extends model
if($story->parent < 0 and $action != 'edit' and $action != 'batchcreate') return false;
global $config, $app, $dao;
$reviewers = $dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->andWhere('result')->ne('pass')->fetchAll('reviewer');
$notReview = $dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->andWhere('result')->eq('')->fetchAll('reviewer');
$reviewers = $dao->select('reviewer')->from(TABLE_STORYREVIEW)->where('story')->eq($story->id)->andWhere('version')->eq($story->version)->fetchAll('reviewer');
if($action == 'change') return $story->status != 'closed';
if($action == 'review') return in_array($app->user->account, array_keys($reviewers)) and ($story->status == 'draft' or $story->status == 'changed');
if($action == 'change') return (count($reviewers) == 0 || count($notReview) == 0) and $story->status != 'closed';
if($action == 'review') return in_array($app->user->account, array_keys($notReview)) and ($story->status == 'draft' or $story->status == 'changed');
if($action == 'close') return $story->status != 'closed';
if($action == 'activate') return $story->status == 'closed';
if($action == 'assignto') return $story->status != 'closed';
+1 -3
View File
@@ -204,12 +204,10 @@
<th><?php echo $lang->story->assignedTo;?></th>
<td><?php echo html::select('assignedTo', $users, $story->assignedTo, 'class="form-control chosen"');?></td>
</tr>
<?php if($reviewers):?>
<tr>
<th><?php echo $lang->story->reviewedBy;?></th>
<td><?php echo $reviewers;?></td>
<td><?php echo html::select('reviewer[]', $users, $reviewers, 'class="form-control chosen" multiple')?></td>
</tr>
<?php endif;?>
<?php if($story->status == 'closed'):?>
<tr>
<th><?php echo $lang->story->closedBy;?></th>
+2 -2
View File
@@ -836,7 +836,7 @@ class taskModel extends model
->setIF($oldTask->parent < 0, 'estimate', $oldTask->estimate)
->setIF($oldTask->parent < 0, 'left', $oldTask->left)
->setIF($oldTask->name != $task->name || $oldTask->estStarted != $task->estStarted || $oldTask->deadline != $task->deadline, 'version', $oldTask->version + 1)
->setIF($oldTask->name != $this->post->name || $oldTask->estStarted != $this->post->estStarted || $oldTask->deadline != $this->post->deadline, 'version', $oldTask->version + 1)
->setDefault('lastEditedBy', $this->app->user->account)
->add('lastEditedDate', $now)
@@ -947,7 +947,7 @@ class taskModel extends model
}
/* Record task version. */
if($task->version > $oldTask->version)
if(isset($task->version) and $task->version > $oldTask->version)
{
$taskSpec = new stdClass();
$taskSpec->task = $taskID;