Merge branch 'master' of http://gitlab.zcorp.cc/easycorp/zentaopms
This commit is contained in:
@@ -109,6 +109,7 @@ zentaoxx:
|
||||
sed -i '/xxb_entry/d' zentaoxx/db/*.sql
|
||||
sed -i '/deviceToken/d' zentaoxx/db/*.sql
|
||||
sed -i '/deviceType/d' zentaoxx/db/*.sql
|
||||
sed -i "/fetch('push', 'pushMessage');/d" zentaoxx/module/im/control.php
|
||||
sed -i "s/marked\.html\.php';?>/marked\.html\.php';?>\n<div id='mainMenu' class='clearfix'><div class='btn-toolbar pull-left'><?php common::printAdminSubMenu('xuanxuan');?><\/div><\/div>/g" zentaoxx/module/client/view/checkupgrade.html.php
|
||||
sed -i '/var serverVersions/d' zentaoxx/module/client/js/checkupgrade.js
|
||||
sed -i '/var currentVersion/d' zentaoxx/module/client/js/checkupgrade.js
|
||||
|
||||
+2
-3
@@ -68,7 +68,6 @@ $filter->doc->alllibs = new stdclass();
|
||||
$filter->doc->objectlibs = new stdclass();
|
||||
$filter->doc->showfiles = new stdclass();
|
||||
$filter->doc->default = new stdclass();
|
||||
$filter->doc->showfiles = new stdclass();
|
||||
$filter->mail->ztcloud = new stdclass();
|
||||
$filter->mail->batchdelete = new stdclass();
|
||||
$filter->misc->checkupdate = new stdclass();
|
||||
@@ -76,6 +75,8 @@ $filter->file->download = new stdclass();
|
||||
$filter->product->browse = new stdclass();
|
||||
$filter->product->default = new stdclass();
|
||||
$filter->product->index = new stdclass();
|
||||
$filter->product->export = new stdclass();
|
||||
$filter->product->project = new stdclass();
|
||||
$filter->program->default = new stdclass();
|
||||
$filter->program->prjbrowse = new stdclass();
|
||||
$filter->program->pgmproject = new stdclass();
|
||||
@@ -83,8 +84,6 @@ $filter->program->prjbrowse = new stdclass();
|
||||
$filter->program->pgmbrowse = new stdclass();
|
||||
$filter->program->export = new stdclass();
|
||||
$filter->program->ajaxgetpgmdropmenu = new stdclass();
|
||||
$filter->product->export = new stdclass();
|
||||
$filter->product->project = new stdclass();
|
||||
$filter->project->default = new stdclass();
|
||||
$filter->project->story = new stdclass();
|
||||
$filter->project->export = new stdclass();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,91 @@
|
||||
2021-01-06 12.5.3
|
||||
完成的需求
|
||||
5855 实现年度总结的Bug数据区块
|
||||
5852 实现区块的鼠标hover态
|
||||
5842 年度总结实现按公司、部分、个人的范围统计
|
||||
5841 实现年度总结的用例数据区块
|
||||
5840 实现年度总结的需求数据区块
|
||||
5839 实现年度总结的任务数据区块
|
||||
5838 实现年度总结的产品数据区块
|
||||
5837 实现年度总结的迭代数据区块
|
||||
5836 实现年度总结截止今日的软件需求/任务/Bug状态分布区块
|
||||
5835 实现年度总结的能力雷达图区块
|
||||
5834 实现年度总结的贡献数据区块
|
||||
5833 年度总结的基础数据区块调整
|
||||
5726 组织权限维护中,请假模块增加个人年假的权限设置
|
||||
修复的Bug
|
||||
3724 新增客户端弹窗提示没有正常弹出
|
||||
3735 提bug页面黏贴淘口令导致页面布局显示错误
|
||||
3628 BUG页面-级别-P优先级自定义显示问题
|
||||
3629 项目-bug创建bug默认指派人没有正常显示出来
|
||||
3647 升级插件弹窗需优化
|
||||
3676 添加任务备注时,整个页面置灰
|
||||
3681 下载客户端登录时服务器默认地址错误
|
||||
3682 安装禅道时选择日语后无法再进行安装
|
||||
3683 测试单点击关闭之后变为了已完成状态
|
||||
3750 套件列表描述内容展示异常
|
||||
3762 任务起止日期设为必填项后填写0000-00-00可以保存
|
||||
3763 构建详情页切换标签后页面多余空白问题
|
||||
3770 自定义文档库文档 编辑功能 选择到手册目录下导致文档丢失
|
||||
|
||||
2020-12-18 12.5.2
|
||||
修复的Bug
|
||||
3744 搜索需求后报错
|
||||
3740 回收站中删除的构建任务对象类型和对象名称未正确显示
|
||||
3737 CNVD-C-2020-287511 CNVD-C-2020-286783 CNVD-C-2020-286963 禅道CMS存在命令执行漏洞(漏洞名称相同位置不同)
|
||||
3732 运维模块下的上线步骤,点击标题进入详情页,历史记录中的操作没有转换对应的语言项
|
||||
3730 组织用户的列表页面表头和展示内容排版样式不齐
|
||||
3725 linux一键安装包“Retart”改为“Restart”
|
||||
3722 用户需求上传附件没有显示在产品附件库中
|
||||
3720 版本移除关联的需求bug后数据库中存储的格式不一致
|
||||
3719 测试单无法修改所属产品
|
||||
3715 批量指派需求时输入框无输入进行搜索
|
||||
3714 分页功能数据计算错误
|
||||
3713 CNVD-C-2020-281405 禅道CMS存在命令执行漏洞
|
||||
3708 任务列表页面和任务详情页面子任务的操作按钮顺序不一致
|
||||
3707 我的地盘首页添加待办报错
|
||||
3704 编辑器中保存锚点时name丢失
|
||||
3703 版本条件搜索报错
|
||||
3701 用户没有项目访问权限,可以通过组织-用户看到相关信息
|
||||
3699 内禅--任务相关用例详情页底部报错
|
||||
3698 编辑任务页面设置必填项后父任务编辑无法正常保存
|
||||
3697 用例转bug时重现步骤必填识别错误
|
||||
3693 组织用户查看带减号的帐号信息跳转错误
|
||||
3692 草稿状态需求变更,由谁评审和指派给会清空
|
||||
3691 待办转任务时,待办的描述信息没有同步到任务中
|
||||
3690 集成中做代码评审生成的bug类型有误
|
||||
3689 测试单下的用例模块显示问题
|
||||
3688 批量编辑任务关闭时间没有更新
|
||||
3687 编辑任务手动设置的关闭时间没有时分秒自动保存的有时分秒
|
||||
3686 bug导出日期没有时分秒
|
||||
3685 报告详情页面和编辑页面统计数据显示不一致
|
||||
3684 需求细分页面字段展示错误
|
||||
3680 测试单列表页面显示问题
|
||||
3679 通知邮件中的链接地址与禅道中填写的不一致
|
||||
3678 关联bug页面ID显示问题
|
||||
3677 重新生成测试单时,测试轮次与之前选择的不一致
|
||||
3675 测试报告编辑页面和查看页面数据不一致
|
||||
3674 编辑模块修改所属产品下的某个分支未起效
|
||||
3669 S10 任务历史记录里记录了2次关闭操作
|
||||
3668 用例导出内容不正确
|
||||
3667 我的地盘-bug-指派给中没有显示指派给自己的bug
|
||||
3666 我的地盘我评审的需求中没有记录批量评审过的需求
|
||||
3660 项目主页工时信息统计不准确
|
||||
3659 QTVA-2020-1548464 禅道存在命令执行漏洞
|
||||
3658 CNVD-C-2020-224623 _关于禅道后台存在命令执行漏洞的情况通报
|
||||
3657 CNVD-C-2020-258606 _关于禅道CMS存在任意文件读取漏洞的情况通报
|
||||
3656 CNVD-C-2020-255650关于禅道最新开源版12.4.3及以下存在任意文件下载漏洞的情况通报
|
||||
3649 CNVD-2017-04121--青岛易软天创网络科技有限公司禅道项目管理软件后台存在设计缺陷漏洞
|
||||
3646 测试单中选择模块后用例无法正常显示
|
||||
3644 二次开发数据库中名称和实际功能名称不一致
|
||||
3642 测试单按复制测试单关联用例时展示数据不准确
|
||||
3640 bug激活历史记录不准确
|
||||
3636 批量编辑任务时指派人字段内容未显示
|
||||
3629 项目-bug创建bug默认指派人没有正常显示出来
|
||||
3627 任务模块显示错误
|
||||
3624 父任务状态显示不对
|
||||
3568 windows和linux一键安装包切换日语后页面未能正确跳转
|
||||
|
||||
2020-11-29 12.5.1
|
||||
修复的Bug
|
||||
3406 AppScan漏洞
|
||||
|
||||
@@ -365,7 +365,8 @@ class baseHelper
|
||||
}
|
||||
|
||||
/* Check decrypted password. Judge whether there is garbled code. */
|
||||
if(json_encode($decryptedPassword) === 'null') $decryptedPassword = '';
|
||||
$jsoned = json_encode($decryptedPassword);
|
||||
if($jsoned === 'null' or empty($jsoned)) $decryptedPassword = '';
|
||||
}
|
||||
if(empty($decryptedPassword)) $decryptedPassword = $password;
|
||||
|
||||
|
||||
@@ -259,12 +259,13 @@ class baseModel
|
||||
if(!empty($moduleExtPath['site'])) $extensionFile = $moduleExtPath['site'] . 'class/' . $extensionName . '.class.php';
|
||||
if(!isset($extensionFile) or !file_exists($extensionFile)) $extensionFile = $moduleExtPath['common'] . 'class/' . $extensionName . '.class.php';
|
||||
|
||||
/* 设置扩展类的名字。Set the extension class name. */
|
||||
$extensionClass = $extensionName . ucfirst($moduleName);
|
||||
if(isset($this->$extensionClass)) return $this->$extensionClass;
|
||||
|
||||
/* 载入父类。Try to import parent model file auto and then import the extension file. */
|
||||
if(!class_exists($moduleName . 'Model')) helper::import($this->app->getModulePath($this->appName, $moduleName) . 'model.php');
|
||||
if(!helper::import($extensionFile)) return false;
|
||||
|
||||
/* 设置扩展类的名字。Set the extension class name. */
|
||||
$extensionClass = $extensionName . ucfirst($moduleName);
|
||||
if(!class_exists($extensionClass)) return false;
|
||||
|
||||
/* 实例化扩展类。Create an instance of the extension class and return it. */
|
||||
|
||||
@@ -831,6 +831,7 @@ class baseRouter
|
||||
{
|
||||
$sessionName = $this->config->sessionVar;
|
||||
session_name($sessionName);
|
||||
session_set_cookie_params(0, $this->config->webRoot);
|
||||
if($this->config->customSession) session_save_path($this->getTmpRoot() . 'session');
|
||||
session_start();
|
||||
|
||||
|
||||
@@ -302,6 +302,7 @@ class control extends baseControl
|
||||
if(!isset($this->config->bizVersion)) return false;
|
||||
if(empty($_POST)) return false;
|
||||
|
||||
$flow = $this->dao->select('*')->from(TABLE_WORKFLOW)->where('module')->eq($this->moduleName)->fetch();
|
||||
$fields = $this->loadModel('workflowaction')->getFields($this->moduleName, $this->methodName);
|
||||
$layouts = $this->loadModel('workflowlayout')->getFields($this->moduleName, $this->methodName);
|
||||
$rules = $this->dao->select('*')->from(TABLE_WORKFLOWRULE)->orderBy('id_desc')->fetchAll('id');
|
||||
@@ -330,10 +331,29 @@ class control extends baseControl
|
||||
}
|
||||
elseif($rule->type == 'system' and isset($_POST[$field->field]))
|
||||
{
|
||||
$checkFunc = 'check' . $rule->rule;
|
||||
if(validater::$checkFunc($_POST[$field->field]) === false)
|
||||
$pass = true;
|
||||
if($rule->rule == 'unique')
|
||||
{
|
||||
if(!empty($_POST[$field->field]))
|
||||
{
|
||||
$sqlClass = new sql();
|
||||
$sql = "SELECT COUNT(*) AS count FROM $flow->table WHERE `$field->field` = " . $sqlClass->quote(fixer::input('post')->get($field->field));
|
||||
if(isset($_POST['id'])) $sql .= ' AND `id` != ' . (int)$_POST['id'];
|
||||
|
||||
$row = $this->dbh->query($sql)->fetch();
|
||||
if($row->count != 0) $pass = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$checkFunc = 'check' . $rule->rule;
|
||||
if(validater::$checkFunc($_POST[$field->field]) === false) $pass = false;
|
||||
}
|
||||
|
||||
if(!$pass)
|
||||
{
|
||||
$error = zget($this->lang->error, $rule->rule, '');
|
||||
if($rule->rule == 'unique') $error = sprintf($error, $field->name, $_POST[$field->field]);
|
||||
if($error) $error = sprintf($error, $field->name);
|
||||
if(empty($error)) $error = sprintf($this->lang->error->reg, $field->name, $rule->rule);
|
||||
|
||||
|
||||
@@ -0,0 +1,806 @@
|
||||
<?php
|
||||
/**
|
||||
* Builds a new captcha image
|
||||
* Uses the fingerprint parameter, if one is passed, to generate the same image
|
||||
*
|
||||
* @author Gregwar <g.passault@gmail.com>
|
||||
* @author Jeremy Livingston <jeremy.j.livingston@gmail.com>
|
||||
*/
|
||||
class captcha
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fingerprint = array();
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $useFingerprint = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $textColor = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $lineColor = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $backgroundColor = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $backgroundImages = array();
|
||||
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
protected $contents = null;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $phrase = null;
|
||||
|
||||
/**
|
||||
* @var PhraseBuilderInterface
|
||||
*/
|
||||
protected $builder;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $distortion = true;
|
||||
|
||||
/**
|
||||
* The maximum number of lines to draw in front of
|
||||
* the image. null - use default algorithm
|
||||
*/
|
||||
protected $maxFrontLines = null;
|
||||
|
||||
/**
|
||||
* The maximum number of lines to draw behind
|
||||
* the image. null - use default algorithm
|
||||
*/
|
||||
protected $maxBehindLines = null;
|
||||
|
||||
/**
|
||||
* The maximum angle of char
|
||||
*/
|
||||
protected $maxAngle = 8;
|
||||
|
||||
/**
|
||||
* The maximum offset of char
|
||||
*/
|
||||
protected $maxOffset = 5;
|
||||
|
||||
/**
|
||||
* Is the interpolation enabled ?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $interpolation = true;
|
||||
|
||||
/**
|
||||
* Ignore all effects
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $ignoreAllEffects = false;
|
||||
|
||||
/**
|
||||
* Allowed image types for the background images
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $allowedBackgroundImageTypes = array('image/png', 'image/jpeg', 'image/gif');
|
||||
|
||||
/**
|
||||
* The image contents
|
||||
*/
|
||||
public function getContents()
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disables the interpolation
|
||||
*
|
||||
* @param $interpolate bool True to enable, false to disable
|
||||
*
|
||||
* @return CaptchaBuilder
|
||||
*/
|
||||
public function setInterpolation($interpolate = true)
|
||||
{
|
||||
$this->interpolation = $interpolate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary dir, for OCR check
|
||||
*/
|
||||
public $tempDir = 'temp/';
|
||||
|
||||
public function __construct($phrase = null, PhraseBuilderInterface $builder = null)
|
||||
{
|
||||
if ($builder === null) {
|
||||
$this->builder = new PhraseBuilder;
|
||||
} else {
|
||||
$this->builder = $builder;
|
||||
}
|
||||
|
||||
$this->phrase = is_string($phrase) ? $phrase : $this->builder->build($phrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting the phrase
|
||||
*/
|
||||
public function setPhrase($phrase)
|
||||
{
|
||||
$this->phrase = (string) $phrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disable distortion
|
||||
*/
|
||||
public function setDistortion($distortion)
|
||||
{
|
||||
$this->distortion = (bool) $distortion;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMaxBehindLines($maxBehindLines)
|
||||
{
|
||||
$this->maxBehindLines = $maxBehindLines;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMaxFrontLines($maxFrontLines)
|
||||
{
|
||||
$this->maxFrontLines = $maxFrontLines;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMaxAngle($maxAngle)
|
||||
{
|
||||
$this->maxAngle = $maxAngle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMaxOffset($maxOffset)
|
||||
{
|
||||
$this->maxOffset = $maxOffset;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the captcha phrase
|
||||
*/
|
||||
public function getPhrase()
|
||||
{
|
||||
return $this->phrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given phrase is good
|
||||
*/
|
||||
public function testPhrase($phrase)
|
||||
{
|
||||
return ($this->builder->niceize($phrase) == $this->builder->niceize($this->getPhrase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiation
|
||||
*/
|
||||
public static function create($phrase = null)
|
||||
{
|
||||
return new self($phrase);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text color to use
|
||||
*/
|
||||
public function setTextColor($r, $g, $b)
|
||||
{
|
||||
$this->textColor = array($r, $g, $b);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the background color to use
|
||||
*/
|
||||
public function setBackgroundColor($r, $g, $b)
|
||||
{
|
||||
$this->backgroundColor = array($r, $g, $b);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLineColor($r, $g, $b)
|
||||
{
|
||||
$this->lineColor = array($r, $g, $b);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ignoreAllEffects value
|
||||
*
|
||||
* @param bool $ignoreAllEffects
|
||||
* @return CaptchaBuilder
|
||||
*/
|
||||
public function setIgnoreAllEffects($ignoreAllEffects)
|
||||
{
|
||||
$this->ignoreAllEffects = $ignoreAllEffects;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the list of background images to use (one image is randomly selected)
|
||||
*/
|
||||
public function setBackgroundImages(array $backgroundImages)
|
||||
{
|
||||
$this->backgroundImages = $backgroundImages;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw lines over the image
|
||||
*/
|
||||
protected function drawLine($image, $width, $height, $tcol = null)
|
||||
{
|
||||
if ($this->lineColor === null) {
|
||||
$red = $this->rand(100, 255);
|
||||
$green = $this->rand(100, 255);
|
||||
$blue = $this->rand(100, 255);
|
||||
} else {
|
||||
$red = $this->lineColor[0];
|
||||
$green = $this->lineColor[1];
|
||||
$blue = $this->lineColor[2];
|
||||
}
|
||||
|
||||
if ($tcol === null) {
|
||||
$tcol = imagecolorallocate($image, $red, $green, $blue);
|
||||
}
|
||||
|
||||
if ($this->rand(0, 1)) { // Horizontal
|
||||
$Xa = $this->rand(0, $width/2);
|
||||
$Ya = $this->rand(0, $height);
|
||||
$Xb = $this->rand($width/2, $width);
|
||||
$Yb = $this->rand(0, $height);
|
||||
} else { // Vertical
|
||||
$Xa = $this->rand(0, $width);
|
||||
$Ya = $this->rand(0, $height/2);
|
||||
$Xb = $this->rand(0, $width);
|
||||
$Yb = $this->rand($height/2, $height);
|
||||
}
|
||||
imagesetthickness($image, $this->rand(1, 3));
|
||||
imageline($image, $Xa, $Ya, $Xb, $Yb, $tcol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply some post effects
|
||||
*/
|
||||
protected function postEffect($image)
|
||||
{
|
||||
if (!function_exists('imagefilter')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->backgroundColor != null || $this->textColor != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Negate ?
|
||||
if ($this->rand(0, 1) == 0) {
|
||||
imagefilter($image, IMG_FILTER_NEGATE);
|
||||
}
|
||||
|
||||
// Edge ?
|
||||
if ($this->rand(0, 10) == 0) {
|
||||
imagefilter($image, IMG_FILTER_EDGEDETECT);
|
||||
}
|
||||
|
||||
// Contrast
|
||||
imagefilter($image, IMG_FILTER_CONTRAST, $this->rand(-50, 10));
|
||||
|
||||
// Colorize
|
||||
if ($this->rand(0, 5) == 0) {
|
||||
imagefilter($image, IMG_FILTER_COLORIZE, $this->rand(-80, 50), $this->rand(-80, 50), $this->rand(-80, 50));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the phrase on the image
|
||||
*/
|
||||
protected function writePhrase($image, $phrase, $font, $width, $height)
|
||||
{
|
||||
$length = mb_strlen($phrase);
|
||||
if ($length === 0) {
|
||||
return \imagecolorallocate($image, 0, 0, 0);
|
||||
}
|
||||
|
||||
// Gets the text size and start position
|
||||
$size = $width / $length - $this->rand(0, 3) - 1;
|
||||
$box = \imagettfbbox($size, 0, $font, $phrase);
|
||||
$textWidth = $box[2] - $box[0];
|
||||
$textHeight = $box[1] - $box[7];
|
||||
$x = ($width - $textWidth) / 2;
|
||||
$y = ($height - $textHeight) / 2 + $size;
|
||||
|
||||
if (!$this->textColor) {
|
||||
$textColor = array($this->rand(0, 150), $this->rand(0, 150), $this->rand(0, 150));
|
||||
} else {
|
||||
$textColor = $this->textColor;
|
||||
}
|
||||
$col = \imagecolorallocate($image, $textColor[0], $textColor[1], $textColor[2]);
|
||||
|
||||
// Write the letters one by one, with random angle
|
||||
for ($i=0; $i<$length; $i++) {
|
||||
$symbol = mb_substr($phrase, $i, 1);
|
||||
$box = \imagettfbbox($size, 0, $font, $symbol);
|
||||
$w = $box[2] - $box[0];
|
||||
$angle = $this->rand(-$this->maxAngle, $this->maxAngle);
|
||||
$offset = $this->rand(-$this->maxOffset, $this->maxOffset);
|
||||
\imagettftext($image, $size, $angle, $x, $y + $offset, $col, $font, $symbol);
|
||||
$x += $w;
|
||||
}
|
||||
|
||||
return $col;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to read the code against an OCR
|
||||
*/
|
||||
public function isOCRReadable()
|
||||
{
|
||||
if (!is_dir($this->tempDir)) {
|
||||
@mkdir($this->tempDir, 0755, true);
|
||||
}
|
||||
|
||||
$tempj = $this->tempDir . uniqid('captcha', true) . '.jpg';
|
||||
$tempp = $this->tempDir . uniqid('captcha', true) . '.pgm';
|
||||
|
||||
$this->save($tempj);
|
||||
shell_exec("convert $tempj $tempp");
|
||||
$value = trim(strtolower(shell_exec("ocrad $tempp")));
|
||||
|
||||
@unlink($tempj);
|
||||
@unlink($tempp);
|
||||
|
||||
return $this->testPhrase($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds while the code is readable against an OCR
|
||||
*/
|
||||
public function buildAgainstOCR($width = 150, $height = 40, $font = null, $fingerprint = null)
|
||||
{
|
||||
do {
|
||||
$this->build($width, $height, $font, $fingerprint);
|
||||
} while ($this->isOCRReadable());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the image
|
||||
*/
|
||||
public function build($width = 150, $height = 40, $font = null, $fingerprint = null)
|
||||
{
|
||||
if (null !== $fingerprint) {
|
||||
$this->fingerprint = $fingerprint;
|
||||
$this->useFingerprint = true;
|
||||
} else {
|
||||
$this->fingerprint = array();
|
||||
$this->useFingerprint = false;
|
||||
}
|
||||
|
||||
if ($font === null) {
|
||||
$font = __DIR__ . '/font/captcha'.$this->rand(0, 5).'.ttf';
|
||||
}
|
||||
|
||||
if (empty($this->backgroundImages)) {
|
||||
// if background images list is not set, use a color fill as a background
|
||||
$image = imagecreatetruecolor($width, $height);
|
||||
if ($this->backgroundColor == null) {
|
||||
$bg = imagecolorallocate($image, $this->rand(200, 255), $this->rand(200, 255), $this->rand(200, 255));
|
||||
} else {
|
||||
$color = $this->backgroundColor;
|
||||
$bg = imagecolorallocate($image, $color[0], $color[1], $color[2]);
|
||||
}
|
||||
$this->background = $bg;
|
||||
imagefill($image, 0, 0, $bg);
|
||||
} else {
|
||||
// use a random background image
|
||||
$randomBackgroundImage = $this->backgroundImages[rand(0, count($this->backgroundImages)-1)];
|
||||
|
||||
$imageType = $this->validateBackgroundImage($randomBackgroundImage);
|
||||
|
||||
$image = $this->createBackgroundImageFromType($randomBackgroundImage, $imageType);
|
||||
}
|
||||
|
||||
// Apply effects
|
||||
if (!$this->ignoreAllEffects) {
|
||||
$square = $width * $height;
|
||||
$effects = $this->rand($square/3000, $square/2000);
|
||||
|
||||
// set the maximum number of lines to draw in front of the text
|
||||
if ($this->maxBehindLines != null && $this->maxBehindLines > 0) {
|
||||
$effects = min($this->maxBehindLines, $effects);
|
||||
}
|
||||
|
||||
if ($this->maxBehindLines !== 0) {
|
||||
for ($e = 0; $e < $effects; $e++) {
|
||||
$this->drawLine($image, $width, $height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write CAPTCHA text
|
||||
$color = $this->writePhrase($image, $this->phrase, $font, $width, $height);
|
||||
|
||||
// Apply effects
|
||||
if (!$this->ignoreAllEffects) {
|
||||
$square = $width * $height;
|
||||
$effects = $this->rand($square/3000, $square/2000);
|
||||
|
||||
// set the maximum number of lines to draw in front of the text
|
||||
if ($this->maxFrontLines != null && $this->maxFrontLines > 0) {
|
||||
$effects = min($this->maxFrontLines, $effects);
|
||||
}
|
||||
|
||||
if ($this->maxFrontLines !== 0) {
|
||||
for ($e = 0; $e < $effects; $e++) {
|
||||
$this->drawLine($image, $width, $height, $color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Distort the image
|
||||
if ($this->distortion && !$this->ignoreAllEffects) {
|
||||
$image = $this->distort($image, $width, $height, $bg);
|
||||
}
|
||||
|
||||
// Post effects
|
||||
if (!$this->ignoreAllEffects) {
|
||||
$this->postEffect($image);
|
||||
}
|
||||
|
||||
$this->contents = $image;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Distorts the image
|
||||
*/
|
||||
public function distort($image, $width, $height, $bg)
|
||||
{
|
||||
$contents = imagecreatetruecolor($width, $height);
|
||||
$X = $this->rand(0, $width);
|
||||
$Y = $this->rand(0, $height);
|
||||
$phase = $this->rand(0, 10);
|
||||
$scale = 1.1 + $this->rand(0, 10000) / 30000;
|
||||
for ($x = 0; $x < $width; $x++) {
|
||||
for ($y = 0; $y < $height; $y++) {
|
||||
$Vx = $x - $X;
|
||||
$Vy = $y - $Y;
|
||||
$Vn = sqrt($Vx * $Vx + $Vy * $Vy);
|
||||
|
||||
if ($Vn != 0) {
|
||||
$Vn2 = $Vn + 4 * sin($Vn / 30);
|
||||
$nX = $X + ($Vx * $Vn2 / $Vn);
|
||||
$nY = $Y + ($Vy * $Vn2 / $Vn);
|
||||
} else {
|
||||
$nX = $X;
|
||||
$nY = $Y;
|
||||
}
|
||||
$nY = $nY + $scale * sin($phase + $nX * 0.2);
|
||||
|
||||
if ($this->interpolation) {
|
||||
$p = $this->interpolate(
|
||||
$nX - floor($nX),
|
||||
$nY - floor($nY),
|
||||
$this->getCol($image, floor($nX), floor($nY), $bg),
|
||||
$this->getCol($image, ceil($nX), floor($nY), $bg),
|
||||
$this->getCol($image, floor($nX), ceil($nY), $bg),
|
||||
$this->getCol($image, ceil($nX), ceil($nY), $bg)
|
||||
);
|
||||
} else {
|
||||
$p = $this->getCol($image, round($nX), round($nY), $bg);
|
||||
}
|
||||
|
||||
if ($p == 0) {
|
||||
$p = $bg;
|
||||
}
|
||||
|
||||
imagesetpixel($contents, $x, $y, $p);
|
||||
}
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the Captcha to a jpeg file
|
||||
*/
|
||||
public function save($filename, $quality = 90)
|
||||
{
|
||||
imagejpeg($this->contents, $filename, $quality);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the image GD
|
||||
*/
|
||||
public function getGd()
|
||||
{
|
||||
return $this->contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the image contents
|
||||
*/
|
||||
public function get($quality = 90)
|
||||
{
|
||||
ob_start();
|
||||
$this->output($quality);
|
||||
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the HTML inline base64
|
||||
*/
|
||||
public function inline($quality = 90)
|
||||
{
|
||||
return 'data:image/jpeg;base64,' . base64_encode($this->get($quality));
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the image
|
||||
*/
|
||||
public function output($quality = 90)
|
||||
{
|
||||
imagejpeg($this->contents, null, $quality);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getFingerprint()
|
||||
{
|
||||
return $this->fingerprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a random number or the next number in the
|
||||
* fingerprint
|
||||
*/
|
||||
protected function rand($min, $max)
|
||||
{
|
||||
if (!is_array($this->fingerprint)) {
|
||||
$this->fingerprint = array();
|
||||
}
|
||||
|
||||
if ($this->useFingerprint) {
|
||||
$value = current($this->fingerprint);
|
||||
next($this->fingerprint);
|
||||
} else {
|
||||
$value = mt_rand($min, $max);
|
||||
$this->fingerprint[] = $value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $x
|
||||
* @param $y
|
||||
* @param $nw
|
||||
* @param $ne
|
||||
* @param $sw
|
||||
* @param $se
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function interpolate($x, $y, $nw, $ne, $sw, $se)
|
||||
{
|
||||
list($r0, $g0, $b0) = $this->getRGB($nw);
|
||||
list($r1, $g1, $b1) = $this->getRGB($ne);
|
||||
list($r2, $g2, $b2) = $this->getRGB($sw);
|
||||
list($r3, $g3, $b3) = $this->getRGB($se);
|
||||
|
||||
$cx = 1.0 - $x;
|
||||
$cy = 1.0 - $y;
|
||||
|
||||
$m0 = $cx * $r0 + $x * $r1;
|
||||
$m1 = $cx * $r2 + $x * $r3;
|
||||
$r = (int) ($cy * $m0 + $y * $m1);
|
||||
|
||||
$m0 = $cx * $g0 + $x * $g1;
|
||||
$m1 = $cx * $g2 + $x * $g3;
|
||||
$g = (int) ($cy * $m0 + $y * $m1);
|
||||
|
||||
$m0 = $cx * $b0 + $x * $b1;
|
||||
$m1 = $cx * $b2 + $x * $b3;
|
||||
$b = (int) ($cy * $m0 + $y * $m1);
|
||||
|
||||
return ($r << 16) | ($g << 8) | $b;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $image
|
||||
* @param $x
|
||||
* @param $y
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getCol($image, $x, $y, $background)
|
||||
{
|
||||
$L = imagesx($image);
|
||||
$H = imagesy($image);
|
||||
if ($x < 0 || $x >= $L || $y < 0 || $y >= $H) {
|
||||
return $background;
|
||||
}
|
||||
|
||||
return imagecolorat($image, $x, $y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $col
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRGB($col)
|
||||
{
|
||||
return array(
|
||||
(int) ($col >> 16) & 0xff,
|
||||
(int) ($col >> 8) & 0xff,
|
||||
(int) ($col) & 0xff,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the background image path. Return the image type if valid
|
||||
*
|
||||
* @param string $backgroundImage
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function validateBackgroundImage($backgroundImage)
|
||||
{
|
||||
// check if file exists
|
||||
if (!file_exists($backgroundImage)) {
|
||||
$backgroundImageExploded = explode('/', $backgroundImage);
|
||||
$imageFileName = count($backgroundImageExploded) > 1? $backgroundImageExploded[count($backgroundImageExploded)-1] : $backgroundImage;
|
||||
|
||||
throw new Exception('Invalid background image: ' . $imageFileName);
|
||||
}
|
||||
|
||||
// check image type
|
||||
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
|
||||
$imageType = finfo_file($finfo, $backgroundImage);
|
||||
finfo_close($finfo);
|
||||
|
||||
if (!in_array($imageType, $this->allowedBackgroundImageTypes)) {
|
||||
throw new Exception('Invalid background image type! Allowed types are: ' . join(', ', $this->allowedBackgroundImageTypes));
|
||||
}
|
||||
|
||||
return $imageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create background image from type
|
||||
*
|
||||
* @param string $backgroundImage
|
||||
* @param string $imageType
|
||||
* @return resource
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function createBackgroundImageFromType($backgroundImage, $imageType)
|
||||
{
|
||||
switch ($imageType) {
|
||||
case 'image/jpeg':
|
||||
$image = imagecreatefromjpeg($backgroundImage);
|
||||
break;
|
||||
case 'image/png':
|
||||
$image = imagecreatefrompng($backgroundImage);
|
||||
break;
|
||||
case 'image/gif':
|
||||
$image = imagecreatefromgif($backgroundImage);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception('Not supported file type for background image!');
|
||||
break;
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random phrase
|
||||
*
|
||||
* @author Gregwar <g.passault@gmail.com>
|
||||
*/
|
||||
class PhraseBuilder
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $length;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $charset;
|
||||
/**
|
||||
* Constructs a PhraseBuilder with given parameters
|
||||
*/
|
||||
public function __construct($length = 5, $charset = 'abcdefghijklmnpqrstuvwxyz123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
{
|
||||
$this->length = $length;
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates random phrase of given length with given charset
|
||||
*/
|
||||
public function build($length = null, $charset = null)
|
||||
{
|
||||
if ($length !== null) {
|
||||
$this->length = $length;
|
||||
}
|
||||
if ($charset !== null) {
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
$phrase = '';
|
||||
$chars = str_split($this->charset);
|
||||
|
||||
for ($i = 0; $i < $this->length; $i++) {
|
||||
$phrase .= $chars[array_rand($chars)];
|
||||
}
|
||||
|
||||
return $phrase;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Niceize" a code
|
||||
*/
|
||||
public function niceize($str)
|
||||
{
|
||||
return self::doNiceize($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static helper to niceize
|
||||
*/
|
||||
public static function doNiceize($str)
|
||||
{
|
||||
return strtr(strtolower($str), '01', 'ol');
|
||||
}
|
||||
|
||||
/**
|
||||
* A static helper to compare
|
||||
*/
|
||||
public static function comparePhrases($str1, $str2)
|
||||
{
|
||||
return self::doNiceize($str1) === self::doNiceize($str2);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -95,6 +95,7 @@ $lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Eintrag';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
|
||||
/* 用来描述操作历史记录。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -95,6 +95,7 @@ $lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Entry';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -95,6 +95,7 @@ $lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Entrée';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
|
||||
/* 用来描述操作历史记录。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -95,6 +95,7 @@ $lang->action->objectTypes['stakeholder'] = 'Stakeholder';
|
||||
$lang->action->objectTypes['budget'] = 'Cost Estimate';
|
||||
$lang->action->objectTypes['entry'] = 'Entry';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = 'Job';
|
||||
|
||||
/* Used to describe operation history. */
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -95,6 +95,7 @@ $lang->action->objectTypes['stakeholder'] = '干系人';
|
||||
$lang->action->objectTypes['budget'] = '费用估算';
|
||||
$lang->action->objectTypes['entry'] = '应用';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = '构建';
|
||||
|
||||
/* 用来描述操作历史记录。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -95,6 +95,7 @@ $lang->action->objectTypes['stakeholder'] = '干係人';
|
||||
$lang->action->objectTypes['budget'] = '費用估算';
|
||||
$lang->action->objectTypes['entry'] = '應用';
|
||||
$lang->action->objectTypes['webhook'] = 'Webhook';
|
||||
$lang->action->objectTypes['job'] = '構建';
|
||||
|
||||
/* 用來描述操作歷史記錄。*/
|
||||
$lang->action->desc = new stdclass();
|
||||
|
||||
@@ -54,13 +54,14 @@ $lang->admin->bind->caption = '关联社区帐号';
|
||||
$lang->admin->bind->success = "关联账户成功";
|
||||
|
||||
$lang->admin->safe = new stdclass();
|
||||
$lang->admin->safe->common = '安全策略';
|
||||
$lang->admin->safe->set = '密码安全设置';
|
||||
$lang->admin->safe->password = '密码安全';
|
||||
$lang->admin->safe->weak = '常用弱口令';
|
||||
$lang->admin->safe->reason = '类型';
|
||||
$lang->admin->safe->checkWeak = '弱口令扫描';
|
||||
$lang->admin->safe->changeWeak = '修改弱口令密码';
|
||||
$lang->admin->safe->common = '安全策略';
|
||||
$lang->admin->safe->set = '密码安全设置';
|
||||
$lang->admin->safe->password = '密码安全';
|
||||
$lang->admin->safe->weak = '常用弱口令';
|
||||
$lang->admin->safe->reason = '类型';
|
||||
$lang->admin->safe->checkWeak = '弱口令扫描';
|
||||
$lang->admin->safe->changeWeak = '修改弱口令密码';
|
||||
$lang->admin->safe->loginCaptcha = '登录使用验证码';
|
||||
$lang->admin->safe->modifyPasswordFirstLogin = '首次登录修改密码';
|
||||
|
||||
$lang->admin->safe->modeList[0] = '不检查';
|
||||
@@ -79,5 +80,8 @@ $lang->admin->safe->reasonList['birthday'] = '与生日相同';
|
||||
$lang->admin->safe->modifyPasswordList[1] = '必须修改';
|
||||
$lang->admin->safe->modifyPasswordList[0] = '不强制';
|
||||
|
||||
$lang->admin->safe->loginCaptchaList[1] = '是';
|
||||
$lang->admin->safe->loginCaptchaList[0] = '否';
|
||||
|
||||
$lang->admin->safe->noticeMode = '系统会在登录、创建和修改用户、修改密码的时候检查用户口令。';
|
||||
$lang->admin->safe->noticeStrong = '密码长度越长,含有大写字母或数字或特殊符号越多,密码字母越不重复,安全度越强!';
|
||||
|
||||
@@ -47,6 +47,10 @@
|
||||
<th><?php echo $lang->admin->safe->modifyPasswordFirstLogin?></th>
|
||||
<td colspan='2'><?php echo html::radio('modifyPasswordFirstLogin', $lang->admin->safe->modifyPasswordList, isset($config->safe->modifyPasswordFirstLogin) ? $config->safe->modifyPasswordFirstLogin : 0)?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?php echo $lang->admin->safe->loginCaptcha?></th>
|
||||
<td colspan='2'><?php echo html::radio('loginCaptcha', $lang->admin->safe->loginCaptchaList, isset($config->safe->loginCaptcha) ? $config->safe->loginCaptcha : 0)?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan='3' class='text-center form-actions'>
|
||||
<?php echo html::submitButton();?>
|
||||
|
||||
@@ -738,6 +738,7 @@ class bug extends control
|
||||
$this->view->stories = $bug->project ? $this->story->getProjectStoryPairs($bug->project) : $this->story->getProductStoryPairs($bug->product, $bug->branch);
|
||||
$this->view->branches = $this->session->currentProductType == 'normal' ? array() : $this->loadModel('branch')->getPairs($bug->product);
|
||||
$this->view->tasks = $this->task->getProjectTaskPairs($bug->project);
|
||||
$this->view->testtasks = $this->loadModel('testtask')->getPairs($bug->product, $bug->project, $bug->testtask);
|
||||
$this->view->users = $this->user->getPairs('nodeleted', "$bug->assignedTo,$bug->resolvedBy,$bug->closedBy,$bug->openedBy");
|
||||
$this->view->openedBuilds = $openedBuilds;
|
||||
$this->view->resolvedBuilds = array('' => '') + $openedBuilds + $oldResolvedBuild;
|
||||
|
||||
@@ -20,6 +20,7 @@ td.delayed{color:#fff; background: #e84e0f!important;}
|
||||
.dropdown-list > li > a:focus {color: #1a4f85;text-decoration: none;background-color: #ddd;}
|
||||
|
||||
th.c-confirmed {text-align: center;}
|
||||
.c-severity{overflow: hidden; white-space: nowrap;}
|
||||
.c-id {text-overflow:ellipsis; white-space:nowrap;}
|
||||
|
||||
.body-modal #mainMenu>.btn-toolbar {width: auto;}
|
||||
|
||||
+28
-14
@@ -4,19 +4,6 @@ $(function()
|
||||
var flow = window.flow;
|
||||
|
||||
$('#subNavbar a[data-toggle=dropdown]').parent().addClass('dropdown dropdown-hover');
|
||||
if(page == 'create')
|
||||
{
|
||||
var productID = $('#product').val();
|
||||
var moduleID = $('#module').val();
|
||||
var assignedto = $('#assignedTo').val();
|
||||
changeProductConfirmed = true;
|
||||
oldStoryID = $('#story').val() || 0;
|
||||
oldProjectID = 0;
|
||||
oldOpenedBuild = '';
|
||||
oldTaskID = $('#oldTaskID').val() || 0;
|
||||
if(!assignedto) setAssignedTo(moduleID, productID);
|
||||
notice();
|
||||
}
|
||||
|
||||
if(page == 'create' || page == 'edit' || page == 'assignedto' || page == 'confirmbug')
|
||||
{
|
||||
@@ -72,6 +59,7 @@ function loadAll(productID)
|
||||
loadProductBuilds(productID);
|
||||
loadProductplans(productID);
|
||||
loadProductStories(productID);
|
||||
loadTestTasks(productID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,12 +315,14 @@ function loadProjectRelated(projectID)
|
||||
loadProjectStories(projectID);
|
||||
loadProjectBuilds(projectID);
|
||||
loadAssignedTo(projectID);
|
||||
loadTestTasks($('#product').val(), projectID);
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#taskIdBox').innerHTML = '<select id="task"></select>'; // Reset the task.
|
||||
loadProductStories($('#product').val());
|
||||
loadProductBuilds($('#product').val());
|
||||
loadTestTasks($('#product').val());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,7 +460,7 @@ var oldAssignedTo = $("#assignedTo").find("option:selected").val();
|
||||
*/
|
||||
function loadAssignedTo(projectID, selectedUser)
|
||||
{
|
||||
selectedUser = (typeof selectedUser == undefined) ? '' : $('#assignedTo').val();
|
||||
selectedUser = (typeof(selectedUser) == 'undefined') ? '' : $('#assignedTo').val();
|
||||
link = createLink('bug', 'ajaxLoadAssignedTo', 'projectID=' + projectID + '&selectedUser=' + selectedUser);
|
||||
$.get(link, function(data)
|
||||
{
|
||||
@@ -484,6 +474,30 @@ function loadAssignedTo(projectID, selectedUser)
|
||||
});
|
||||
}
|
||||
|
||||
var oldTestTaskTitle = $("#testtask").find("option:selected").text();
|
||||
var oldTestTask = $("#testtask").find("option:selected").val();
|
||||
|
||||
/**
|
||||
* Load test tasks.
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadTestTasks(productID, projectID)
|
||||
{
|
||||
if(typeof(projectID) == 'undefined') projectID = 0;
|
||||
link = createLink('testtask', 'ajaxGetTestTasks', 'productID=' + productID + '&projectID=' + projectID);
|
||||
$.get(link, function(data)
|
||||
{
|
||||
var defaultOption = '<option title="' + oldTestTaskTitle + '" value="' + oldTestTask + '" selected="selected">' + oldTestTaskTitle + '</option>';
|
||||
$('#testtaskBox').html(data);
|
||||
$('#testtask').append(defaultOption);
|
||||
$('#testtask').chosen();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* notice for create build.
|
||||
*
|
||||
|
||||
@@ -87,7 +87,19 @@ function setAssignedTo(moduleID, productID)
|
||||
|
||||
$(function()
|
||||
{
|
||||
var productID = $('#product').val();
|
||||
var moduleID = $('#module').val();
|
||||
var assignedto = $('#assignedTo').val();
|
||||
changeProductConfirmed = true;
|
||||
oldStoryID = $('#story').val() || 0;
|
||||
oldProjectID = 0;
|
||||
oldOpenedBuild = '';
|
||||
oldTaskID = $('#oldTaskID').val() || 0;
|
||||
|
||||
if($('#project').val()) loadProjectRelated($('#project').val());
|
||||
if(!assignedto) setTimeout(function(){setAssignedTo(moduleID, productID)}, 500);
|
||||
notice();
|
||||
|
||||
|
||||
$('[data-toggle=tooltip]').tooltip();
|
||||
|
||||
|
||||
@@ -334,9 +334,9 @@ class bugModel extends model
|
||||
public function checkDelayBug($bug)
|
||||
{
|
||||
// Delayed or not?.
|
||||
if($bug->deadline != '0000-00-00')
|
||||
if(!helper::isZeroDate($bug->deadline))
|
||||
{
|
||||
if($bug->resolvedDate and substr($bug->resolvedDate, 0, 10) != '0000-00-00')
|
||||
if($bug->resolvedDate and !helper::isZeroDate($bug->resolvedDate))
|
||||
{
|
||||
$delay = helper::diffDate(substr($bug->resolvedDate, 0, 10), $bug->deadline);
|
||||
}
|
||||
@@ -1339,7 +1339,6 @@ class bugModel extends model
|
||||
->beginIF($projectID)->andWhere('t1.PRJ')->eq($projectID)->fi()
|
||||
->beginIF($type != 'closedBy' and $this->app->moduleName == 'block')->andWhere('t1.status')->ne('closed')->fi()
|
||||
->beginIF($type != 'all')->andWhere("t1.`$type`")->eq($account)->fi()
|
||||
->beginIF($this->app->rawMethod == 'contribute')->andWhere("t1.status")->in('resolved,closed')->fi()
|
||||
->orderBy($orderBy)
|
||||
->beginIF($limit > 0)->limit($limit)->fi()
|
||||
->page($pager)
|
||||
@@ -2303,8 +2302,8 @@ class bugModel extends model
|
||||
if(strpos($bugQuery, $allBranch) !== false) $bugQuery = str_replace($allBranch, '1', $bugQuery);
|
||||
|
||||
/* Fix bug #2878. */
|
||||
if(strpos($bugQuery, '`resolvedDate`') !== false) $bugQuery .= " AND `resolvedDate` != '0000-00-00 00:00:00'";
|
||||
if(strpos($bugQuery, '`closedDate`') !== false) $bugQuery .= " AND `closedDate` != '0000-00-00 00:00:00'";
|
||||
if(strpos($bugQuery, ' `resolvedDate` ') !== false) $bugQuery = str_replace(' `resolvedDate` ', " `resolvedDate` != '0000-00-00 00:00:00' AND `resolvedDate` ", $bugQuery);
|
||||
if(strpos($bugQuery, ' `closedDate` ') !== false) $bugQuery = str_replace(' `closedDate` ', " `closedDate` != '0000-00-00 00:00:00' AND `closedDate` ", $bugQuery);
|
||||
|
||||
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where($bugQuery)
|
||||
->beginIF(!$this->app->user->admin)->andWhere('project')->in('0,' . $this->app->user->view->projects)->fi()
|
||||
@@ -2522,13 +2521,15 @@ class bugModel extends model
|
||||
}
|
||||
break;
|
||||
case 'severity':
|
||||
$severityValue = zget($this->lang->bug->severityList, $bug->severity);
|
||||
$hasCustomSeverity = !is_numeric($severityValue);
|
||||
if($hasCustomSeverity)
|
||||
{
|
||||
echo "<span class='label-severity-custom' data-severity='{$bug->severity}' title='" . zget($this->lang->bug->severityList, $bug->severity) . "'>" . zget($this->lang->bug->severityList, $bug->severity) . "</span>";
|
||||
echo "<span class='label-severity-custom' data-severity='{$bug->severity}' title='" . $severityValue . "'>" . $severityValue . "</span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "<span class='label-severity' data-severity='{$bug->severity}' title='" . zget($this->lang->bug->severityList, $bug->severity) . "'></span>";
|
||||
echo "<span class='label-severity' data-severity='{$bug->severity}' title='" . $severityValue . "'></span>";
|
||||
}
|
||||
break;
|
||||
case 'pri':
|
||||
|
||||
@@ -251,26 +251,29 @@ js::set('oldResolvedBuild' , $bug->resolvedBuild);
|
||||
<th class='thWidth'><?php echo $lang->bug->linkBug;?></th>
|
||||
<td><?php echo html::a($this->createLink('bug', 'linkBugs', "bugID=$bug->id", '', true), $lang->bug->linkBugs, '', "class='text-primary' data-toggle='modal' data-type='iframe' data-width='95%'");?></td>
|
||||
</tr>
|
||||
<?php if(isset($bug->linkBugTitles)):?>
|
||||
<tr>
|
||||
<th></th>
|
||||
<td>
|
||||
<ul class='list-unstyled'>
|
||||
<?php
|
||||
if(isset($bug->linkBugTitles))
|
||||
foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle)
|
||||
{
|
||||
foreach($bug->linkBugTitles as $linkBugID => $linkBugTitle)
|
||||
{
|
||||
echo "<li><div class='checkbox-primary'>";
|
||||
echo "<input type='checkbox' checked='checked' name='linkBug[]' value=$linkBugID />";
|
||||
echo "<label>#{$linkBugID} {$linkBugTitle}</label>";
|
||||
echo '</div></li>';
|
||||
}
|
||||
echo "<li><div class='checkbox-primary'>";
|
||||
echo "<input type='checkbox' checked='checked' name='linkBug[]' value=$linkBugID />";
|
||||
echo "<label>#{$linkBugID} {$linkBugTitle}</label>";
|
||||
echo '</div></li>';
|
||||
}
|
||||
?>
|
||||
<span id='linkBugsBox'></span>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th><?php echo $lang->bug->testtask;?></th>
|
||||
<td id='testtaskBox'><?php echo html::select('testtask', $testtasks, $bug->testtask, 'class="form-control chosen"');?></td>
|
||||
</tr>
|
||||
<?php if($bug->case):?>
|
||||
<tr>
|
||||
<th><?php echo $lang->bug->fromCase;?></th>
|
||||
|
||||
@@ -347,16 +347,15 @@ class build extends control
|
||||
{
|
||||
$builds = $this->build->getExecutionBuildPairs($projectID, $productID, $branch, 'noempty,notrunk');
|
||||
if($isJsonView) die(json_encode($builds));
|
||||
else
|
||||
|
||||
if(empty($builds))
|
||||
{
|
||||
if(empty($builds))
|
||||
{
|
||||
echo html::a($this->createLink('build', 'create', "projectID=$projectID&productID=$productID", '', $onlybody = true), $this->lang->build->create, '', "data-toggle='modal' data-type='iframe'");
|
||||
echo ' ';
|
||||
die(html::a("javascript:loadProjectBuilds($projectID)", $this->lang->refresh));
|
||||
}
|
||||
die(html::select('build', $builds, $build, "class='form-control'"));
|
||||
$html = html::a($this->createLink('build', 'create', "projectID=$projectID&productID=$productID", '', $onlybody = true), $this->lang->build->create, '', "data-toggle='modal' data-type='iframe'");
|
||||
$html .= ' ';
|
||||
$html .= html::a("javascript:loadProjectBuilds($projectID)", $this->lang->refresh);
|
||||
die($html);
|
||||
}
|
||||
die(html::select('build', $builds, $build, "class='form-control'"));
|
||||
}
|
||||
if($varName == 'dropdownList')
|
||||
{
|
||||
|
||||
@@ -228,6 +228,7 @@ class buildModel extends model
|
||||
* @param int $executionID
|
||||
* @param int $productID
|
||||
* @param string $params noempty|notrunk, can be a set of them
|
||||
* @param int $buildID
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -507,7 +507,7 @@ $lang->projectrelease->menu = new stdclass();
|
||||
$lang->report = new stdclass();
|
||||
$lang->report->menu = new stdclass();
|
||||
|
||||
$lang->report->menu->annual = array('link' => 'Annual Summary|report|annualData', 'target' => '_blank');
|
||||
$lang->report->menu->annual = array('link' => 'Annual Summary|report|annualData|year=&dept=&userID=' . (isset($_SESSION['user']) ? zget($_SESSION['user'], 'id', 0) : 0), 'target' => '_blank');
|
||||
$lang->report->menu->product = array('link' => $lang->productCommon . '|report|productsummary');
|
||||
$lang->report->menu->prj = array('link' => $lang->executionCommon . '|report|projectdeviation');
|
||||
$lang->report->menu->test = array('link' => 'Test|report|bugcreate', 'alias' => 'bugassign');
|
||||
|
||||
@@ -507,7 +507,7 @@ $lang->projectrelease->menu = new stdclass();
|
||||
$lang->report = new stdclass();
|
||||
$lang->report->menu = new stdclass();
|
||||
|
||||
$lang->report->menu->annual = array('link' => 'Annual Summary|report|annualData', 'target' => '_blank');
|
||||
$lang->report->menu->annual = array('link' => 'Annual Summary|report|annualData|year=&dept=&userID=' . (isset($_SESSION['user']) ? zget($_SESSION['user'], 'id', 0) : 0), 'target' => '_blank');
|
||||
$lang->report->menu->product = array('link' => $lang->productCommon . '|report|productsummary');
|
||||
$lang->report->menu->prj = array('link' => $lang->executionCommon . '|report|projectdeviation');
|
||||
$lang->report->menu->test = array('link' => 'Request|report|bugcreate', 'alias' => 'bugassign');
|
||||
|
||||
@@ -507,7 +507,7 @@ $lang->projectrelease->menu = new stdclass();
|
||||
$lang->report = new stdclass();
|
||||
$lang->report->menu = new stdclass();
|
||||
|
||||
$lang->report->menu->annual = array('link' => 'Annual Summary|report|annualData', 'target' => '_blank');
|
||||
$lang->report->menu->annual = array('link' => 'Annual Summary|report|annualData|year=&dept=&userID=' . (isset($_SESSION['user']) ? zget($_SESSION['user'], 'id', 0) : 0), 'target' => '_blank');
|
||||
$lang->report->menu->product = array('link' => $lang->productCommon . '|report|productsummary');
|
||||
$lang->report->menu->prj = array('link' => $lang->executionCommon . '|report|projectdeviation');
|
||||
$lang->report->menu->test = array('link' => 'Recette|report|bugcreate', 'alias' => 'bugassign');
|
||||
|
||||
@@ -507,7 +507,7 @@ $lang->projectrelease->menu = new stdclass();
|
||||
$lang->report = new stdclass();
|
||||
$lang->report->menu = new stdclass();
|
||||
|
||||
$lang->report->menu->annual = array('link' => 'Tóm tắt năm|report|annualData', 'target' => '_blank');
|
||||
$lang->report->menu->annual = array('link' => 'Tóm tắt năm|report|annualData|year=&dept=&userID=' . (isset($_SESSION['user']) ? zget($_SESSION['user'], 'id', 0) : 0), 'target' => '_blank');
|
||||
$lang->report->menu->product = array('link' => $lang->productCommon . '|report|productsummary');
|
||||
$lang->report->menu->prj = array('link' => $lang->executionCommon . '|report|projectdeviation');
|
||||
$lang->report->menu->test = array('link' => 'Yêu cầu|report|bugcreate', 'alias' => 'bugassign');
|
||||
|
||||
@@ -183,7 +183,7 @@ $lang->product->menu->list = array('link' => $lang->productCommon . '|product|al
|
||||
$lang->product->viewMenu = new stdclass();
|
||||
$lang->product->viewMenu->requirement = array('link' => "$lang->URCommon|product|browse|productID=%s&branch=&browseType=unclosed¶m=0&storyType=requirement", 'alias' => 'batchedit', 'subModule' => 'story');
|
||||
$lang->product->viewMenu->story = array('link' => "$lang->SRCommon|product|browse|productID=%s", 'alias' => 'batchedit', 'subModule' => 'story');
|
||||
$lang->product->viewMenu->track = array('link' => "跟踪矩阵|story|track|productID=%s");
|
||||
$lang->product->viewMenu->track = array('link' => "矩阵|story|track|productID=%s");
|
||||
$lang->product->viewMenu->plan = array('link' => "计划|productplan|browse|productID=%s", 'subModule' => 'productplan');
|
||||
$lang->product->viewMenu->release = array('link' => '发布|release|browse|productID=%s', 'subModule' => 'release');
|
||||
$lang->product->viewMenu->roadmap = '路线图|product|roadmap|productID=%s';
|
||||
@@ -507,7 +507,7 @@ $lang->projectrelease->menu = new stdclass();
|
||||
$lang->report = new stdclass();
|
||||
$lang->report->menu = new stdclass();
|
||||
|
||||
$lang->report->menu->annual = array('link' => '年度总结|report|annualData', 'target' => '_blank');
|
||||
$lang->report->menu->annual = array('link' => '年度总结|report|annualData|year=&dept=&userID=' . (isset($_SESSION['user']) ? zget($_SESSION['user'], 'id', 0) : 0), 'target' => '_blank');
|
||||
$lang->report->menu->product = array('link' => $lang->productCommon . '|report|productsummary');
|
||||
$lang->report->menu->prj = array('link' => $lang->executionCommon . '|report|projectdeviation');
|
||||
$lang->report->menu->test = array('link' => '测试|report|bugcreate', 'alias' => 'bugassign');
|
||||
|
||||
@@ -183,7 +183,7 @@ $lang->product->menu->list = array('link' => $lang->productCommon . '|product|al
|
||||
$lang->product->viewMenu = new stdclass();
|
||||
$lang->product->viewMenu->requirement = array('link' => "$lang->URCommon|product|browse|productID=%s&branch=&browseType=unclosed¶m=0&storyType=requirement", 'alias' => 'batchedit', 'subModule' => 'story');
|
||||
$lang->product->viewMenu->story = array('link' => "$lang->SRCommon|product|browse|productID=%s", 'alias' => 'batchedit', 'subModule' => 'story');
|
||||
$lang->product->viewMenu->track = array('link' => "跟蹤矩陣|story|track|productID=%s");
|
||||
$lang->product->viewMenu->track = array('link' => "矩陣|story|track|productID=%s");
|
||||
$lang->product->viewMenu->plan = array('link' => "計劃|productplan|browse|productID=%s", 'subModule' => 'productplan');
|
||||
$lang->product->viewMenu->release = array('link' => '發佈|release|browse|productID=%s', 'subModule' => 'release');
|
||||
$lang->product->viewMenu->roadmap = '路線圖|product|roadmap|productID=%s';
|
||||
@@ -507,7 +507,7 @@ $lang->projectrelease->menu = new stdclass();
|
||||
$lang->report = new stdclass();
|
||||
$lang->report->menu = new stdclass();
|
||||
|
||||
$lang->report->menu->annual = array('link' => '年度總結|report|annualData', 'target' => '_blank');
|
||||
$lang->report->menu->annual = array('link' => '年度總結|report|annualData|year=&dept=&userID=' . (isset($_SESSION['user']) ? zget($_SESSION['user'], 'id', 0) : 0), 'target' => '_blank');
|
||||
$lang->report->menu->product = array('link' => $lang->productCommon . '|report|productsummary');
|
||||
$lang->report->menu->prj = array('link' => $lang->executionCommon . '|report|projectdeviation');
|
||||
$lang->report->menu->test = array('link' => '測試|report|bugcreate', 'alias' => 'bugassign');
|
||||
|
||||
@@ -164,13 +164,14 @@ class commonModel extends model
|
||||
*/
|
||||
public function isOpenMethod($module, $method)
|
||||
{
|
||||
if($module == 'user' and strpos('login|logout|deny|reset', $method) !== false) return true;
|
||||
if($module == 'user' and strpos('login|logout|deny|reset|refreshrandom', $method) !== false) return true;
|
||||
if($module == 'api' and $method == 'getsessionid') return true;
|
||||
if($module == 'misc' and $method == 'checktable') return true;
|
||||
if($module == 'misc' and $method == 'qrcode') return true;
|
||||
if($module == 'misc' and $method == 'about') return true;
|
||||
if($module == 'misc' and $method == 'checkupdate') return true;
|
||||
if($module == 'misc' and $method == 'ping') return true;
|
||||
if($module == 'misc' and $method == 'captcha') return true;
|
||||
if($module == 'sso' and $method == 'login') return true;
|
||||
if($module == 'sso' and $method == 'logout') return true;
|
||||
if($module == 'sso' and $method == 'bind') return true;
|
||||
|
||||
@@ -55,7 +55,7 @@ js::set('confirmDelete', $lang->user->confirmDelete);
|
||||
</div>
|
||||
</div>
|
||||
<div class='main-col'>
|
||||
<div class="cell" id="queryBox" data-module='user'></div>
|
||||
<div class="cell<?php if($type == 'bysearch') echo ' show';?>" id="queryBox" data-module='user'></div>
|
||||
<form class='main-table table-user' data-ride='table' action='<?php echo $this->createLink('user', 'batchEdit', "deptID=$deptID")?>' method='post' id='userListForm'>
|
||||
<?php $canBatchEdit = common::hasPriv('user', 'batchEdit');?>
|
||||
<table class='table has-sort-head' id='userList'>
|
||||
|
||||
@@ -136,7 +136,7 @@ class cronModel extends model
|
||||
if(empty($this->config->global->cron)) return false;
|
||||
|
||||
$lastTime = $this->getLastTime();
|
||||
if($lastTime == '0000-00-00 00:00:00' or ((time() - strtotime($lastTime)) > $this->config->cron->maxRunTime)) return true;
|
||||
if(helper::isZeroDate($lastTime) or ((time() - strtotime($lastTime)) > $this->config->cron->maxRunTime)) return true;
|
||||
if(!isset($this->config->cron->run->status)) return true;
|
||||
if($this->config->cron->run->status == 'stop') return true;
|
||||
|
||||
|
||||
@@ -405,7 +405,7 @@ class custom extends control
|
||||
* @return void
|
||||
*/
|
||||
public function browseStoryConcept()
|
||||
{
|
||||
{
|
||||
/* Process menu.*/
|
||||
$this->app->loadLang('custom');
|
||||
$this->lang->custom->menu = $this->lang->subject->menu;
|
||||
@@ -475,24 +475,23 @@ class custom extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete story concept.
|
||||
* @param int $key
|
||||
*
|
||||
* Set story concept.
|
||||
*
|
||||
* @param int $key
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setDefaultConcept($key = 0)
|
||||
{
|
||||
$this->loadModel('setting')->setItem('system.custom.URSR', $key);
|
||||
|
||||
die(js::locate(inlink('browseStoryConcept'), 'parent'));
|
||||
die(js::reload('parent'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete story concept.
|
||||
*
|
||||
* @param int $key
|
||||
* @param string $confirm yse|no
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
|
||||
@@ -462,7 +462,7 @@ class doc extends control
|
||||
$this->view->doc = $doc;
|
||||
$this->view->moduleOptionMenu = $this->tree->getOptionMenu($libID, 'doc', $startModuleID = 0);
|
||||
$this->view->type = $type;
|
||||
$this->view->libs = $this->doc->getLibs($type = 'all', $extra = 'withObject');
|
||||
$this->view->libs = $this->doc->getLibs('all', $extra = 'withObject|noBook');
|
||||
$this->view->groups = $this->loadModel('group')->getPairs();
|
||||
$this->view->users = $this->user->getPairs('noletter|noclosed|nodeleted', $doc->users);
|
||||
$this->display();
|
||||
|
||||
@@ -145,7 +145,7 @@ class docModel extends model
|
||||
* @param string $extra
|
||||
* @param string $appendLibs
|
||||
* @access public
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
public function getLibs($type = '', $extra = '', $appendLibs = '')
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<td class="c-name" title="<?php echo $doc->title?>"><?php echo $doc->title;?></td>
|
||||
<td class="c-num text-right"><?php echo $doc->fileSize ? $doc->fileSize : '-';?></td>
|
||||
<td class="c-user"><?php echo zget($users, $doc->addedBy);?></td>
|
||||
<td class="c-datetime"><?php echo $doc->editedDate == '0000-00-00 00:00:00' ? formatTime($doc->addedDate, 'Y-m-d') : formatTime($doc->editedDate, 'Y-m-d');?></td>
|
||||
<td class="c-datetime"><?php echo helper::isZeroDate($doc->editedDate) ? formatTime($doc->addedDate, 'Y-m-d') : formatTime($doc->editedDate, 'Y-m-d');?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
|
||||
@@ -895,7 +895,7 @@ class extensionModel extends model
|
||||
$days = isset($order->days) ? $order->days : 0;
|
||||
if($order->type == 'demo') $days = 31;
|
||||
if($order->type == 'year') $days = 365;
|
||||
$startDate = $order->paidDate != '0000-00-00 00:00:00' ? $order->paidDate : $order->createdDate;
|
||||
$startDate = !helper::isZeroDate($order->paidDate) ? $order->paidDate : $order->createdDate;
|
||||
if($days) $expiredDate = date('Y-m-d', strtotime($startDate) + $days * 24 * 3600);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
if($extension->status == 'installed' and !empty($extension->upgradeLink))
|
||||
{
|
||||
echo html::a($extension->upgradeLink, $lang->extension->upgrade, '', "class='btn iframe'");
|
||||
echo html::a($extension->upgradeLink, $lang->extension->upgrade, '', "class='btn iframe' data-height='500px'");
|
||||
}
|
||||
|
||||
if($extension->type != 'patch')
|
||||
|
||||
@@ -568,7 +568,7 @@ class fileModel extends model
|
||||
|
||||
$content = file_get_contents($fileName);
|
||||
/* Fix bug #890. */
|
||||
$content = str_replace(array("\r\n","\r"), "\n", $content);
|
||||
$content = str_replace(array("\r\n", "\r"), "\n", $content);
|
||||
$lines = explode("\n", $content);
|
||||
|
||||
$col = -1;
|
||||
@@ -576,7 +576,6 @@ class fileModel extends model
|
||||
$data = array();
|
||||
foreach($lines as $line)
|
||||
{
|
||||
$line = trim($line);
|
||||
$markNum = substr_count($line, '"') - substr_count($line, '\"');
|
||||
if(substr($line, -1) != ',' and (($markNum % 2 == 1 and $col != -1) or ($markNum % 2 == 0 and substr($line, -2) != ',"' and $col == -1))) $line .= ',';
|
||||
$line = str_replace(',"",', ',,', $line);
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
}
|
||||
return 'doc';
|
||||
}
|
||||
if(moduleName === 'custom' && ['estimate', 'browsestoryconcept', 'configurescrum'].includes(methodLowerCase))
|
||||
if(moduleName === 'custom' && ['estimate', 'browsestoryconcept', 'configurescrum', 'setdefaultconcept'].includes(methodLowerCase))
|
||||
{
|
||||
return 'system';
|
||||
}
|
||||
|
||||
@@ -164,7 +164,6 @@ class issueModel extends model
|
||||
$issueList = $this->dao->select('*')->from(TABLE_ISSUE)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere($type)->eq($account)->fi()
|
||||
->beginIF($this->app->rawMethod == 'contribute')->andWhere("status")->in('resolved,canceled,closed')->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
|
||||
@@ -38,4 +38,13 @@ $(function()
|
||||
$('.group-collapse-all').show();
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
$('#tabsNav .nav-tabs').on('shown.zui.tab', function(e)
|
||||
{
|
||||
setTimeout(function()
|
||||
{
|
||||
var modalHeight = $('body').height();
|
||||
parent.$('#triggerModal .modal-body').height(modalHeight);
|
||||
}, 300);
|
||||
});
|
||||
})
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
<tr>
|
||||
<th><?php echo $lang->job->customParam;?></th>
|
||||
<td>
|
||||
<?php if($job->customParam):?>
|
||||
<?php foreach(json_decode($job->customParam) as $paramName => $paramValue):?>
|
||||
<?php
|
||||
$paramValue = str_replace('$zentao_version', zget($lang->job->paramValueList, $paramValue). '(' . $this->config->version . ')', $paramValue);
|
||||
@@ -99,6 +100,7 @@
|
||||
?>
|
||||
<div><?php echo $paramName . ' : ' . $paramValue;?></div>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -217,6 +217,22 @@ class misc extends control
|
||||
die($check ? 'success' : 'fail');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show captcha and save to session.
|
||||
*
|
||||
* @param string $sessionVar
|
||||
* @param string $uuid
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function captcha($sessionVar = 'captcha', $uuid = '')
|
||||
{
|
||||
header('Content-Type: image/jpeg');
|
||||
$captcha = $this->app->loadClass('captcha');
|
||||
$this->session->set($sessionVar, $captcha->getPhrase());
|
||||
$captcha->build()->output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax set unfoldID.
|
||||
*
|
||||
|
||||
@@ -87,9 +87,8 @@ $lang->misc->feature = new stdclass();
|
||||
$lang->misc->feature->lastest = 'Letzte Version';
|
||||
$lang->misc->feature->detailed = 'Details';
|
||||
|
||||
$lang->misc->releaseDate['20.0.beta3'] = '2020-01-08';
|
||||
$lang->misc->releaseDate['20.0.beta2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['20.0.beta1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.3'] = '2021-01-06';
|
||||
$lang->misc->releaseDate['12.5.2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['12.5.1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.stable'] = '2020-11-19';
|
||||
$lang->misc->releaseDate['20.0.alpha1'] = '2020-10-30';
|
||||
@@ -142,11 +141,8 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['20.0.beta3'][] = array('title'=>'Optimize navigation interaction, enhance user experience, upgrade to flagship', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta2'][] = array('title'=>'Zentao 20 beta1,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta1'][] = array('title'=>'Zentao 20 beta,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.alpha1'][] = array('title'=>'Add program, reset priv.', 'desc' => '');
|
||||
|
||||
$lang->misc->feature->all['12.5.3'][] = array('title' => 'Adjust annual data.', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.2'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.1'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.stable'][] = array('title' => 'Fix Bug. Complete high priority story.', 'desc' => '');
|
||||
|
||||
|
||||
@@ -87,9 +87,8 @@ $lang->misc->feature = new stdclass();
|
||||
$lang->misc->feature->lastest = 'Latest Version';
|
||||
$lang->misc->feature->detailed = 'Detail';
|
||||
|
||||
$lang->misc->releaseDate['20.0.beta3'] = '2020-01-08';
|
||||
$lang->misc->releaseDate['20.0.beta2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['20.0.beta1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.3'] = '2021-01-06';
|
||||
$lang->misc->releaseDate['12.5.2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['12.5.1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.stable'] = '2020-11-19';
|
||||
$lang->misc->releaseDate['20.0.alpha1'] = '2020-10-30';
|
||||
@@ -142,11 +141,8 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['20.0.beta3'][] = array('title'=>'Optimize navigation interaction, enhance user experience, upgrade to flagship', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta2'][] = array('title'=>'Zentao 20 beta1,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta1'][] = array('title'=>'Zentao 20 beta1,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.alpha1'][] = array('title'=>'Add program, reset priv.', 'desc' => '');
|
||||
|
||||
$lang->misc->feature->all['12.5.3'][] = array('title' => 'Adjust annual data.', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.2'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.1'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.stable'][] = array('title' => 'Fix Bug. Complete high priority story.', 'desc' => '');
|
||||
|
||||
|
||||
@@ -87,9 +87,8 @@ $lang->misc->feature = new stdclass();
|
||||
$lang->misc->feature->lastest = 'Dernière Version';
|
||||
$lang->misc->feature->detailed = 'Détail';
|
||||
|
||||
$lang->misc->releaseDate['20.0.beta3'] = '2020-01-08';
|
||||
$lang->misc->releaseDate['20.0.beta2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['20.0.beta1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.3'] = '2021-01-06';
|
||||
$lang->misc->releaseDate['12.5.2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['12.5.1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.stable'] = '2020-11-19';
|
||||
$lang->misc->releaseDate['20.0.alpha1'] = '2020-10-30';
|
||||
@@ -142,11 +141,8 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['20.0.beta3'][] = array('title'=>'Optimize navigation interaction, enhance user experience, upgrade to flagship', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta2'][] = array('title'=>'Zentao 20 beta1,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta1'][] = array('title'=>'Zentao 20 beta,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.alpha1'][] = array('title'=>'Add program, reset priv.', 'desc' => '');
|
||||
|
||||
$lang->misc->feature->all['12.5.3'][] = array('title' => 'Adjust annual data.', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.2'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.1'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.stable'][] = array('title' => 'Fix Bug. Complete high priority story.', 'desc' => '');
|
||||
|
||||
|
||||
@@ -87,9 +87,8 @@ $lang->misc->feature = new stdclass();
|
||||
$lang->misc->feature->lastest = 'Latest Version';
|
||||
$lang->misc->feature->detailed = 'Chi tiết';
|
||||
|
||||
$lang->misc->releaseDate['20.0.beta3'] = '2020-01-08';
|
||||
$lang->misc->releaseDate['20.0.beta2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['20.0.beta1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.3'] = '2021-01-06';
|
||||
$lang->misc->releaseDate['12.5.2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['12.5.1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.stable'] = '2020-11-19';
|
||||
$lang->misc->releaseDate['20.0.alpha1'] = '2020-10-30';
|
||||
@@ -142,11 +141,8 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['20.0.beta3'][] = array('title'=>'Optimize navigation interaction, enhance user experience, upgrade to flagship', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta2'][] = array('title'=>'Zentao 20 beta1,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta1'][] = array('title'=>'Zentao 20 beta,fix bug,process detail', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.alpha1'][] = array('title'=>'Add program, reset priv.', 'desc' => '');
|
||||
|
||||
$lang->misc->feature->all['12.5.3'][] = array('title' => 'Adjust annual data.', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.2'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.1'][] = array('title' => 'Fix Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.stable'][] = array('title' => 'Fix Bug. Complete high priority story.', 'desc' => '');
|
||||
|
||||
|
||||
@@ -87,9 +87,8 @@ $lang->misc->feature = new stdclass();
|
||||
$lang->misc->feature->lastest = '最新版本';
|
||||
$lang->misc->feature->detailed = '详情';
|
||||
|
||||
$lang->misc->releaseDate['20.0.beta3'] = '2020-01-08';
|
||||
$lang->misc->releaseDate['20.0.beta2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['20.0.beta1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.3'] = '2021-01-06';
|
||||
$lang->misc->releaseDate['12.5.2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['12.5.1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.stable'] = '2020-11-19';
|
||||
$lang->misc->releaseDate['20.0.alpha1'] = '2020-10-30';
|
||||
@@ -142,11 +141,8 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['20.0.beta3'][] = array('title'=>'优化导航交互,增强用户体验,升级到旗舰版', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta2'][] = array('title'=>'重构组织导航,修复bug,完善细节', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta1'][] = array('title'=>'禅道20beta版本,修复bug,完善细节', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.alpha1'][] = array('title'=>'禅道20版本大更新,重构导航,增加瀑布模型', 'desc' => '<p>增加项目集和项目概念</p><p>将原项目概念变为迭代或阶段概念</p><p>增加瀑布开发模板</p>');
|
||||
|
||||
$lang->misc->feature->all['12.5.3'][] = array('title' => '优化年度总结', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.2'][] = array('title' => '修复Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.1'][] = array('title' => '修复漏洞。', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.stable'][] = array('title' => '解决bug,完成高优先级需求。', 'desc' => '');
|
||||
|
||||
|
||||
@@ -87,9 +87,8 @@ $lang->misc->feature = new stdclass();
|
||||
$lang->misc->feature->lastest = '最新版本';
|
||||
$lang->misc->feature->detailed = '詳情';
|
||||
|
||||
$lang->misc->releaseDate['20.0.beta3'] = '2020-01-08';
|
||||
$lang->misc->releaseDate['20.0.beta2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['20.0.beta1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.3'] = '2021-01-06';
|
||||
$lang->misc->releaseDate['12.5.2'] = '2020-12-18';
|
||||
$lang->misc->releaseDate['12.5.1'] = '2020-11-30';
|
||||
$lang->misc->releaseDate['12.5.stable'] = '2020-11-19';
|
||||
$lang->misc->releaseDate['20.0.alpha1'] = '2020-10-30';
|
||||
@@ -142,11 +141,8 @@ $lang->misc->releaseDate['7.2.stable'] = '2015-05-22';
|
||||
$lang->misc->releaseDate['7.1.stable'] = '2015-03-07';
|
||||
$lang->misc->releaseDate['6.3.stable'] = '2014-11-07';
|
||||
|
||||
$lang->misc->feature->all['20.0.beta3'][] = array('title'=>'優化導航交互,增強用戶體驗,升級到旗艦版', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta2'][] = array('title'=>'重構組織導航,修復bug,完善細節', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.beta1'][] = array('title'=>'禪道20beta版本,修復bug,完善細節', 'desc' => '');
|
||||
$lang->misc->feature->all['20.0.alpha1'][] = array('title'=>'禪道20版本大更新,重構導航,增加瀑布模型', 'desc' => '<p>增加項目集和項目概念</p><p>將原項目概念變為迭代或階段概念</p><p>增加瀑布開發模板</p>');
|
||||
|
||||
$lang->misc->feature->all['12.5.3'][] = array('title' => '優化年度總結', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.2'][] = array('title' => '修復Bug', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.1'][] = array('title' => '修復漏洞。', 'desc' => '');
|
||||
$lang->misc->feature->all['12.5.stable'][] = array('title' => '解決bug,完成高優先順序需求。', 'desc' => '');
|
||||
|
||||
|
||||
@@ -366,7 +366,11 @@ class product extends control
|
||||
$linkStoriesProjects = array();
|
||||
|
||||
/* Link the projects stories under this product. */
|
||||
$notRemovePRJ = $this->dao->select('*')->from(TABLE_PROJECTSTORY)->where('product')->eq($productID)->fetchPairs('project', 'product');
|
||||
$notRemovePRJ = $this->dao->select('t1.*')->from(TABLE_PROJECTSTORY)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->where('t1.product')->eq($productID)
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->fetchPairs('project', 'product');
|
||||
if(!empty($notRemovePRJ)) $canChangePGM = false;
|
||||
|
||||
/* Get the projects linked with this product. */
|
||||
|
||||
@@ -986,7 +986,7 @@ class productModel extends model
|
||||
unset($plans[$planID]);
|
||||
continue;
|
||||
}
|
||||
if(($plan->end != '0000-00-00' and strtotime($plan->end) - time() <= 0) or $plan->end == '2030-01-01') continue;
|
||||
if((!helper::isZeroDate($plan->end) and strtotime($plan->end) - time() <= 0) or $plan->end == '2030-01-01') continue;
|
||||
$orderedPlans[$plan->end][] = $plan;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
td.delayed{background: #e84e0f!important; color: white;}
|
||||
#int-dropdown{margin-left: -8px; border-radius: 4px; border: 1px solid #0c64eb}
|
||||
#projectTaskForm table tbody tr td{overflow: hidden; text-overflow: ellipsis; white-space: nowrap;}
|
||||
th.c-deadline{text-align:center;}
|
||||
|
||||
+15
-12
@@ -448,8 +448,9 @@ class projectModel extends model
|
||||
|
||||
/* Get the data from the post. */
|
||||
$project = fixer::input('post')
|
||||
->setIF($this->post->begin == '0000-00-00', 'begin', '')
|
||||
->setIF($this->post->end == '0000-00-00', 'end', '')
|
||||
->setIF(helper::isZeroDate($this->post->begin), 'begin', '')
|
||||
->setIF(helper::isZeroDate($this->post->end), 'end', '')
|
||||
->setIF($this->post->acl != 'custom', 'whitelist', '')
|
||||
->setDefault('team', $this->post->name)
|
||||
->join('whitelist', ',')
|
||||
->stripTags($this->config->project->editor->edit['id'], $this->config->allowedTags)
|
||||
@@ -715,7 +716,7 @@ class projectModel extends model
|
||||
->fetchAll();
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
if($task->status == 'wait' and $task->estStarted != '0000-00-00')
|
||||
if($task->status == 'wait' and !helper::isZeroDate($task->estStarted))
|
||||
{
|
||||
$taskDays = helper::diffDate($task->deadline, $task->estStarted);
|
||||
$taskOffset = helper::diffDate($task->estStarted, $oldProject->begin);
|
||||
@@ -1175,7 +1176,7 @@ class projectModel extends model
|
||||
/* If projectBurns > $itemCounts, split it, else call processBurnData() to pad burns. */
|
||||
$begin = $executions[$executionID]->begin;
|
||||
$end = $executions[$executionID]->end;
|
||||
if($begin == '0000-00-00') $begin = $executions[$executionID]->openedDate;
|
||||
if(helper::isZeroDate($begin)) $begin = $executions[$executionID]->openedDate;
|
||||
$executionBurns = $this->processBurnData($executionBurns, $itemCounts, $begin, $end);
|
||||
|
||||
/* Shorter names. */
|
||||
@@ -1965,7 +1966,7 @@ class projectModel extends model
|
||||
$task->openedBy = $this->app->user->account;
|
||||
|
||||
if($task->estimate !== '') $task->left = $task->estimate;
|
||||
if(strpos($requiredFields, 'deadline') !== false and $task->deadline == '0000-00-00') $task->deadline = '';
|
||||
if(strpos($requiredFields, 'deadline') !== false and helper::isZeroDate($task->deadline)) $task->deadline = '';
|
||||
if(!empty($bugToTasks->assignedTo[$key]))
|
||||
{
|
||||
$task->assignedTo = $bugToTasks->assignedTo[$key];
|
||||
@@ -2605,7 +2606,7 @@ class projectModel extends model
|
||||
*/
|
||||
public function processBurnData($sets, $itemCounts, $begin, $end, $mode = 'noempty')
|
||||
{
|
||||
if($end != '0000-00-00')
|
||||
if(!helper::isZeroDate($end))
|
||||
{
|
||||
$period = helper::diffDate($end, $begin) + 1;
|
||||
$counts = $period > $itemCounts ? $itemCounts : $period;
|
||||
@@ -3585,12 +3586,14 @@ class projectModel extends model
|
||||
$isView = (empty($this->app->user->view->sprints) || empty($this->app->user->view->projects)) ? false : true;
|
||||
if(!$this->app->user->admin && $isView === false) return array();
|
||||
|
||||
$executions = $this->dao->select('id,project,code,name,type')->from(TABLE_PROJECT)
|
||||
->where('type')->in('stage,sprint')
|
||||
->beginIF(!$this->app->user->admin)->andWhere('id')->in($this->app->user->view->sprints)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('project')->in($this->app->user->view->projects)->fi()
|
||||
->andWhere('status')->ne('closed')
|
||||
->andWhere('deleted')->eq('0')
|
||||
$executions = $this->dao->select('t1.id,t1.project,t1.code,t1.name,t1.type')->from(TABLE_PROJECT)->alias('t1')
|
||||
->leftJoin(TABLE_TEAM)->alias('t2')->on('t1.id=t2.root')
|
||||
->where('t1.type')->in('stage,sprint')
|
||||
->andWhere('t2.account')->eq($this->app->user->account)
|
||||
->beginIF(!$this->app->user->admin)->andWhere('t1.id')->in($this->app->user->view->sprints)->fi()
|
||||
->beginIF(!$this->app->user->admin)->andWhere('t1.project')->in($this->app->user->view->projects)->fi()
|
||||
->andWhere('t1.status')->ne('closed')
|
||||
->andWhere('t1.deleted')->eq('0')
|
||||
->orderBy('id_desc')
|
||||
->fetchAll();
|
||||
|
||||
|
||||
+44
-16
@@ -7,22 +7,50 @@ $config->report->dailyreminder->task = true;
|
||||
$config->report->dailyreminder->todo = true;
|
||||
$config->report->dailyreminder->testTask = true;
|
||||
|
||||
$config->report->annualData['minMonth'] = 2;
|
||||
$config->report->annualData['minMonth'] = 2;
|
||||
$config->report->annualData['colors'] = array('#0075A9', '#22AC38', '#CAAC32', '#2B4D6D', '#0071a4', '#00a0e9', '#7ecef4');
|
||||
$config->report->annualData['itemMinWidth'] = array(1 => 3, 2 => 5, 3 => 7, 4 => 9, 5 => 11);
|
||||
|
||||
$config->report->annualData['po']['block1'] = array('title' => 'baseInfo', 'data' => array('logins', 'involvedProducts', 'createdPlans', 'createdStories'));
|
||||
$config->report->annualData['po']['block2'] = array('title' => 'productOverview', 'data' => array());
|
||||
$config->report->annualData['po']['block3'] = array('title' => '', 'data' => array('products'));
|
||||
$config->report->annualData['po']['block4'] = array('title' => 'poData', 'data' => array('storyPri', 'storyStage'));
|
||||
$config->report->annualData['po']['block5'] = array('title' => 'poStatistics', 'data' => array('storyMonth'));
|
||||
$config->report->annualData['contributions']['product'] = array('opened' => 'create', 'edited' => 'edit', 'closed' => 'close');
|
||||
$config->report->annualData['contributions']['story'] = array('opened' => 'create', 'reviewed' => 'review', 'closed' => 'close', 'gitcommited' => 'gitCommit', 'svncommited' => 'svnCommit');
|
||||
$config->report->annualData['contributions']['productplan'] = array('opened' => 'create');
|
||||
$config->report->annualData['contributions']['release'] = array('opened' => 'create');
|
||||
$config->report->annualData['contributions']['project'] = array('opened' => 'create', 'edited' => 'edit', 'started' => 'start', 'closed' => 'close');
|
||||
$config->report->annualData['contributions']['task'] = array('opened' => 'create', 'assigned' => 'assign', 'finished' => 'finish', 'activated' => 'activate', 'closed' => 'close', 'gitcommited' => 'gitCommit', 'svncommited' => 'svnCommit');
|
||||
$config->report->annualData['contributions']['bug'] = array('opened' => 'create', 'resolved' => 'resolve', 'closed' => 'close', 'activated' => 'activate', 'gitcommited' => 'gitCommit', 'svncommited' => 'svnCommit');
|
||||
$config->report->annualData['contributions']['build'] = array('opened' => 'create');
|
||||
$config->report->annualData['contributions']['case'] = array('opened' => 'create', 'run' => 'run');
|
||||
$config->report->annualData['contributions']['testtask'] = array('opened' => 'create', 'edited' => 'edit');
|
||||
$config->report->annualData['contributions']['doc'] = array('created' => 'create', 'edited' => 'edit');
|
||||
|
||||
$config->report->annualData['dev']['block1'] = array('title' => 'baseInfo', 'data' => array('logins', 'actions', 'efforts', 'consumed'));
|
||||
$config->report->annualData['dev']['block2'] = array('title' => 'projectOverview', 'data' => array('doneProject', 'doingProject', 'suspendProject'));
|
||||
$config->report->annualData['dev']['block3'] = array('title' => '', 'data' => array('projects'));
|
||||
$config->report->annualData['dev']['block4'] = array('title' => 'devData', 'data' => array('finishedTaskPri', 'resolvedBugPri'));
|
||||
$config->report->annualData['dev']['block5'] = array('title' => 'devStatistics', 'data' => array('taskMonth', 'effortMonth', 'bugMonth'));
|
||||
$config->report->annualData['radar']['product']['create'] = array('product');
|
||||
$config->report->annualData['radar']['product']['edit'] = array('product');
|
||||
$config->report->annualData['radar']['story']['create'] = array('product');
|
||||
$config->report->annualData['radar']['story']['edit'] = array('product');
|
||||
$config->report->annualData['radar']['story']['close'] = array('product');
|
||||
$config->report->annualData['radar']['productplan']['create'] = array('product');
|
||||
$config->report->annualData['radar']['release']['create'] = array('product');
|
||||
$config->report->annualData['radar']['project']['create'] = array('project');
|
||||
$config->report->annualData['radar']['project']['edit'] = array('project');
|
||||
$config->report->annualData['radar']['project']['start'] = array('project');
|
||||
$config->report->annualData['radar']['project']['close'] = array('project');
|
||||
$config->report->annualData['radar']['build']['create'] = array('project');
|
||||
$config->report->annualData['radar']['task']['create'] = array('project', 'devel');
|
||||
$config->report->annualData['radar']['task']['assign'] = array('project', 'devel');
|
||||
$config->report->annualData['radar']['task']['close'] = array('project', 'devel');
|
||||
$config->report->annualData['radar']['task']['activate'] = array('project');
|
||||
$config->report->annualData['radar']['repo']['svnCommit'] = array('devel');
|
||||
$config->report->annualData['radar']['repo']['gitCommit'] = array('devel');
|
||||
$config->report->annualData['radar']['bug']['resolve'] = array('devel');
|
||||
$config->report->annualData['radar']['bug']['create'] = array('qa');
|
||||
$config->report->annualData['radar']['bug']['activate'] = array('qa');
|
||||
$config->report->annualData['radar']['bug']['close'] = array('qa');
|
||||
$config->report->annualData['radar']['case']['create'] = array('qa');
|
||||
$config->report->annualData['radar']['case']['run'] = array('qa');
|
||||
$config->report->annualData['radar']['testtask']['create'] = array('qa');
|
||||
$config->report->annualData['radar']['testtask']['edit'] = array('qa');
|
||||
|
||||
$config->report->annualData['qa']['block1'] = array('title' => 'baseInfo', 'data' => array('logins', 'actions', 'foundBugs', 'createdCases'));
|
||||
$config->report->annualData['qa']['block2'] = array('title' => 'qaOverview', 'data' => array());
|
||||
$config->report->annualData['qa']['block3'] = array('title' => '', 'data' => array('projects'));
|
||||
$config->report->annualData['qa']['block4'] = array('title' => 'qaData', 'data' => array('bugPri', 'casePri'));
|
||||
$config->report->annualData['qa']['block5'] = array('title' => 'qaStatistics', 'data' => array('bugMonth', 'caseMonth'));
|
||||
$config->report->annualData['month']['story'] = array('opened' => 'create', 'activated' => 'activate', 'closed' => 'close', 'changed' => 'change');
|
||||
$config->report->annualData['month']['task'] = array('opened' => 'create', 'started' => 'start', 'finished' => 'finish', 'paused' => 'pause', 'activated' => 'activate', 'canceled' => 'cancel', 'closed' => 'close');
|
||||
$config->report->annualData['month']['bug'] = array('opened' => 'create', 'bugconfirmed' => 'confirm', 'activated' => 'activate', 'resolved' => 'resolve', 'closed' => 'close');
|
||||
$config->report->annualData['month']['case'] = array('opened' => 'create', 'run' => 'run', 'createBug' => 'createBug');
|
||||
|
||||
+64
-91
@@ -254,14 +254,21 @@ class report extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Show personal annual data
|
||||
* Show annual data
|
||||
*
|
||||
* @param string $year
|
||||
* @param string $dept
|
||||
* @param string $userID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function annualData($year = '')
|
||||
{
|
||||
$account = $this->app->user->account;
|
||||
public function annualData($year = '', $dept = '', $userID = '')
|
||||
{
|
||||
$this->app->loadLang('story');
|
||||
$this->app->loadLang('task');
|
||||
$this->app->loadLang('bug');
|
||||
$this->app->loadLang('testcase');
|
||||
|
||||
$firstAction = $this->dao->select('*')->from(TABLE_ACTION)->orderBy('id')->limit(1)->fetch();
|
||||
$currentYear = date('Y');
|
||||
$firstYear = empty($firstAction) ? $currentYear : substr($firstAction->date, 0, 4);
|
||||
@@ -282,101 +289,67 @@ class report extends control
|
||||
}
|
||||
}
|
||||
|
||||
/* Get common annual data. */
|
||||
/* Get users and depts. */
|
||||
$users = $this->loadModel('user')->getPairs('noletter|useid|noclosed');
|
||||
$users[''] = $this->lang->report->annualData->allUser;
|
||||
|
||||
$depts = $this->loadModel('dept')->getOptionMenu();
|
||||
$depts = array('' => $this->lang->report->annualData->allDept) + $depts;
|
||||
if(empty($userID)) unset($depts[0]);
|
||||
|
||||
$accounts = array();
|
||||
if($dept)
|
||||
{
|
||||
$accounts = $this->loadModel('dept')->getDeptUserPairs($dept);
|
||||
}
|
||||
if($userID)
|
||||
{
|
||||
$user = $this->loadModel('user')->getById($userID, 'id');
|
||||
$dept = $user->dept;
|
||||
$accounts = array($user->account => ($user->realname ? $user->realname : $user->account));
|
||||
}
|
||||
if($accounts) $accounts = array_keys($accounts);
|
||||
|
||||
if($dept)
|
||||
{
|
||||
$users = $this->loadModel('dept')->getDeptUserPairs($dept, 'useid');
|
||||
$users = array('' => $this->lang->report->annualData->allUser) + $users;
|
||||
}
|
||||
|
||||
/* Get annual data. */
|
||||
$data = array();
|
||||
$data['logins'] = $this->report->getUserYearLogins($account, $year);
|
||||
|
||||
/* Set role. */
|
||||
$role = 'po';
|
||||
if($this->app->user->role == 'dev' or $this->app->user->role == 'td' or $this->app->user->role == 'pm') $role = 'dev';
|
||||
if($this->app->user->role == 'qd' or $this->app->user->role == 'qa') $role = 'qa';
|
||||
|
||||
/* Get annual data by role. */
|
||||
if($role == 'po')
|
||||
if(!$userID)
|
||||
{
|
||||
$products = $this->report->getUserYearProducts($account, $year);
|
||||
$data['involvedProducts'] = count($products);
|
||||
|
||||
$planGroups = $this->report->getPlansByProducts($products, $account, $year);
|
||||
$planCount = 0;
|
||||
foreach($planGroups as $plans) $planCount += $plans;
|
||||
$data['createdPlans'] = $planCount;
|
||||
$data['productStat'] = $this->report->getStatByProducts($products, $account, $year);
|
||||
|
||||
$storyInfo = $this->report->getUserYearStory($products, $account, $year);
|
||||
$data['createdStories'] = $storyInfo['count'];
|
||||
$data['storyPri'] = $storyInfo['pri'];
|
||||
$data['storyStage'] = $storyInfo['stage'];
|
||||
$data['storyMonth'] = $storyInfo['month'];
|
||||
|
||||
$storyGroups = $this->report->getStoriesByProducts($products, $account, $year);
|
||||
foreach($products as $productID => $product)
|
||||
{
|
||||
$product->plans = zget($planGroups, $productID, 0);
|
||||
$product->stories = zget($storyGroups, $productID, 0);
|
||||
}
|
||||
$data['products'] = $products;
|
||||
$data['users'] = $dept ? count($accounts) : (count($users) - 1);
|
||||
}
|
||||
elseif($role == 'dev')
|
||||
else
|
||||
{
|
||||
$data['actions'] = $this->report->getUserYearActions($account, $year);
|
||||
|
||||
$efforts = $this->report->getUserYearEfforts($account, $year);
|
||||
$data['efforts'] = $efforts->count;
|
||||
$data['consumed'] = round($efforts->consumed, 2);
|
||||
|
||||
$projects = $this->report->getUserYearProjects($account, $year);
|
||||
$projectStat = $this->report->getStatByProjects($projects);
|
||||
|
||||
$tasks = $this->report->getUserYearFinishedTasks($account, $year);
|
||||
$bugs = $this->report->getUserYearResolvedBugs($account, $year);
|
||||
$data['finishedTaskPri'] = $tasks['pri'];
|
||||
$data['resolvedBugPri'] = $bugs['pri'];
|
||||
$data['taskMonth'] = $tasks['month'];
|
||||
$data['bugMonth'] = $bugs['month'];
|
||||
$data['effortMonth'] = $this->report->getEffort4Month($account, $year);;
|
||||
|
||||
$stories = $this->report->getFinishedStoryByProjects($projects, $account, $year);
|
||||
$tasks = $this->report->getFinishedTaskByProjects($projects, $account, $year);
|
||||
$bugs = $this->report->getResolvedBugByProjects($projects, $account, $year);
|
||||
foreach($projects as $projectID => $project)
|
||||
{
|
||||
$project->stories = zget($stories, $projectID, 0);
|
||||
$project->tasks = zget($tasks, $projectID, 0);
|
||||
$project->bugs = zget($bugs, $projectID, 0);
|
||||
}
|
||||
|
||||
$data['projects'] = $projects;
|
||||
$data['projectStat'] = $projectStat;
|
||||
$data['logins'] = $this->report->getUserYearLogins($accounts, $year);
|
||||
}
|
||||
elseif($role == 'qa')
|
||||
{
|
||||
$data['actions'] = $this->report->getUserYearActions($account, $year);
|
||||
$bugInfo = $this->report->getUserYearCreatedBugs($account, $year);
|
||||
$data['foundBugs'] = $bugInfo['count'];
|
||||
$data['bugPri'] = $bugInfo['pri'];
|
||||
$data['bugMonth'] = $bugInfo['month'];
|
||||
$data['actions'] = $this->report->getUserYearActions($accounts, $year);
|
||||
$data['todos'] = $this->report->getUserYearTodos($accounts, $year);
|
||||
$data['contributions'] = $this->report->getUserYearContributions($accounts, $year);
|
||||
$data['projectStat'] = $this->report->getUserYearProjects($accounts, $year);
|
||||
$data['productStat'] = $this->report->getUserYearProducts($accounts, $year);
|
||||
$data['storyStat'] = $this->report->getYearObjectStat($accounts, $year, 'story');
|
||||
$data['taskStat'] = $this->report->getYearObjectStat($accounts, $year, 'task');
|
||||
$data['bugStat'] = $this->report->getYearObjectStat($accounts, $year, 'bug');
|
||||
$data['caseStat'] = $this->report->getYearCaseStat($accounts, $year);
|
||||
|
||||
$caseInfo = $this->report->getUserYearCreatedCases($account, $year);
|
||||
$data['createdCases'] = $caseInfo['count'];
|
||||
$data['casePri'] = $caseInfo['pri'];
|
||||
$data['caseMonth'] = $caseInfo['month'];
|
||||
$yearEfforts = $this->report->getUserYearEfforts($accounts, $year);
|
||||
$data['consumed'] = $yearEfforts->consumed;
|
||||
|
||||
$products = $this->report->getUserYearProducts4QA($account, $year);
|
||||
$productStat = $this->report->getBugStatByProducts($products, $account, $year);
|
||||
if(empty($dept) and empty($userID)) $data['statusStat'] = $this->report->getAllTimeStatusStat();
|
||||
|
||||
$bugs = $this->report->getCreatedBugByProducts($products, $account, $year);
|
||||
foreach($products as $productID => $product) $product->bugs = zget($bugs, $productID, 0);
|
||||
|
||||
$data['products'] = $products;
|
||||
$data['productStat'] = $productStat;
|
||||
}
|
||||
|
||||
$this->view->title = sprintf($this->lang->report->annualData->title, $year, $this->app->user->realname);
|
||||
$this->view->data = $data;
|
||||
$this->view->role = $role;
|
||||
$this->view->year = $year;
|
||||
$this->view->years = $years;
|
||||
$this->view->title = sprintf($this->lang->report->annualData->title, ($userID ? $users[$userID] : ($dept ? substr($depts[$dept], strrpos($depts[$dept], '/') + 1) : $depts[''])), $year);
|
||||
$this->view->data = $data;
|
||||
$this->view->year = $year;
|
||||
$this->view->users = $users;
|
||||
$this->view->depts = $depts;
|
||||
$this->view->years = $years;
|
||||
$this->view->dept = $dept;
|
||||
$this->view->userID = $userID;
|
||||
$this->view->months = $this->report->getYearMonths($year);
|
||||
die($this->display());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,79 +1,84 @@
|
||||
|
||||
body {height: 100vh; padding: 0;}
|
||||
#container {position: fixed; top: 0; right: 0; bottom: 0; left: 0; display: flex; justify-content: center; align-items: center; background-color: #010417; color: #fff; background-size: cover; overflow: auto;}
|
||||
#container {top: 0; right: 0; bottom: 0; left: 0; display: flex; justify-content: center; align-items: center; background-color: #010417; color: #fff; background-size: cover; overflow: auto;}
|
||||
#container:before {content: ' '; display: block; position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 0; opacity: 0.9; background: #010419;}
|
||||
#main {min-width: 1280px; min-height: 800px; position: absolute; z-index: 10; padding: 0; background-size: cover;}
|
||||
#main > section {position: absolute; }
|
||||
#main > section > header {height: 24px;}
|
||||
#main > section > header > h2 {line-height: 24px; font-size: 14px; padding: 0 8px; float: left; margin: 0; position: relative; background: #1a77a5; position: relative; font-weight: normal;}
|
||||
#main > section > header > h2:after {content: ' '; display: block; position: absolute; top: 0; right: -40px; bottom: 0; width: 40px; background: linear-gradient(to right, #1a77a5 0%, transparent 100%);}
|
||||
#mainBg {position: absolute; top: 0; right: 0; bottom: 0; left: 0;}
|
||||
#main {position:relative; width: 1360px; z-index: 10; padding:0 35px; background-size: cover; padding-bottom:20px;}
|
||||
#main section > header {height: 24px; margin-top: 7px;}
|
||||
#main section > header > h2 {line-height: 24px; font-size: 14px; padding: 0 8px; float: left; margin: 0; position: relative; background: #1a77a5; position: relative; font-weight: normal;}
|
||||
#main section > header > h2:after {content: ' '; display: block; position: absolute; top: 0; right: -40px; bottom: 0; width: 40px; background: linear-gradient(to right, #1a77a5 0%, transparent 100%);}
|
||||
.exporting #mainBg {background-color: rgb(1, 4, 25, .9);}
|
||||
#loadIndicator {position: fixed; left: 0; right: 0; bottom: 0; top: 0; z-index: 1000; visibility: hidden;}
|
||||
#loadIndicator.loading {visibility: visible;}
|
||||
#loadIndicator:before {background-color: rgba(50,50,50,.65);}
|
||||
#loadIndicator:after {font-size: 30px}
|
||||
|
||||
#header {margin-bottom:45px;}
|
||||
#header > h1 {width: 500px; margin: 40px auto 0; height: 58px; font-weight: normal; text-align: center; font-size: 20px; display: block; line-height: 58px; position: relative; left: -30px;}
|
||||
#toolbar {position: absolute; right: 33px; top: 80px; text-align: center;}
|
||||
#toolbar #year{width:70px; display:inline-block; margin-right:5px; padding-top:2px; border-color: #1a77a5; background-color: transparent; color:#fff;}
|
||||
#toolbar {position: absolute; right: 33px; top: 80px; text-align: center;width:1280px;}
|
||||
#toolbar #year{width:70px; display:inline-block; margin-right:5px; padding-top:5px; border-color: #1a77a5; background-color: transparent; color:#fff;}
|
||||
#toolbar #year option{background: #141414;}
|
||||
#toolbar #dept, #dept_chosen, #dept_chosen > .chosen-single{width:100px !important; display:inline-block; margin-right:5px; padding-top:0px; border-color: #1a77a5; background-color: transparent; color:#fff;}
|
||||
#toolbar #userID, #userID_chosen, #userID_chosen > .chosen-single, #toolbar .picker-single{width:100px !important; display:inline-block; margin-right:5px; padding-top:0px; border-color: #1a77a5; background-color: transparent; color:#fff;}
|
||||
|
||||
.chosen-container > .chosen-single > span{padding-top:5px; height:28px;}
|
||||
.chosen-container .chosen-drop{background:#141414; text-align:left;}
|
||||
.chosen-container-single .chosen-search input[type=text]{background: #141414; color:#fff;}
|
||||
.chosen-results .no-results{background: #141414 !important;}
|
||||
|
||||
#toolbar .picker-single{position: absolute; top:1px;}
|
||||
#toolbar .picker-single .picker-selections{background: #010417;color:#fff; border-color: #1a77a5 !important; text-align:left;}
|
||||
#toolbar .picker-single .picker-selection.picker-selection-single{padding-top:6px; height:30px;}
|
||||
.picker-drop-menu.picker-single{background: #141414;}
|
||||
.picker-drop-menu.picker-single .picker-option{color:#fff;}
|
||||
.picker-drop-menu.picker-single .picker-message{background: #141414 !important;color:#fff;}
|
||||
|
||||
.exporting #toolbar {display: none;}
|
||||
#toolbar .btn-primary {border-color: #1a77a5; background-color: transparent; padding: 6px 7px;}
|
||||
#toolbar .btn-primary:hover,
|
||||
#toolbar .btn-primary:focus {border-color: #B5E8FF; background-color: #1a77a5;}
|
||||
|
||||
#block1 {left: 25px; top: 128px; width: 366px; height: 283px;}
|
||||
#block1 > header {margin-top: 7px;}
|
||||
#block1 > div {overflow: auto; max-height: 250px;}
|
||||
#block1List {margin: 16px 36px 0 32px; padding: 0;}
|
||||
#block1List > li {line-height: 40px; width: 294px; height: 46px; padding-left: 23px; position: relative; margin-bottom: 10px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASYAAAAuCAMAAACyPkQxAAAAilBMVEW16P8AAAAAdakAdakAdakAdalBn8gBdqoAdam16P8AdqoEd6sAdakAdakAdakAdakqi7oAdakAdakCdqoNfK4AdakBdqoAdakAdakAdqoAdam16P+Pwtlkq8sJeqy62uiv1OSeyt6Au9RztNBWpMZLncI/l78zkbspi7chh7QZg7IRfq+mz+H1+vzlZNDsAAAAGnRSTlMNAH80IxAg1kR/1Yf26HRhF9/ItlOjmz8vBYfBgpwAAAFCSURBVGje7dZHcoNAEIXhbpSwUZachiBylO9/PReYUpUWAyxmqAK9/whf9+KR3SZeNc/zqqosiyLPsyxNkySOXdeNojB0HCcI7r5/u/0+mAjJu4EJTMryCURgUtUdTEMKwDSMSRDqzQETmMA0biGYwKSsCExgUpYLJjCBadxiMIFJWQmYwKSsFExgUlYGpoFMa0J95bQ/LQj1MvFhZxLqriBmc3cl1MvEi92BUFclGcy8PFmEOplE7XQ8fxKSV5FonFaXy5FQF1Pj9PNxxoCS5tG+dWJLTLHNGMdde8T/TlPNGMFpvbGI+QCnHiWDiZmvWyEss24h6Xsp6biSxNKm5lQrNUxsboXW+KlpOTVKb8R1X09OE2PS6dQq2cQzyHhvnXQpjcNk60nipEFpHt/UOulSmg9T7aRLaU5MbAj1PZTsP0LdcHztAh8bAAAAAElFTkSuQmCC);}
|
||||
#block1List > li > strong {position: absolute; right: 18px; top: 2px; font-size: 20px; color: #B5E8FF;}
|
||||
section{border:1px solid rgb(0, 117, 169); float:left;}
|
||||
section.active{border:1px solid rgb(0, 166, 255);}
|
||||
#baseInfo {width: 370px; height: 330px;}
|
||||
#infoList {margin: 16px 36px 0 32px; padding: 0;}
|
||||
#infoList > li {line-height: 40px; width: 294px; height: 46px; padding-left: 23px; position: relative; margin-bottom: 10px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASYAAAAuCAMAAACyPkQxAAAAilBMVEW16P8AAAAAdakAdakAdakAdalBn8gBdqoAdam16P8AdqoEd6sAdakAdakAdakAdakqi7oAdakAdakCdqoNfK4AdakBdqoAdakAdakAdqoAdam16P+Pwtlkq8sJeqy62uiv1OSeyt6Au9RztNBWpMZLncI/l78zkbspi7chh7QZg7IRfq+mz+H1+vzlZNDsAAAAGnRSTlMNAH80IxAg1kR/1Yf26HRhF9/ItlOjmz8vBYfBgpwAAAFCSURBVGje7dZHcoNAEIXhbpSwUZachiBylO9/PReYUpUWAyxmqAK9/whf9+KR3SZeNc/zqqosiyLPsyxNkySOXdeNojB0HCcI7r5/u/0+mAjJu4EJTMryCURgUtUdTEMKwDSMSRDqzQETmMA0biGYwKSsCExgUpYLJjCBadxiMIFJWQmYwKSsFExgUlYGpoFMa0J95bQ/LQj1MvFhZxLqriBmc3cl1MvEi92BUFclGcy8PFmEOplE7XQ8fxKSV5FonFaXy5FQF1Pj9PNxxoCS5tG+dWJLTLHNGMdde8T/TlPNGMFpvbGI+QCnHiWDiZmvWyEss24h6Xsp6biSxNKm5lQrNUxsboXW+KlpOTVKb8R1X09OE2PS6dQq2cQzyHhvnXQpjcNk60nipEFpHt/UOulSmg9T7aRLaU5MbAj1PZTsP0LdcHztAh8bAAAAAElFTkSuQmCC);}
|
||||
#infoList > li > strong {position: absolute; right: 18px; top: 2px; font-size: 20px; color: #B5E8FF;}
|
||||
#infoList > li.dropdown .dropdown-menu{ background-color:#000; color:#fff; padding:10px; border: 1px solid #999}
|
||||
#infoList > li.dropdown .dropdown-menu > li{line-height:1;height:20px;}
|
||||
#infoList > li.dropdown .dropdown-menu > li .todoStatus{display:inline-block; width:80px;}
|
||||
|
||||
#block2 {left: 405px; top: 132px; width: 400px; height: 280px;}
|
||||
#block2 > header {margin-top: 23px;}
|
||||
#block2 > .progress-pie {margin: 18px 0 0 18px;}
|
||||
#block2 > .progress-pie .progress-info {padding: 70px 0; pointer-events: none;}
|
||||
#block2 > .progress-pie .progress-info > strong {font-size: 30px; font-weight: normal;}
|
||||
#block2 > .progress-pie .progress-info > strong > small {font-size: 12px; color: #A0A0A0;}
|
||||
#block2ListWrapper {position: absolute; left: 235px; top: 60px; padding-top: 20px; font-size: 14px; overflow: auto; max-height: 184px;}
|
||||
#block2List {padding: 0;}
|
||||
#block2List > li {padding-left: 25px; line-height: 20px; position: relative; color: #A0A0A0; margin-bottom: 15px;}
|
||||
#block2List > li > .dot {position: absolute; width: 16px; height: 16px; left: 0; top: 2px; background: #00A0E9; border-radius: 2px;}
|
||||
#block2List > li:first-child > .dot {background: #0068B7;}
|
||||
#block2List > li:last-child > .dot {background: #7ECEF4;}
|
||||
#block2List > li > div {margin-top: 5px; color: #fff; max-width: 80px;}
|
||||
#block2List > li > div > span:last-child {float: right;}
|
||||
#block2List > li > div > span small {color: #A0A0A0;}
|
||||
#actionData {width:525px; height:330px; margin:0px 20px;}
|
||||
#actionData > div { margin-top:13px;}
|
||||
#actionData > div > ul > li{ margin-bottom:5px;cursor: default;}
|
||||
#actionData > div > ul > li .dropdown-menu{ background-color:#000; padding:5px; border: 1px solid #999}
|
||||
#actionData > div > ul > li .dropdown-menu > li{margin-bottom:5px; white-space: nowrap;}
|
||||
#actionData > div > ul > li .dropdown-menu > li .color{display:inline-block; width:10px; height:10px; margin-right: 8px}
|
||||
#actionData > div > ul > li .dropdown-menu > li .item-name{display:inline-block; max-width:100px; min-width:60px}
|
||||
#actionData > div > ul > li .dropdown-menu > li .count{display:inline-block; padding-left:10px}
|
||||
#actionData .name {display:inline-block; width:60px; text-align:right;}
|
||||
#actionData .ratio {display:inline-block; width:400px;}
|
||||
#actionData .ratio .item{display:inline-block; text-align:center;}
|
||||
|
||||
#block3 {left: 825px; top: 129px; width: 421px; height: 284px; padding: 8px 0 8px 8px;}
|
||||
#block3TableHeader {position: absolute; top: 8px; left: 8px; right: 10px; background: #0075A9; width: 401px;}
|
||||
#block3TableHeader > thead > tr > th {color: #fff; font-weight: normal; line-height: 20px; padding: 2px 4px; border: none}
|
||||
#block3 > .table-wrapper {overflow: auto; margin-top: 26px; max-height: 247px;}
|
||||
#block3Table {color: #A0A0A0;}
|
||||
#block3Table > tbody > tr > td {border-bottom: 1px #0075A9 dashed; line-height: 20px; padding: 5px 4px;}
|
||||
#block3 .col-name {width: 170px;}
|
||||
#block3 .col-storyCount {width: 80px; text-align: center;}
|
||||
#block3 .col-taskCount {width: 80px; text-align: center;}
|
||||
#block3 .col-bugCount {text-align: center;}
|
||||
#radar {width:350px; height:330px;}
|
||||
#radarCanvas {width:310px; height:310px; margin:0 auto;}
|
||||
|
||||
#block4 {left: 25px; top: 434px; width: 631px; height: 322px; padding: 0 30px 10px 10px}
|
||||
#block4 .pri {display: inline-block; width: 13px; height: 8px; background: #2B4D6D; border-radius: 4px; margin-right: 8px;}
|
||||
#block4 > header {margin-top: 12px; margin-left: -10px;}
|
||||
#block4 > header > div > .pri {margin: 0 10px;}
|
||||
#block4 > .row {margin-top: 20px; height:260px; overflow:auto;}
|
||||
#block4 > .row > .col-xs-6 + .col-xs-6:before {content: ' '; display: block; position: absolute; left: 0; top: 10px; bottom: 26px; background: #1A2835; width: 1px;}
|
||||
#block4 > .row > .col-xs-6 {text-align: center;}
|
||||
#block4 .progress-info {pointer-events: 'none';}
|
||||
#block4 .progress-info > p {color: #A0A0A0; margin-bottom: 0; margin-top: 25px;}
|
||||
#block4 .progress-info > strong {font-size: 30px; font-weight: normal;}
|
||||
#block4 .progress-info > strong > small {font-size: 12px; color: #A0A0A0;}
|
||||
#block4 > .row > .col-xs-6 > ul {margin: 0 auto; width: 250px;}
|
||||
#block4 > .row > .col-xs-6 > ul > li {float: left; width: 50%; text-align: left; color: #C9C9C9; margin-bottom: 8px;}
|
||||
#block4 canvas {transform: rotate(150deg);}
|
||||
#projectData, #productData{width:633px; height:350px; margin-top:20px; position: relative;}
|
||||
#projectData div.has-table, #productData div.has-table {margin-top:30px; height:285px; overflow:auto;}
|
||||
#projectData div.table-header-fixed, #productData div.table-header-fixed {position: absolute;left: 0px;top: 35px;right: 10px;}
|
||||
#projectData table, #productData table{margin-bottom:0px;}
|
||||
#projectData table tr>th, #productData table tr>th{color:#fff !important}
|
||||
#projectData .c-story, #projectData .c-task, #projectData .c-bug {text-align:center; width:105px}
|
||||
#productData{margin-left:20px;}
|
||||
#productData .c-plan, #productData .c-requirement, #productData .c-story, #productData .c-finished {text-align:center; width:105px;}
|
||||
#productData .c-story {width:115px;}
|
||||
#productData .c-requirement{width:140px;}
|
||||
.table-hover>tbody>tr:hover>td{background-color: #888 !important;}
|
||||
|
||||
#block5 {left: 672px; top: 434px; width: 574px; height: 322px;}
|
||||
#block5 > header {margin-top: 12px; margin-left: 0;}
|
||||
#block5Legend {position: absolute; right: 25px; top: 40px; color: #A0A0A0; font-size: 12px;}
|
||||
#block5Legend .dot {display: inline-block; border: 1px solid #fff; border-radius: 50px; width: 10px; height: 10px; background: #22AC38; margin-right: 6px; margin-left: 12px;}
|
||||
#block5 canvas {margin: 25px auto 0; display: block;}
|
||||
#allTimeStatusStat{width:1286px; height:345px; margin-top:20px;}
|
||||
#allTimeStatusStat > div {margin-top:5px;}
|
||||
#allTimeStatusStat .canvas{float:left; width:420px; height:305px; padding-left:10px;}
|
||||
|
||||
.dataYearStat{width:1286px; height:345px; margin-top:20px;}
|
||||
.dataYearStat > div{margin-top:5px;}
|
||||
.dataYearStat .canvas{float:left; height:305px; padding-left:30px;}
|
||||
.dataYearStat .canvas.left{width:450px;}
|
||||
.dataYearStat .canvas.right{width:810px;float:right}
|
||||
|
||||
+161
-145
@@ -1,142 +1,148 @@
|
||||
/**
|
||||
* Show or refresh annual data
|
||||
* @param {Object} data Annual data object
|
||||
* @return {void}
|
||||
* Draw status pie chart.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $title
|
||||
* @param array $data
|
||||
* @param function $callback
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
function showAnnualData(data)
|
||||
function drawStatusPieChart(id, title, data, callback)
|
||||
{
|
||||
// Block 1
|
||||
var $block1List = $('#block1List').empty();
|
||||
data.block1.data && $.each(data.block1.data, function(index)
|
||||
{
|
||||
var item = data.block1.data[index];
|
||||
$block1List.append('<li>' + item.title + ' <strong>' + item.value + '</strong></li>');
|
||||
});
|
||||
var titleTextStyle = {
|
||||
color:'#fff',
|
||||
fontSize: 14
|
||||
};
|
||||
var tooltip = {
|
||||
trigger: 'item',
|
||||
backgroundColor: '#010419',
|
||||
textStyle: {color:'#fff'},
|
||||
formatter: '{a} <br/>{b}: {c} ({d}%)'
|
||||
};
|
||||
|
||||
// Block 2
|
||||
data.block2.dataTotal = 0;
|
||||
var $block2List = $('#block2List').empty();
|
||||
var $block2Chart = $('#block2Chart');
|
||||
var pieChart = $block2Chart.data('pieChart');
|
||||
var pieChartColors = ['#0068B7', '#1aa1e6', '#81cef2', '#aee3fc', '#b1e6ff', '#ddeaf0'];
|
||||
while(pieChart.segments.length) pieChart.removeData();
|
||||
pieChart.options.tooltipTemplate = "<%=label%>: <%=value%>";
|
||||
data.block2.data && $.each(data.block2.data, function(index)
|
||||
{
|
||||
var item = data.block2.data[index];
|
||||
var color = pieChartColors[Math.min(pieChartColors.length - 1, index)];
|
||||
data.block2.dataTotal += item.value;
|
||||
$block2List.append('<li><span class="dot" style="background: ' + color + '"></span> ' + item.title + ' <div><span>' + item.value + '<small>' + data.block2.unit + '</small></span><span>' + (item.percent || '') + '</span></div></li>');
|
||||
pieChart.addData({color: color, label: item.title, value: item.value});
|
||||
});
|
||||
var legendLeft = '0';
|
||||
var legendTop = '25';
|
||||
var legendItemWidth = 8;
|
||||
var legendItemHeight = 8;
|
||||
var legendTextStyle = {
|
||||
color:'#fff',
|
||||
fontSize: 12
|
||||
};
|
||||
|
||||
// Block3
|
||||
var $blcok3TableHeader = $('#block3TableHeader').find('tr').empty();
|
||||
data.block3.cols && $.each(data.block3.cols, function(index)
|
||||
{
|
||||
var col = data.block3.cols[index];
|
||||
var $th = $('<th></th>').text(col.title);
|
||||
$th.css({width: col.width, textAlign: col.align});
|
||||
$blcok3TableHeader.append($th);
|
||||
});
|
||||
var $block3TableRows = $('<tbody></tbody>');
|
||||
data.block3.rows && $.each(data.block3.rows, function(index)
|
||||
{
|
||||
var row = data.block3.rows[index];
|
||||
var $tr = $('<tr></tr>');
|
||||
$.each(data.block3.cols, function(colIndex)
|
||||
{
|
||||
var $td = $('<td></td>').text(row[colIndex]);
|
||||
var rowCol = data.block3.cols[colIndex];
|
||||
$td.css({width: rowCol.width, textAlign: rowCol.align});
|
||||
$tr.append($td);
|
||||
});
|
||||
$block3TableRows.append($tr);
|
||||
});
|
||||
$('#block3Table').empty().append($block3TableRows);
|
||||
var seriesTop = '50';
|
||||
var seriesRadius = ['40%', '70%'];
|
||||
var seriesLabel = {
|
||||
color:'#fff',
|
||||
formatter: '{b} {d}%'
|
||||
};
|
||||
|
||||
// Block4
|
||||
var block4Colors = ['#CAAC32', '#0075A9', '#22AC38', '#2B4D6D', '#0071a4', '#00a0e9', '#7ecef4'];
|
||||
$.each(['chart1', 'chart2'], function(i, chartName)
|
||||
{
|
||||
var $chart = $('#block4' + chartName);
|
||||
var chart = $chart.data('pieChart');
|
||||
var chartData = data.block4[chartName];
|
||||
chartData.total = 0;
|
||||
while(chart.segments.length) chart.removeData();
|
||||
var dataLength = chartData.data && chartData.data.length;
|
||||
if(!dataLength) return;
|
||||
for(var i = 0; i < dataLength; ++i)
|
||||
{
|
||||
var item = chartData.data[i];
|
||||
chartData.total += item.value;
|
||||
}
|
||||
chart.addData({color: 'transparent', value: chartData.total / 5, label: ''});
|
||||
var $chartInfo = $('#block4' + chartName + 'Info').empty();
|
||||
for(var i = 0; i < dataLength; ++i)
|
||||
{
|
||||
var item = chartData.data[i];
|
||||
var color = block4Colors[Math.min(block4Colors.length - 1, i)];
|
||||
chart.addData({color: color, label: item.title, value: item.value, circleBeginEnd: true});
|
||||
$chartInfo.append('<li><span class="pri" style="background: ' + color + '"></span> ' + (item.legend ? (item.legend + ' - ') :'') + item.value + ' ' + chartData.unit + '</li>');
|
||||
};
|
||||
});
|
||||
|
||||
// Block5
|
||||
var $block5Chart = $('#block5Chart');
|
||||
var block5Chart = $block5Chart.data('block5Chart');
|
||||
var block5Colors = ['#76FF03', '#2979FF', '#00B0FF', '#FFD740', '#B388FF'];
|
||||
var block5Datasets = [];
|
||||
var $block5Legend = $('#block5Legend').empty();
|
||||
$.each(data.block5.datasets, function(index)
|
||||
{
|
||||
var dataset = data.block5.datasets[index];
|
||||
var color = block5Colors[Math.min(block5Colors.length - 1, index)];
|
||||
block5Datasets.push({label: dataset.label, data: dataset.data, color: new $.zui.Color(color).fade(50).toCssStr()});
|
||||
$block5Legend.append('<span class="dot" style="background: ' + color + '"></span> ' + dataset.label);
|
||||
});
|
||||
if(!block5Chart)
|
||||
{
|
||||
block5Chart = $block5Chart.lineChart(
|
||||
{
|
||||
labels: data.block5.labels,
|
||||
datasets: block5Datasets
|
||||
}, {
|
||||
scaleFontColor: '#A0A0A0',
|
||||
datasetStrokeWidth: 1,
|
||||
pointDotRadius: 3,
|
||||
scaleShowVerticalLines: false,
|
||||
scaleGridLineColor: 'rgba(255,255,255,.3)'
|
||||
});
|
||||
$block5Chart.data('block5Chart', block5Chart);
|
||||
}
|
||||
else
|
||||
{
|
||||
$.each(block5Datasets, function(index)
|
||||
{
|
||||
var dataset = block5Datasets[index];
|
||||
var oldDataset = block5Chart.datasets[index];
|
||||
for(var i = 0; i < dataset.data.length; ++i)
|
||||
var chart = echarts.init(document.getElementById(id));
|
||||
var option = {
|
||||
title: {
|
||||
text: title,
|
||||
textStyle: titleTextStyle,
|
||||
},
|
||||
tooltip: tooltip,
|
||||
legend: {
|
||||
left: legendLeft,
|
||||
top: legendTop,
|
||||
icon: 'circle',
|
||||
itemWidth: legendItemWidth,
|
||||
itemHeight: legendItemHeight,
|
||||
textStyle: legendTextStyle,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
oldDataset.points[i].value = dataset.data[i];
|
||||
name: title,
|
||||
type: 'pie',
|
||||
top: seriesTop,
|
||||
radius: seriesRadius,
|
||||
avoidLabelOverlap: false,
|
||||
label: seriesLabel,
|
||||
data: data
|
||||
}
|
||||
});
|
||||
block5Chart.update();
|
||||
]
|
||||
}
|
||||
chart.setOption(option);
|
||||
if(typeof(callback) == 'function') chart.on('finished', callback);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
// Common text holders
|
||||
$('.text-holder').each(function()
|
||||
{
|
||||
var $this = $(this);
|
||||
var id = $this.data('id');
|
||||
var idPath = id.split('.');
|
||||
var dataProp = data;
|
||||
for(var i = 0; i < idPath.length; ++i)
|
||||
{
|
||||
dataProp = dataProp[idPath[i]];
|
||||
/**
|
||||
* Draw months bar chart.
|
||||
*
|
||||
* @param string $id
|
||||
* @param string $title
|
||||
* @param array $legends
|
||||
* @param array $xAxis
|
||||
* @param array $data
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
function drawMonthsBarChart(id, title, legends, xAxis, data)
|
||||
{
|
||||
var titleTextStyle = {
|
||||
color:'#fff',
|
||||
fontSize: 14
|
||||
};
|
||||
var tooltip = {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
$this.text(dataProp);
|
||||
});
|
||||
};
|
||||
|
||||
var legendRight = '20';
|
||||
var legendTop = '0';
|
||||
var legendItemWidth = 10;
|
||||
var legendItemHeight = 10;
|
||||
var legendTextStyle = {
|
||||
color:'#fff',
|
||||
fontSize: 12
|
||||
};
|
||||
|
||||
var labelStyle = {color:'#fff'}
|
||||
|
||||
var chart = echarts.init(document.getElementById(id));
|
||||
var option = {
|
||||
title: {
|
||||
text: title,
|
||||
textStyle: titleTextStyle,
|
||||
},
|
||||
tooltip: tooltip,
|
||||
legend: {
|
||||
right: legendRight,
|
||||
top: legendTop,
|
||||
itemWidth: legendItemWidth,
|
||||
itemHeight: legendItemHeight,
|
||||
textStyle: legendTextStyle,
|
||||
data: legends
|
||||
},
|
||||
grid: {
|
||||
left: '0%',
|
||||
right: '0%',
|
||||
bottom: '2%',
|
||||
containLabel: true
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {show: true },
|
||||
splitLine: {show: false},
|
||||
axisLabel: labelStyle
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisLabel: labelStyle,
|
||||
axisTick: {alignWithLabel: true},
|
||||
data: xAxis
|
||||
},
|
||||
series: data
|
||||
}
|
||||
chart.setOption(option);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -152,10 +158,10 @@ function exportAnnualImage(sucessCallback, errorCallback)
|
||||
var $loading = $('#loadIndicator');
|
||||
$loading.addClass('loading');
|
||||
var $container = $('#container');
|
||||
$main.addClass('exporting').css('backgroundImage', $container.css('backgroundImage'));
|
||||
$main.addClass('exporting').css('background-color', $container.css('background-color'));
|
||||
var afterFinish = function(canvas)
|
||||
{
|
||||
$main.removeClass('exporting').css('backgroundImage', 'none');
|
||||
$main.removeClass('exporting');
|
||||
$loading.removeClass('loading');
|
||||
};
|
||||
html2canvas($main[0], {logging: false}).then(function(canvas)
|
||||
@@ -165,6 +171,14 @@ function exportAnnualImage(sucessCallback, errorCallback)
|
||||
afterFinish(canvas);
|
||||
if(errorCallback) errorCallback('Cannot convert image to blob.');
|
||||
};
|
||||
|
||||
/* Watermark. */
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.font = '12px serif';
|
||||
ctx.fillStyle = 'rgba(200,200,200, 0.8)';
|
||||
ctx.fillText(exportByZentao, 1220, 90);
|
||||
ctx.fillText(exportByZentao, 45, canvas.height - 10);
|
||||
|
||||
canvas.toBlob(function(blob)
|
||||
{
|
||||
var imageUrl = URL.createObjectURL(blob);
|
||||
@@ -177,26 +191,28 @@ function exportAnnualImage(sucessCallback, errorCallback)
|
||||
|
||||
$(function()
|
||||
{
|
||||
var $main = $('#main');
|
||||
var ajustPosition = function()
|
||||
{
|
||||
$main.css(
|
||||
{
|
||||
posotion: 'absolute',
|
||||
top: Math.max(0, Math.floor(($(window).height() - $main.outerHeight()) / 2)),
|
||||
left: Math.max(0, Math.floor(($(window).width() - $main.outerWidth()) / 2)),
|
||||
});
|
||||
};
|
||||
ajustPosition();
|
||||
$(window).on('resize', ajustPosition);
|
||||
|
||||
$('#exportBtn').on('click', function()
|
||||
{
|
||||
exportAnnualImage();
|
||||
});
|
||||
|
||||
$('#toolbar #year').change(function()
|
||||
$('select#year, select#dept, select#userID').change(function()
|
||||
{
|
||||
location.href = createLink('report', 'annualData', 'year=' + $(this).val());
|
||||
var dept = $('select#dept').val();
|
||||
var userID = $('select#userID').val();
|
||||
if($(this).attr('id') == 'dept') userID = 0;
|
||||
location.href = createLink('report', 'annualData', 'year=' + $('select#year').val() + '&dept=' + dept + '&userID=' + userID);
|
||||
});
|
||||
|
||||
$('#actionData > div > ul > li').mouseenter(function(e)
|
||||
{
|
||||
var width = $(this).width();
|
||||
var maxOffset = width - 100;
|
||||
var offset = e.pageX - $(this).offset().left + 10;
|
||||
if(offset > maxOffset) offset = maxOffset;
|
||||
$('#actionData > div > ul > li .dropdown-menu').css('left', offset);
|
||||
});
|
||||
|
||||
$('section').mouseover(function(){$(this).addClass('active')});
|
||||
$('section').mouseout(function(){$(this).removeClass('active')});
|
||||
});
|
||||
|
||||
@@ -107,3 +107,101 @@ $lang->report->mailTitle->testTask = " Test Aufgaben (%s),";
|
||||
|
||||
$lang->report->proVersion = '<a href="http://api.zentao.net/goto.php?item=proversion&from=reportpage" target="_blank">Testen Sie ZenTao Pro für mehr Informationen!</a>';
|
||||
$lang->report->proVersionEn = '<a href="http://api.zentao.pm/goto.php?item=proversion&from=reportpage" target="_blank">Testen Sie ZenTao Pro für mehr Informationen!</a>';
|
||||
|
||||
$lang->report->annualData = new stdclass();
|
||||
$lang->report->annualData->title = "%s work summary in %s";
|
||||
$lang->report->annualData->exportByZentao = "Export By ZenTao";
|
||||
$lang->report->annualData->scope = "Scope";
|
||||
$lang->report->annualData->allUser = "All Users";
|
||||
$lang->report->annualData->allDept = "Whole Company";
|
||||
$lang->report->annualData->soFar = " (%s)";
|
||||
$lang->report->annualData->baseInfo = "Basic Data";
|
||||
$lang->report->annualData->actionData = "Operation Data";
|
||||
$lang->report->annualData->contributionData = "Contribution Data";
|
||||
$lang->report->annualData->radar = "Capability Radar Chart";
|
||||
$lang->report->annualData->projects = "{$lang->projectCommon} Data";
|
||||
$lang->report->annualData->products = "{$lang->productCommon} Data";
|
||||
$lang->report->annualData->stories = "Story Data";
|
||||
$lang->report->annualData->tasks = "Task Data";
|
||||
$lang->report->annualData->bugs = "Bug Data";
|
||||
$lang->report->annualData->cases = "Case Data";
|
||||
$lang->report->annualData->statusStat = "{$lang->storyCommon}/task/bug status distribution (as of today)";
|
||||
|
||||
$lang->report->annualData->companyUsers = "Number of company";
|
||||
$lang->report->annualData->deptUsers = "Number of departments";
|
||||
$lang->report->annualData->logins = "Login times";
|
||||
$lang->report->annualData->actions = "Number of operations";
|
||||
$lang->report->annualData->contributions = "Number of contributions";
|
||||
$lang->report->annualData->consumed = "Consumed";
|
||||
$lang->report->annualData->todos = "Number of Todos";
|
||||
|
||||
$lang->report->annualData->storyStatusStat = "Story status distribution";
|
||||
$lang->report->annualData->taskStatusStat = "Task status distribution";
|
||||
$lang->report->annualData->bugStatusStat = "Bug status distribution";
|
||||
$lang->report->annualData->caseResultStat = "Case result distribution";
|
||||
$lang->report->annualData->allStory = "Total";
|
||||
$lang->report->annualData->allTask = "Total";
|
||||
$lang->report->annualData->allBug = "Total";
|
||||
$lang->report->annualData->undone = "Undone";
|
||||
$lang->report->annualData->unresolve = "Unresolve";
|
||||
|
||||
$lang->report->annualData->storyMonthActions = "Monthly story operation";
|
||||
$lang->report->annualData->taskMonthActions = "Monthly task operation";
|
||||
$lang->report->annualData->bugMonthActions = "Monthly bug operation";
|
||||
$lang->report->annualData->caseMonthActions = "Monthly case operation";
|
||||
|
||||
$lang->report->annualData->projectFields['name'] = "{$lang->projectCommon} name";
|
||||
$lang->report->annualData->projectFields['story'] = "Finished stories";
|
||||
$lang->report->annualData->projectFields['task'] = "Finished tasks";
|
||||
$lang->report->annualData->projectFields['bug'] = "Resolved bugs";
|
||||
|
||||
$lang->report->annualData->productFields['name'] = "{$lang->productCommon} name";
|
||||
$lang->report->annualData->productFields['plan'] = "Plans";
|
||||
global $config;
|
||||
if(!empty($config->URAndSR))
|
||||
{
|
||||
$lang->report->annualData->productFields['requirement'] = "Created requirements";
|
||||
}
|
||||
$lang->report->annualData->productFields['story'] = "Created stories";
|
||||
$lang->report->annualData->productFields['finished'] = "Finished stories";
|
||||
|
||||
$lang->report->annualData->objectTypeList['product'] = $lang->productCommon;
|
||||
$lang->report->annualData->objectTypeList['story'] = $lang->storyCommon;
|
||||
$lang->report->annualData->objectTypeList['productplan'] = "Plan";
|
||||
$lang->report->annualData->objectTypeList['release'] = "Release";
|
||||
$lang->report->annualData->objectTypeList['project'] = $lang->projectCommon;
|
||||
$lang->report->annualData->objectTypeList['task'] = 'Task';
|
||||
$lang->report->annualData->objectTypeList['repo'] = 'Code';
|
||||
$lang->report->annualData->objectTypeList['bug'] = 'Bug';
|
||||
$lang->report->annualData->objectTypeList['build'] = 'Build';
|
||||
$lang->report->annualData->objectTypeList['testtask'] = 'TestTask';
|
||||
$lang->report->annualData->objectTypeList['case'] = 'Case';
|
||||
$lang->report->annualData->objectTypeList['doc'] = 'Document';
|
||||
|
||||
$lang->report->annualData->actionList['create'] = 'Created';
|
||||
$lang->report->annualData->actionList['edit'] = 'Edited';
|
||||
$lang->report->annualData->actionList['close'] = 'Closed';
|
||||
$lang->report->annualData->actionList['review'] = 'Reviewed';
|
||||
$lang->report->annualData->actionList['gitCommit'] = 'GIT Commited';
|
||||
$lang->report->annualData->actionList['svnCommit'] = 'SVN Commited';
|
||||
$lang->report->annualData->actionList['start'] = 'Started';
|
||||
$lang->report->annualData->actionList['finish'] = 'Finished';
|
||||
$lang->report->annualData->actionList['assign'] = 'Assigned';
|
||||
$lang->report->annualData->actionList['activate'] = 'Activated';
|
||||
$lang->report->annualData->actionList['resolve'] = 'Resolved';
|
||||
$lang->report->annualData->actionList['run'] = 'Execute';
|
||||
$lang->report->annualData->actionList['change'] = 'Changed';
|
||||
$lang->report->annualData->actionList['pause'] = 'Paused';
|
||||
$lang->report->annualData->actionList['cancel'] = 'Canceled';
|
||||
$lang->report->annualData->actionList['confirm'] = 'Confirmed';
|
||||
$lang->report->annualData->actionList['createBug'] = 'Turn to bug';
|
||||
|
||||
$lang->report->annualData->todoStatus['all'] = 'All';
|
||||
$lang->report->annualData->todoStatus['undone'] = 'Undone';
|
||||
$lang->report->annualData->todoStatus['done'] = 'Done';
|
||||
|
||||
$lang->report->annualData->radarItems['product'] = "Product";
|
||||
$lang->report->annualData->radarItems['project'] = "Project";
|
||||
$lang->report->annualData->radarItems['devel'] = "Development";
|
||||
$lang->report->annualData->radarItems['qa'] = "QA";
|
||||
$lang->report->annualData->radarItems['other'] = "Other";
|
||||
|
||||
+89
-39
@@ -109,49 +109,99 @@ $lang->report->proVersion = '<a href="https://api.zentao.net/goto.php?item=pro
|
||||
$lang->report->proVersionEn = '<a href="http://api.zentao.pm/goto.php?item=proversion&from=reportpage" target="_blank">Try ZenTao Pro for more!</a>';
|
||||
|
||||
$lang->report->annualData = new stdclass();
|
||||
$lang->report->annualData->title = "%s Work Summary —— %s";
|
||||
$lang->report->annualData->baseInfo = "Basic Information";
|
||||
$lang->report->annualData->logins = "Login";
|
||||
$lang->report->annualData->actions = "Action";
|
||||
$lang->report->annualData->efforts = "Effort";
|
||||
$lang->report->annualData->consumed = "Hour Cost";
|
||||
$lang->report->annualData->foundBugs = "Bug Reported";
|
||||
$lang->report->annualData->createdCases = "Case Created";
|
||||
$lang->report->annualData->involvedProducts = "{$lang->productCommon} Involved";
|
||||
$lang->report->annualData->createdPlans = "Plan Created";
|
||||
$lang->report->annualData->createdStories = "{$lang->SRCommon} Created";
|
||||
$lang->report->annualData->title = "%s work summary in %s";
|
||||
$lang->report->annualData->exportByZentao = "Export By ZenTao";
|
||||
$lang->report->annualData->scope = "Scope";
|
||||
$lang->report->annualData->allUser = "All Users";
|
||||
$lang->report->annualData->allDept = "Whole Company";
|
||||
$lang->report->annualData->soFar = " (%s)";
|
||||
$lang->report->annualData->baseInfo = "Basic Data";
|
||||
$lang->report->annualData->actionData = "Operation Data";
|
||||
$lang->report->annualData->contributionData = "Contribution Data";
|
||||
$lang->report->annualData->radar = "Capability Radar Chart";
|
||||
$lang->report->annualData->projects = "{$lang->projectCommon} Data";
|
||||
$lang->report->annualData->products = "{$lang->productCommon} Data";
|
||||
$lang->report->annualData->stories = "Story Data";
|
||||
$lang->report->annualData->tasks = "Task Data";
|
||||
$lang->report->annualData->bugs = "Bug Data";
|
||||
$lang->report->annualData->cases = "Case Data";
|
||||
$lang->report->annualData->statusStat = "{$lang->storyCommon}/task/bug status distribution (as of today)";
|
||||
|
||||
$lang->report->annualData->productOverview = "{$lang->productCommon} {$lang->SRCommon} Count and Percent";
|
||||
$lang->report->annualData->qaOverview = "{$lang->productCommon} Bug Count and Percent";
|
||||
$lang->report->annualData->projectOverview = "{$lang->executionCommon} Overview";
|
||||
$lang->report->annualData->doneProject = "Done {$lang->executionCommon}";
|
||||
$lang->report->annualData->doingProject = "Ongoing {$lang->executionCommon}";
|
||||
$lang->report->annualData->suspendProject = "Suspended {$lang->executionCommon}";
|
||||
$lang->report->annualData->companyUsers = "Number of company";
|
||||
$lang->report->annualData->deptUsers = "Number of departments";
|
||||
$lang->report->annualData->logins = "Login times";
|
||||
$lang->report->annualData->actions = "Number of operations";
|
||||
$lang->report->annualData->contributions = "Number of contributions";
|
||||
$lang->report->annualData->consumed = "Consumed";
|
||||
$lang->report->annualData->todos = "Number of Todos";
|
||||
|
||||
$lang->report->annualData->projectName = "{$lang->executionCommon}";
|
||||
$lang->report->annualData->finishedStory = "{$lang->SRCommon} Finished";
|
||||
$lang->report->annualData->finishedTask = 'Task Finished';
|
||||
$lang->report->annualData->foundBug = 'Bug Reported';
|
||||
$lang->report->annualData->resolvedBug = 'Bug Resolved';
|
||||
$lang->report->annualData->productName = "{$lang->productCommon}";
|
||||
$lang->report->annualData->planCount = 'Plan';
|
||||
$lang->report->annualData->storyCount = "{$lang->SRCommon}";
|
||||
$lang->report->annualData->storyStatusStat = "Story status distribution";
|
||||
$lang->report->annualData->taskStatusStat = "Task status distribution";
|
||||
$lang->report->annualData->bugStatusStat = "Bug status distribution";
|
||||
$lang->report->annualData->caseResultStat = "Case result distribution";
|
||||
$lang->report->annualData->allStory = "Total";
|
||||
$lang->report->annualData->allTask = "Total";
|
||||
$lang->report->annualData->allBug = "Total";
|
||||
$lang->report->annualData->undone = "Undone";
|
||||
$lang->report->annualData->unresolve = "Unresolve";
|
||||
|
||||
$lang->report->annualData->qaData = "Bug Reported and Case Created";
|
||||
$lang->report->annualData->totalCreatedBug = 'Bug Reported';
|
||||
$lang->report->annualData->totalCreatedCase = 'Case Created';
|
||||
$lang->report->annualData->storyMonthActions = "Monthly story operation";
|
||||
$lang->report->annualData->taskMonthActions = "Monthly task operation";
|
||||
$lang->report->annualData->bugMonthActions = "Monthly bug operation";
|
||||
$lang->report->annualData->caseMonthActions = "Monthly case operation";
|
||||
|
||||
$lang->report->annualData->devData = "Task Finished and Bug Resolved";
|
||||
$lang->report->annualData->totalFinishedTask = 'Task Finished';
|
||||
$lang->report->annualData->totalResolvedBug = 'Bug Resolved';
|
||||
$lang->report->annualData->totalConsumed = 'Hour Cost';
|
||||
$lang->report->annualData->projectFields['name'] = "{$lang->projectCommon} name";
|
||||
$lang->report->annualData->projectFields['story'] = "Finished stories";
|
||||
$lang->report->annualData->projectFields['task'] = "Finished tasks";
|
||||
$lang->report->annualData->projectFields['bug'] = "Resolved bugs";
|
||||
|
||||
$lang->report->annualData->poData = "{$lang->SRCommon} Created, Priority and Status";
|
||||
$lang->report->annualData->totalStoryPri = "{$lang->SRCommon} Priority";
|
||||
$lang->report->annualData->totalStoryStage = "{$lang->SRCommon} Stage";
|
||||
$lang->report->annualData->productFields['name'] = "{$lang->productCommon} name";
|
||||
$lang->report->annualData->productFields['plan'] = "Plans";
|
||||
global $config;
|
||||
if(!empty($config->URAndSR))
|
||||
{
|
||||
$lang->report->annualData->productFields['requirement'] = "Created requirements";
|
||||
}
|
||||
$lang->report->annualData->productFields['story'] = "Created stories";
|
||||
$lang->report->annualData->productFields['finished'] = "Finished stories";
|
||||
|
||||
$lang->report->annualData->qaStatistics = "Monthly Created Bug and Case";
|
||||
$lang->report->annualData->poStatistics = "Monthly Created {$lang->SRCommon}";
|
||||
$lang->report->annualData->devStatistics = "Monthly Finished Task, Hour, and Resolved Bug";
|
||||
$lang->report->annualData->objectTypeList['product'] = $lang->productCommon;
|
||||
$lang->report->annualData->objectTypeList['story'] = $lang->storyCommon;
|
||||
$lang->report->annualData->objectTypeList['productplan'] = "Plan";
|
||||
$lang->report->annualData->objectTypeList['release'] = "Release";
|
||||
$lang->report->annualData->objectTypeList['project'] = $lang->projectCommon;
|
||||
$lang->report->annualData->objectTypeList['task'] = 'Task';
|
||||
$lang->report->annualData->objectTypeList['repo'] = 'Code';
|
||||
$lang->report->annualData->objectTypeList['bug'] = 'Bug';
|
||||
$lang->report->annualData->objectTypeList['build'] = 'Build';
|
||||
$lang->report->annualData->objectTypeList['testtask'] = 'TestTask';
|
||||
$lang->report->annualData->objectTypeList['case'] = 'Case';
|
||||
$lang->report->annualData->objectTypeList['doc'] = 'Document';
|
||||
|
||||
$lang->report->annualData->unit = " ";
|
||||
$lang->report->annualData->actionList['create'] = 'Created';
|
||||
$lang->report->annualData->actionList['edit'] = 'Edited';
|
||||
$lang->report->annualData->actionList['close'] = 'Closed';
|
||||
$lang->report->annualData->actionList['review'] = 'Reviewed';
|
||||
$lang->report->annualData->actionList['gitCommit'] = 'GIT Commited';
|
||||
$lang->report->annualData->actionList['svnCommit'] = 'SVN Commited';
|
||||
$lang->report->annualData->actionList['start'] = 'Started';
|
||||
$lang->report->annualData->actionList['finish'] = 'Finished';
|
||||
$lang->report->annualData->actionList['assign'] = 'Assigned';
|
||||
$lang->report->annualData->actionList['activate'] = 'Activated';
|
||||
$lang->report->annualData->actionList['resolve'] = 'Resolved';
|
||||
$lang->report->annualData->actionList['run'] = 'Execute';
|
||||
$lang->report->annualData->actionList['change'] = 'Changed';
|
||||
$lang->report->annualData->actionList['pause'] = 'Paused';
|
||||
$lang->report->annualData->actionList['cancel'] = 'Canceled';
|
||||
$lang->report->annualData->actionList['confirm'] = 'Confirmed';
|
||||
$lang->report->annualData->actionList['createBug'] = 'Turn to bug';
|
||||
|
||||
$lang->report->annualData->todoStatus['all'] = 'All';
|
||||
$lang->report->annualData->todoStatus['undone'] = 'Undone';
|
||||
$lang->report->annualData->todoStatus['done'] = 'Done';
|
||||
|
||||
$lang->report->annualData->radarItems['product'] = "Product";
|
||||
$lang->report->annualData->radarItems['project'] = "Project";
|
||||
$lang->report->annualData->radarItems['devel'] = "Development";
|
||||
$lang->report->annualData->radarItems['qa'] = "QA";
|
||||
$lang->report->annualData->radarItems['other'] = "Other";
|
||||
|
||||
@@ -107,3 +107,101 @@ $lang->report->mailTitle->testTask = " Recettes (%s),";
|
||||
|
||||
$lang->report->proVersion = '<a href="https://www.zentao.pm/page/vs.html" target="_blank">Essayez ZenTao Pro pour en savoir plus !</a>';
|
||||
$lang->report->proVersionEn = '<a href="https://www.zentao.pm/page/vs.html" target="_blank">Try ZenTao Pro for more!</a>';
|
||||
|
||||
$lang->report->annualData = new stdclass();
|
||||
$lang->report->annualData->title = "%s work summary in %s";
|
||||
$lang->report->annualData->exportByZentao = "Export By ZenTao";
|
||||
$lang->report->annualData->scope = "Scope";
|
||||
$lang->report->annualData->allUser = "All Users";
|
||||
$lang->report->annualData->allDept = "Whole Company";
|
||||
$lang->report->annualData->soFar = " (%s)";
|
||||
$lang->report->annualData->baseInfo = "Basic Data";
|
||||
$lang->report->annualData->actionData = "Operation Data";
|
||||
$lang->report->annualData->contributionData = "Contribution Data";
|
||||
$lang->report->annualData->radar = "Capability Radar Chart";
|
||||
$lang->report->annualData->projects = "{$lang->projectCommon} Data";
|
||||
$lang->report->annualData->products = "{$lang->productCommon} Data";
|
||||
$lang->report->annualData->stories = "Story Data";
|
||||
$lang->report->annualData->tasks = "Task Data";
|
||||
$lang->report->annualData->bugs = "Bug Data";
|
||||
$lang->report->annualData->cases = "Case Data";
|
||||
$lang->report->annualData->statusStat = "{$lang->storyCommon}/task/bug status distribution (as of today)";
|
||||
|
||||
$lang->report->annualData->companyUsers = "Number of company";
|
||||
$lang->report->annualData->deptUsers = "Number of departments";
|
||||
$lang->report->annualData->logins = "Login times";
|
||||
$lang->report->annualData->actions = "Number of operations";
|
||||
$lang->report->annualData->contributions = "Number of contributions";
|
||||
$lang->report->annualData->consumed = "Consumed";
|
||||
$lang->report->annualData->todos = "Number of Todos";
|
||||
|
||||
$lang->report->annualData->storyStatusStat = "Story status distribution";
|
||||
$lang->report->annualData->taskStatusStat = "Task status distribution";
|
||||
$lang->report->annualData->bugStatusStat = "Bug status distribution";
|
||||
$lang->report->annualData->caseResultStat = "Case result distribution";
|
||||
$lang->report->annualData->allStory = "Total";
|
||||
$lang->report->annualData->allTask = "Total";
|
||||
$lang->report->annualData->allBug = "Total";
|
||||
$lang->report->annualData->undone = "Undone";
|
||||
$lang->report->annualData->unresolve = "Unresolve";
|
||||
|
||||
$lang->report->annualData->storyMonthActions = "Monthly story operation";
|
||||
$lang->report->annualData->taskMonthActions = "Monthly task operation";
|
||||
$lang->report->annualData->bugMonthActions = "Monthly bug operation";
|
||||
$lang->report->annualData->caseMonthActions = "Monthly case operation";
|
||||
|
||||
$lang->report->annualData->projectFields['name'] = "{$lang->projectCommon} name";
|
||||
$lang->report->annualData->projectFields['story'] = "Finished stories";
|
||||
$lang->report->annualData->projectFields['task'] = "Finished tasks";
|
||||
$lang->report->annualData->projectFields['bug'] = "Resolved bugs";
|
||||
|
||||
$lang->report->annualData->productFields['name'] = "{$lang->productCommon} name";
|
||||
$lang->report->annualData->productFields['plan'] = "Plans";
|
||||
global $config;
|
||||
if(!empty($config->URAndSR))
|
||||
{
|
||||
$lang->report->annualData->productFields['requirement'] = "Created requirements";
|
||||
}
|
||||
$lang->report->annualData->productFields['story'] = "Created stories";
|
||||
$lang->report->annualData->productFields['finished'] = "Finished stories";
|
||||
|
||||
$lang->report->annualData->objectTypeList['product'] = $lang->productCommon;
|
||||
$lang->report->annualData->objectTypeList['story'] = $lang->storyCommon;
|
||||
$lang->report->annualData->objectTypeList['productplan'] = "Plan";
|
||||
$lang->report->annualData->objectTypeList['release'] = "Release";
|
||||
$lang->report->annualData->objectTypeList['project'] = $lang->projectCommon;
|
||||
$lang->report->annualData->objectTypeList['task'] = 'Task';
|
||||
$lang->report->annualData->objectTypeList['repo'] = 'Code';
|
||||
$lang->report->annualData->objectTypeList['bug'] = 'Bug';
|
||||
$lang->report->annualData->objectTypeList['build'] = 'Build';
|
||||
$lang->report->annualData->objectTypeList['testtask'] = 'TestTask';
|
||||
$lang->report->annualData->objectTypeList['case'] = 'Case';
|
||||
$lang->report->annualData->objectTypeList['doc'] = 'Document';
|
||||
|
||||
$lang->report->annualData->actionList['create'] = 'Created';
|
||||
$lang->report->annualData->actionList['edit'] = 'Edited';
|
||||
$lang->report->annualData->actionList['close'] = 'Closed';
|
||||
$lang->report->annualData->actionList['review'] = 'Reviewed';
|
||||
$lang->report->annualData->actionList['gitCommit'] = 'GIT Commited';
|
||||
$lang->report->annualData->actionList['svnCommit'] = 'SVN Commited';
|
||||
$lang->report->annualData->actionList['start'] = 'Started';
|
||||
$lang->report->annualData->actionList['finish'] = 'Finished';
|
||||
$lang->report->annualData->actionList['assign'] = 'Assigned';
|
||||
$lang->report->annualData->actionList['activate'] = 'Activated';
|
||||
$lang->report->annualData->actionList['resolve'] = 'Resolved';
|
||||
$lang->report->annualData->actionList['run'] = 'Execute';
|
||||
$lang->report->annualData->actionList['change'] = 'Changed';
|
||||
$lang->report->annualData->actionList['pause'] = 'Paused';
|
||||
$lang->report->annualData->actionList['cancel'] = 'Canceled';
|
||||
$lang->report->annualData->actionList['confirm'] = 'Confirmed';
|
||||
$lang->report->annualData->actionList['createBug'] = 'Turn to bug';
|
||||
|
||||
$lang->report->annualData->todoStatus['all'] = 'All';
|
||||
$lang->report->annualData->todoStatus['undone'] = 'Undone';
|
||||
$lang->report->annualData->todoStatus['done'] = 'Done';
|
||||
|
||||
$lang->report->annualData->radarItems['product'] = "Product";
|
||||
$lang->report->annualData->radarItems['project'] = "Project";
|
||||
$lang->report->annualData->radarItems['devel'] = "Development";
|
||||
$lang->report->annualData->radarItems['qa'] = "QA";
|
||||
$lang->report->annualData->radarItems['other'] = "Other";
|
||||
|
||||
+89
-39
@@ -109,49 +109,99 @@ $lang->report->proVersion = '<a href="https://api.zentao.net/goto.php?item=pro
|
||||
$lang->report->proVersionEn = '<a href="http://api.zentao.pm/goto.php?item=proversion&from=reportpage" target="_blank">Hãy thử ZenTao Pro để biết thêm!</a>';
|
||||
|
||||
$lang->report->annualData = new stdclass();
|
||||
$lang->report->annualData->title = "%s Tóm tắt công việc - %s";
|
||||
$lang->report->annualData->baseInfo = "Thông tin cơ bản";
|
||||
$lang->report->annualData->logins = "Đăng nhập";
|
||||
$lang->report->annualData->actions = "Hành động";
|
||||
$lang->report->annualData->efforts = "Chấm công";
|
||||
$lang->report->annualData->consumed = "Giờ đã làm";
|
||||
$lang->report->annualData->foundBugs = "Bug được tạo";
|
||||
$lang->report->annualData->createdCases = "Tình huống được tạo";
|
||||
$lang->report->annualData->involvedProducts = "{$lang->productCommon} liên quan";
|
||||
$lang->report->annualData->createdPlans = "Kế hoạch được tạo";
|
||||
$lang->report->annualData->createdStories = "{$lang->SRCommon} được tạo";
|
||||
$lang->report->annualData->title = "%s work summary in %s";
|
||||
$lang->report->annualData->exportByZentao = "Export By ZenTao";
|
||||
$lang->report->annualData->scope = "Scope";
|
||||
$lang->report->annualData->allUser = "All Users";
|
||||
$lang->report->annualData->allDept = "Whole Company";
|
||||
$lang->report->annualData->soFar = " (%s)";
|
||||
$lang->report->annualData->baseInfo = "Basic Data";
|
||||
$lang->report->annualData->actionData = "Operation Data";
|
||||
$lang->report->annualData->contributionData = "Contribution Data";
|
||||
$lang->report->annualData->radar = "Capability Radar Chart";
|
||||
$lang->report->annualData->projects = "{$lang->projectCommon} Data";
|
||||
$lang->report->annualData->products = "{$lang->productCommon} Data";
|
||||
$lang->report->annualData->stories = "Story Data";
|
||||
$lang->report->annualData->tasks = "Task Data";
|
||||
$lang->report->annualData->bugs = "Bug Data";
|
||||
$lang->report->annualData->cases = "Case Data";
|
||||
$lang->report->annualData->statusStat = "{$lang->storyCommon}/task/bug status distribution (as of today)";
|
||||
|
||||
$lang->report->annualData->productOverview = "{$lang->productCommon} {$lang->SRCommon} số lượng và Phần trăm";
|
||||
$lang->report->annualData->qaOverview = "Bug {$lang->productCommon} số lượng và Phần trăm";
|
||||
$lang->report->annualData->projectOverview = "Tổng quan {$lang->executionCommon}";
|
||||
$lang->report->annualData->doneProject = "{$lang->executionCommon} hoàn thành";
|
||||
$lang->report->annualData->doingProject = "{$lang->executionCommon} đang thực hiện";
|
||||
$lang->report->annualData->suspendProject = "{$lang->executionCommon} bị đình chỉ";
|
||||
$lang->report->annualData->companyUsers = "Number of company";
|
||||
$lang->report->annualData->deptUsers = "Number of departments";
|
||||
$lang->report->annualData->logins = "Login times";
|
||||
$lang->report->annualData->actions = "Number of operations";
|
||||
$lang->report->annualData->contributions = "Number of contributions";
|
||||
$lang->report->annualData->consumed = "Consumed";
|
||||
$lang->report->annualData->todos = "Number of Todos";
|
||||
|
||||
$lang->report->annualData->projectName = "{$lang->executionCommon}";
|
||||
$lang->report->annualData->finishedStory = "{$lang->SRCommon} kết thúc";
|
||||
$lang->report->annualData->finishedTask = 'Nhiệm vụ hoàn thành';
|
||||
$lang->report->annualData->foundBug = 'Bug được báo cáo';
|
||||
$lang->report->annualData->resolvedBug = 'Bug được giải quyết';
|
||||
$lang->report->annualData->productName = "{$lang->productCommon}";
|
||||
$lang->report->annualData->planCount = 'Kế hoạch';
|
||||
$lang->report->annualData->storyCount = "{$lang->SRCommon}";
|
||||
$lang->report->annualData->storyStatusStat = "Story status distribution";
|
||||
$lang->report->annualData->taskStatusStat = "Task status distribution";
|
||||
$lang->report->annualData->bugStatusStat = "Bug status distribution";
|
||||
$lang->report->annualData->caseResultStat = "Case result distribution";
|
||||
$lang->report->annualData->allStory = "Total";
|
||||
$lang->report->annualData->allTask = "Total";
|
||||
$lang->report->annualData->allBug = "Total";
|
||||
$lang->report->annualData->undone = "Undone";
|
||||
$lang->report->annualData->unresolve = "Unresolve";
|
||||
|
||||
$lang->report->annualData->qaData = "Bug được tạo và Tình huống được tạo";
|
||||
$lang->report->annualData->totalCreatedBug = 'Bug được báo cáo';
|
||||
$lang->report->annualData->totalCreatedCase = 'Tình huống được tạo';
|
||||
$lang->report->annualData->storyMonthActions = "Monthly story operation";
|
||||
$lang->report->annualData->taskMonthActions = "Monthly task operation";
|
||||
$lang->report->annualData->bugMonthActions = "Monthly bug operation";
|
||||
$lang->report->annualData->caseMonthActions = "Monthly case operation";
|
||||
|
||||
$lang->report->annualData->devData = "Nhiệm vụ hoàn thành và Bug được giải quyết";
|
||||
$lang->report->annualData->totalFinishedTask = 'Nhiệm vụ hoàn thành';
|
||||
$lang->report->annualData->totalResolvedBug = 'Bug được giải quyết';
|
||||
$lang->report->annualData->totalConsumed = 'Đã làm';
|
||||
$lang->report->annualData->projectFields['name'] = "{$lang->projectCommon} name";
|
||||
$lang->report->annualData->projectFields['story'] = "Finished stories";
|
||||
$lang->report->annualData->projectFields['task'] = "Finished tasks";
|
||||
$lang->report->annualData->projectFields['bug'] = "Resolved bugs";
|
||||
|
||||
$lang->report->annualData->poData = "{$lang->SRCommon} được tạo, Ưu tiên và tình trạng";
|
||||
$lang->report->annualData->totalStoryPri = "{$lang->SRCommon} Ưu tiên";
|
||||
$lang->report->annualData->totalStoryStage = "Giai đoạn {$lang->SRCommon}";
|
||||
$lang->report->annualData->productFields['name'] = "{$lang->productCommon} name";
|
||||
$lang->report->annualData->productFields['plan'] = "Plans";
|
||||
global $config;
|
||||
if(!empty($config->URAndSR))
|
||||
{
|
||||
$lang->report->annualData->productFields['requirement'] = "Created requirements";
|
||||
}
|
||||
$lang->report->annualData->productFields['story'] = "Created stories";
|
||||
$lang->report->annualData->productFields['finished'] = "Finished stories";
|
||||
|
||||
$lang->report->annualData->qaStatistics = "Bug được tạo hàng tháng và Tình huống";
|
||||
$lang->report->annualData->poStatistics = "{$lang->SRCommon} được tạo hàng tháng";
|
||||
$lang->report->annualData->devStatistics = "Nhiệm vụ hoàn thành háng tháng, giờ và Bug được giải quyết";
|
||||
$lang->report->annualData->objectTypeList['product'] = $lang->productCommon;
|
||||
$lang->report->annualData->objectTypeList['story'] = $lang->storyCommon;
|
||||
$lang->report->annualData->objectTypeList['productplan'] = "Plan";
|
||||
$lang->report->annualData->objectTypeList['release'] = "Release";
|
||||
$lang->report->annualData->objectTypeList['project'] = $lang->projectCommon;
|
||||
$lang->report->annualData->objectTypeList['task'] = 'Task';
|
||||
$lang->report->annualData->objectTypeList['repo'] = 'Code';
|
||||
$lang->report->annualData->objectTypeList['bug'] = 'Bug';
|
||||
$lang->report->annualData->objectTypeList['build'] = 'Build';
|
||||
$lang->report->annualData->objectTypeList['testtask'] = 'TestTask';
|
||||
$lang->report->annualData->objectTypeList['case'] = 'Case';
|
||||
$lang->report->annualData->objectTypeList['doc'] = 'Document';
|
||||
|
||||
$lang->report->annualData->unit = " ";
|
||||
$lang->report->annualData->actionList['create'] = 'Created';
|
||||
$lang->report->annualData->actionList['edit'] = 'Edited';
|
||||
$lang->report->annualData->actionList['close'] = 'Closed';
|
||||
$lang->report->annualData->actionList['review'] = 'Reviewed';
|
||||
$lang->report->annualData->actionList['gitCommit'] = 'GIT Commited';
|
||||
$lang->report->annualData->actionList['svnCommit'] = 'SVN Commited';
|
||||
$lang->report->annualData->actionList['start'] = 'Started';
|
||||
$lang->report->annualData->actionList['finish'] = 'Finished';
|
||||
$lang->report->annualData->actionList['assign'] = 'Assigned';
|
||||
$lang->report->annualData->actionList['activate'] = 'Activated';
|
||||
$lang->report->annualData->actionList['resolve'] = 'Resolved';
|
||||
$lang->report->annualData->actionList['run'] = 'Execute';
|
||||
$lang->report->annualData->actionList['change'] = 'Changed';
|
||||
$lang->report->annualData->actionList['pause'] = 'Paused';
|
||||
$lang->report->annualData->actionList['cancel'] = 'Canceled';
|
||||
$lang->report->annualData->actionList['confirm'] = 'Confirmed';
|
||||
$lang->report->annualData->actionList['createBug'] = 'Turn to bug';
|
||||
|
||||
$lang->report->annualData->todoStatus['all'] = 'All';
|
||||
$lang->report->annualData->todoStatus['undone'] = 'Undone';
|
||||
$lang->report->annualData->todoStatus['done'] = 'Done';
|
||||
|
||||
$lang->report->annualData->radarItems['product'] = "Product";
|
||||
$lang->report->annualData->radarItems['project'] = "Project";
|
||||
$lang->report->annualData->radarItems['devel'] = "Development";
|
||||
$lang->report->annualData->radarItems['qa'] = "QA";
|
||||
$lang->report->annualData->radarItems['other'] = "Other";
|
||||
|
||||
@@ -109,49 +109,99 @@ $lang->report->proVersion = '<a href="https://api.zentao.net/goto.php?item=pro
|
||||
$lang->report->proVersionEn = '<a href="http://api.zentao.pm/goto.php?item=proversion&from=reportpage" target="_blank">Try ZenTao Pro for more!</a>';
|
||||
|
||||
$lang->report->annualData = new stdclass();
|
||||
$lang->report->annualData->title = "%s年工作内容统计一览表 —— %s";
|
||||
$lang->report->annualData->baseInfo = "基本数据信息";
|
||||
$lang->report->annualData->logins = "累计登录次数";
|
||||
$lang->report->annualData->actions = "累计动态数";
|
||||
$lang->report->annualData->efforts = "累计日志数";
|
||||
$lang->report->annualData->consumed = "累计工时数";
|
||||
$lang->report->annualData->foundBugs = "累计创建Bug数";
|
||||
$lang->report->annualData->createdCases = "累计创建用例数";
|
||||
$lang->report->annualData->involvedProducts = "累计参与{$lang->productCommon}数";
|
||||
$lang->report->annualData->createdPlans = "累计创建计划数";
|
||||
$lang->report->annualData->createdStories = "累计创建{$lang->SRCommon}数";
|
||||
$lang->report->annualData->title = "%s %s年工作汇总";
|
||||
$lang->report->annualData->exportByZentao = "由禅道系统导出";
|
||||
$lang->report->annualData->scope = "统计范围";
|
||||
$lang->report->annualData->allUser = "所有用户";
|
||||
$lang->report->annualData->allDept = "全公司";
|
||||
$lang->report->annualData->soFar = "(%s年)";
|
||||
$lang->report->annualData->baseInfo = "基本数据";
|
||||
$lang->report->annualData->actionData = "操作数据";
|
||||
$lang->report->annualData->contributionData = "贡献数据";
|
||||
$lang->report->annualData->radar = "能力雷达图";
|
||||
$lang->report->annualData->projects = "{$lang->projectCommon}数据";
|
||||
$lang->report->annualData->products = "{$lang->productCommon}数据";
|
||||
$lang->report->annualData->stories = "需求数据";
|
||||
$lang->report->annualData->tasks = "任务数据";
|
||||
$lang->report->annualData->bugs = "Bug数据";
|
||||
$lang->report->annualData->cases = "用例数据";
|
||||
$lang->report->annualData->statusStat = "{$lang->storyCommon}/任务/Bug状态分布(截止今日)";
|
||||
|
||||
$lang->report->annualData->productOverview = "{$lang->productCommon}创建{$lang->SRCommon}数及占比";
|
||||
$lang->report->annualData->qaOverview = "{$lang->productCommon}创建Bug数及占比";
|
||||
$lang->report->annualData->projectOverview = "参与{$lang->executionCommon}概览";
|
||||
$lang->report->annualData->doneProject = "已完成的{$lang->executionCommon}";
|
||||
$lang->report->annualData->doingProject = "正在进行的{$lang->executionCommon}";
|
||||
$lang->report->annualData->suspendProject = "已挂起的{$lang->executionCommon}";
|
||||
$lang->report->annualData->companyUsers = "公司总人数";
|
||||
$lang->report->annualData->deptUsers = "部门人数";
|
||||
$lang->report->annualData->logins = "登录次数";
|
||||
$lang->report->annualData->actions = "操作次数";
|
||||
$lang->report->annualData->contributions = "贡献数";
|
||||
$lang->report->annualData->consumed = "消耗工时";
|
||||
$lang->report->annualData->todos = "待办数";
|
||||
|
||||
$lang->report->annualData->projectName = "{$lang->executionCommon}名称";
|
||||
$lang->report->annualData->finishedStory = "完成{$lang->SRCommon}数";
|
||||
$lang->report->annualData->finishedTask = '完成任务数';
|
||||
$lang->report->annualData->foundBug = '创建Bug数';
|
||||
$lang->report->annualData->resolvedBug = '解决Bug数';
|
||||
$lang->report->annualData->productName = "{$lang->productCommon}名称";
|
||||
$lang->report->annualData->planCount = "计划数";
|
||||
$lang->report->annualData->storyCount = "{$lang->SRCommon}数";
|
||||
$lang->report->annualData->storyStatusStat = "需求状态分布";
|
||||
$lang->report->annualData->taskStatusStat = "任务状态分布";
|
||||
$lang->report->annualData->bugStatusStat = "Bug状态分布";
|
||||
$lang->report->annualData->caseResultStat = "用例结果分布";
|
||||
$lang->report->annualData->allStory = "总需求";
|
||||
$lang->report->annualData->allTask = "总任务";
|
||||
$lang->report->annualData->allBug = "总Bug";
|
||||
$lang->report->annualData->undone = "未完成";
|
||||
$lang->report->annualData->unresolve = "未解决";
|
||||
|
||||
$lang->report->annualData->qaData = "累计创建Bug数和创建用例数";
|
||||
$lang->report->annualData->totalCreatedBug = '累计创建Bug数';
|
||||
$lang->report->annualData->totalCreatedCase = '累计创建用例数';
|
||||
$lang->report->annualData->storyMonthActions = "每月需求操作情况";
|
||||
$lang->report->annualData->taskMonthActions = "每月任务操作情况";
|
||||
$lang->report->annualData->bugMonthActions = "每月Bug操作情况";
|
||||
$lang->report->annualData->caseMonthActions = "每月用例操作情况";
|
||||
|
||||
$lang->report->annualData->devData = "完成任务数和解决Bug数";
|
||||
$lang->report->annualData->totalFinishedTask = '完成任务数';
|
||||
$lang->report->annualData->totalResolvedBug = '解决Bug数';
|
||||
$lang->report->annualData->totalConsumed = '累计工时';
|
||||
$lang->report->annualData->projectFields['name'] = "{$lang->projectCommon}名称";
|
||||
$lang->report->annualData->projectFields['story'] = "完成{$lang->storyCommon}数";
|
||||
$lang->report->annualData->projectFields['task'] = "完成任务数";
|
||||
$lang->report->annualData->projectFields['bug'] = "解决Bug数";
|
||||
|
||||
$lang->report->annualData->poData = "所创建{$lang->SRCommon}数和对应的优先级及状态";
|
||||
$lang->report->annualData->totalStoryPri = "创建{$lang->SRCommon}优先级分布";
|
||||
$lang->report->annualData->totalStoryStage = "创建{$lang->SRCommon}阶段分布";
|
||||
$lang->report->annualData->productFields['name'] = "{$lang->productCommon}名称";
|
||||
$lang->report->annualData->productFields['plan'] = "计划数";
|
||||
global $config;
|
||||
if(!empty($config->URAndSR))
|
||||
{
|
||||
$lang->report->annualData->productFields['requirement'] = "创建{$lang->URCommon}数";
|
||||
}
|
||||
$lang->report->annualData->productFields['story'] = "创建{$lang->storyCommon}数";
|
||||
$lang->report->annualData->productFields['finished'] = "完成需求数";
|
||||
|
||||
$lang->report->annualData->qaStatistics = "月创建Bug数和创建用例数";
|
||||
$lang->report->annualData->poStatistics = "月创建{$lang->SRCommon}数";
|
||||
$lang->report->annualData->devStatistics = "月完成任务数及累计工时和解决Bug数";
|
||||
$lang->report->annualData->objectTypeList['product'] = $lang->productCommon;
|
||||
$lang->report->annualData->objectTypeList['story'] = "需求";
|
||||
$lang->report->annualData->objectTypeList['productplan'] = "计划";
|
||||
$lang->report->annualData->objectTypeList['release'] = "发布";
|
||||
$lang->report->annualData->objectTypeList['project'] = $lang->projectCommon;
|
||||
$lang->report->annualData->objectTypeList['task'] = '任务';
|
||||
$lang->report->annualData->objectTypeList['repo'] = '代码';
|
||||
$lang->report->annualData->objectTypeList['bug'] = 'Bug';
|
||||
$lang->report->annualData->objectTypeList['build'] = '版本';
|
||||
$lang->report->annualData->objectTypeList['testtask'] = '测试单';
|
||||
$lang->report->annualData->objectTypeList['case'] = '用例';
|
||||
$lang->report->annualData->objectTypeList['doc'] = '文档';
|
||||
|
||||
$lang->report->annualData->unit = "个";
|
||||
$lang->report->annualData->actionList['create'] = '创建';
|
||||
$lang->report->annualData->actionList['edit'] = '编辑';
|
||||
$lang->report->annualData->actionList['close'] = '关闭';
|
||||
$lang->report->annualData->actionList['review'] = '评审';
|
||||
$lang->report->annualData->actionList['gitCommit'] = 'GIT提交';
|
||||
$lang->report->annualData->actionList['svnCommit'] = 'SVN提交';
|
||||
$lang->report->annualData->actionList['start'] = '开始';
|
||||
$lang->report->annualData->actionList['finish'] = '完成';
|
||||
$lang->report->annualData->actionList['assign'] = '指派';
|
||||
$lang->report->annualData->actionList['activate'] = '激活';
|
||||
$lang->report->annualData->actionList['resolve'] = '解决';
|
||||
$lang->report->annualData->actionList['run'] = '执行';
|
||||
$lang->report->annualData->actionList['change'] = '变更';
|
||||
$lang->report->annualData->actionList['pause'] = '暂停';
|
||||
$lang->report->annualData->actionList['cancel'] = '取消';
|
||||
$lang->report->annualData->actionList['confirm'] = '确认';
|
||||
$lang->report->annualData->actionList['createBug'] = '转Bug';
|
||||
|
||||
$lang->report->annualData->todoStatus['all'] = '所有待办';
|
||||
$lang->report->annualData->todoStatus['undone'] = '未完成';
|
||||
$lang->report->annualData->todoStatus['done'] = '已完成';
|
||||
|
||||
$lang->report->annualData->radarItems['product'] = '产品';
|
||||
$lang->report->annualData->radarItems['project'] = '项目';
|
||||
$lang->report->annualData->radarItems['devel'] = "研发";
|
||||
$lang->report->annualData->radarItems['qa'] = "测试";
|
||||
$lang->report->annualData->radarItems['other'] = "其他";
|
||||
|
||||
@@ -109,49 +109,99 @@ $lang->report->proVersion = '<a href="https://api.zentao.net/goto.php?item=pro
|
||||
$lang->report->proVersionEn = '<a href="http://api.zentao.pm/goto.php?item=proversion&from=reportpage" target="_blank">Try ZenTao Pro for more!</a>';
|
||||
|
||||
$lang->report->annualData = new stdclass();
|
||||
$lang->report->annualData->title = "%s年工作內容統計一覽表 —— %s";
|
||||
$lang->report->annualData->baseInfo = "基本數據信息";
|
||||
$lang->report->annualData->logins = "累計登錄次數";
|
||||
$lang->report->annualData->actions = "累計動態數";
|
||||
$lang->report->annualData->efforts = "累計日誌數";
|
||||
$lang->report->annualData->consumed = "累計工時數";
|
||||
$lang->report->annualData->foundBugs = "累計創建Bug數";
|
||||
$lang->report->annualData->createdCases = "累計創建用例數";
|
||||
$lang->report->annualData->involvedProducts = "累計參與{$lang->productCommon}數";
|
||||
$lang->report->annualData->createdPlans = "累計創建計劃數";
|
||||
$lang->report->annualData->createdStories = "累計創建{$lang->SRCommon}數";
|
||||
$lang->report->annualData->title = "%s %s年工作彙總";
|
||||
$lang->report->annualData->exportByZentao = "由禪道系統導出";
|
||||
$lang->report->annualData->scope = "統計範圍";
|
||||
$lang->report->annualData->allUser = "所有用戶";
|
||||
$lang->report->annualData->allDept = "全公司";
|
||||
$lang->report->annualData->soFar = "(%s年)";
|
||||
$lang->report->annualData->baseInfo = "基本數據";
|
||||
$lang->report->annualData->actionData = "操作數據";
|
||||
$lang->report->annualData->contributionData = "貢獻數據";
|
||||
$lang->report->annualData->radar = "能力雷達圖";
|
||||
$lang->report->annualData->projects = "{$lang->projectCommon}數據";
|
||||
$lang->report->annualData->products = "{$lang->productCommon}數據";
|
||||
$lang->report->annualData->stories = "需求數據";
|
||||
$lang->report->annualData->tasks = "任務數據";
|
||||
$lang->report->annualData->bugs = "Bug數據";
|
||||
$lang->report->annualData->cases = "用例數據";
|
||||
$lang->report->annualData->statusStat = "{$lang->storyCommon}/任務/Bug狀態分佈(截止今日)";
|
||||
|
||||
$lang->report->annualData->productOverview = "{$lang->productCommon}創建{$lang->SRCommon}數及占比";
|
||||
$lang->report->annualData->qaOverview = "{$lang->productCommon}創建Bug數及占比";
|
||||
$lang->report->annualData->projectOverview = "參與{$lang->executionCommon}概覽";
|
||||
$lang->report->annualData->doneProject = "已完成的{$lang->executionCommon}";
|
||||
$lang->report->annualData->doingProject = "正在進行的{$lang->executionCommon}";
|
||||
$lang->report->annualData->suspendProject = "已掛起的{$lang->executionCommon}";
|
||||
$lang->report->annualData->companyUsers = "公司總人數";
|
||||
$lang->report->annualData->deptUsers = "部門人數";
|
||||
$lang->report->annualData->logins = "登錄次數";
|
||||
$lang->report->annualData->actions = "操作次數";
|
||||
$lang->report->annualData->contributions = "貢獻數";
|
||||
$lang->report->annualData->consumed = "消耗工時";
|
||||
$lang->report->annualData->todos = "待辦數";
|
||||
|
||||
$lang->report->annualData->projectName = "{$lang->executionCommon}名稱";
|
||||
$lang->report->annualData->finishedStory = "完成{$lang->SRCommon}數";
|
||||
$lang->report->annualData->finishedTask = '完成任務數';
|
||||
$lang->report->annualData->foundBug = '創建Bug數';
|
||||
$lang->report->annualData->resolvedBug = '解決Bug數';
|
||||
$lang->report->annualData->productName = "{$lang->productCommon}名稱";
|
||||
$lang->report->annualData->planCount = "計劃數";
|
||||
$lang->report->annualData->storyCount = "{$lang->SRCommon}數";
|
||||
$lang->report->annualData->storyStatusStat = "需求狀態分佈";
|
||||
$lang->report->annualData->taskStatusStat = "任務狀態分佈";
|
||||
$lang->report->annualData->bugStatusStat = "Bug狀態分佈";
|
||||
$lang->report->annualData->caseResultStat = "用例結果分佈";
|
||||
$lang->report->annualData->allStory = "總需求";
|
||||
$lang->report->annualData->allTask = "總任務";
|
||||
$lang->report->annualData->allBug = "總Bug";
|
||||
$lang->report->annualData->undone = "未完成";
|
||||
$lang->report->annualData->unresolve = "未解決";
|
||||
|
||||
$lang->report->annualData->qaData = "累計創建Bug數和創建用例數";
|
||||
$lang->report->annualData->totalCreatedBug = '累計創建Bug數';
|
||||
$lang->report->annualData->totalCreatedCase = '累計創建用例數';
|
||||
$lang->report->annualData->storyMonthActions = "每月需求操作情況";
|
||||
$lang->report->annualData->taskMonthActions = "每月任務操作情況";
|
||||
$lang->report->annualData->bugMonthActions = "每月Bug操作情況";
|
||||
$lang->report->annualData->caseMonthActions = "每月用例操作情況";
|
||||
|
||||
$lang->report->annualData->devData = "完成任務數和解決Bug數";
|
||||
$lang->report->annualData->totalFinishedTask = '完成任務數';
|
||||
$lang->report->annualData->totalResolvedBug = '解決Bug數';
|
||||
$lang->report->annualData->totalConsumed = '累計工時';
|
||||
$lang->report->annualData->projectFields['name'] = "{$lang->projectCommon}名稱";
|
||||
$lang->report->annualData->projectFields['story'] = "完成{$lang->storyCommon}數";
|
||||
$lang->report->annualData->projectFields['task'] = "完成任務數";
|
||||
$lang->report->annualData->projectFields['bug'] = "解決Bug數";
|
||||
|
||||
$lang->report->annualData->poData = "所創建{$lang->SRCommon}數和對應的優先順序及狀態";
|
||||
$lang->report->annualData->totalStoryPri = "創建{$lang->SRCommon}優先順序分佈";
|
||||
$lang->report->annualData->totalStoryStage = "創建{$lang->SRCommon}階段分佈";
|
||||
$lang->report->annualData->productFields['name'] = "{$lang->productCommon}名稱";
|
||||
$lang->report->annualData->productFields['plan'] = "計劃數";
|
||||
global $config;
|
||||
if(!empty($config->URAndSR))
|
||||
{
|
||||
$lang->report->annualData->productFields['requirement'] = "創建{$lang->URCommon}數";
|
||||
}
|
||||
$lang->report->annualData->productFields['story'] = "創建{$lang->storyCommon}數";
|
||||
$lang->report->annualData->productFields['finished'] = "完成需求數";
|
||||
|
||||
$lang->report->annualData->qaStatistics = "月創建Bug數和創建用例數";
|
||||
$lang->report->annualData->poStatistics = "月創建{$lang->SRCommon}數";
|
||||
$lang->report->annualData->devStatistics = "月完成任務數及累計工時和解決Bug數";
|
||||
$lang->report->annualData->objectTypeList['product'] = $lang->productCommon;
|
||||
$lang->report->annualData->objectTypeList['story'] = "需求";
|
||||
$lang->report->annualData->objectTypeList['productplan'] = "計劃";
|
||||
$lang->report->annualData->objectTypeList['release'] = "發佈";
|
||||
$lang->report->annualData->objectTypeList['project'] = $lang->projectCommon;
|
||||
$lang->report->annualData->objectTypeList['task'] = '任務';
|
||||
$lang->report->annualData->objectTypeList['repo'] = '代碼';
|
||||
$lang->report->annualData->objectTypeList['bug'] = 'Bug';
|
||||
$lang->report->annualData->objectTypeList['build'] = '版本';
|
||||
$lang->report->annualData->objectTypeList['testtask'] = '測試單';
|
||||
$lang->report->annualData->objectTypeList['case'] = '用例';
|
||||
$lang->report->annualData->objectTypeList['doc'] = '文檔';
|
||||
|
||||
$lang->report->annualData->unit = "個";
|
||||
$lang->report->annualData->actionList['create'] = '創建';
|
||||
$lang->report->annualData->actionList['edit'] = '編輯';
|
||||
$lang->report->annualData->actionList['close'] = '關閉';
|
||||
$lang->report->annualData->actionList['review'] = '評審';
|
||||
$lang->report->annualData->actionList['gitCommit'] = 'GIT提交';
|
||||
$lang->report->annualData->actionList['svnCommit'] = 'SVN提交';
|
||||
$lang->report->annualData->actionList['start'] = '開始';
|
||||
$lang->report->annualData->actionList['finish'] = '完成';
|
||||
$lang->report->annualData->actionList['assign'] = '指派';
|
||||
$lang->report->annualData->actionList['activate'] = '激活';
|
||||
$lang->report->annualData->actionList['resolve'] = '解決';
|
||||
$lang->report->annualData->actionList['run'] = '執行';
|
||||
$lang->report->annualData->actionList['change'] = '變更';
|
||||
$lang->report->annualData->actionList['pause'] = '暫停';
|
||||
$lang->report->annualData->actionList['cancel'] = '取消';
|
||||
$lang->report->annualData->actionList['confirm'] = '確認';
|
||||
$lang->report->annualData->actionList['createBug'] = '轉Bug';
|
||||
|
||||
$lang->report->annualData->todoStatus['all'] = '所有待辦';
|
||||
$lang->report->annualData->todoStatus['undone'] = '未完成';
|
||||
$lang->report->annualData->todoStatus['done'] = '已完成';
|
||||
|
||||
$lang->report->annualData->radarItems['product'] = '產品';
|
||||
$lang->report->annualData->radarItems['project'] = '項目';
|
||||
$lang->report->annualData->radarItems['devel'] = "研發";
|
||||
$lang->report->annualData->radarItems['qa'] = "測試";
|
||||
$lang->report->annualData->radarItems['other'] = "其他";
|
||||
|
||||
+371
-437
@@ -519,557 +519,491 @@ class reportModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year logins.
|
||||
* Get user login count in this year.
|
||||
*
|
||||
* @param string $account
|
||||
* @param array $accounts
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getUserYearLogins($account, $year)
|
||||
public function getUserYearLogins($accounts, $year)
|
||||
{
|
||||
return $this->dao->select('count(*) as count')->from(TABLE_ACTION)->where('actor')->eq($account)->andWhere('LEFT(date, 4)')->eq($year)->andWhere('action')->eq('login')->fetch('count');
|
||||
return $this->dao->select('count(*) as count')->from(TABLE_ACTION)->where('actor')->in($accounts)->andWhere('LEFT(date, 4)')->eq($year)->andWhere('action')->eq('login')->fetch('count');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year actions.
|
||||
* Get user action count in this year.
|
||||
*
|
||||
* @param string $account
|
||||
* @param array $accounts
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return int
|
||||
*/
|
||||
public function getUserYearActions($account, $year)
|
||||
public function getUserYearActions($accounts, $year)
|
||||
{
|
||||
return $this->dao->select('count(*) as count')->from(TABLE_ACTION)->where('actor')->eq($account)->andWhere('LEFT(date, 4)')->eq($year)->fetch('count');
|
||||
return $this->dao->select('count(*) as count')->from(TABLE_ACTION)
|
||||
->where('LEFT(date, 4)')->eq($year)
|
||||
->beginIF($accounts)->andWhere('actor')->in($accounts)->fi()
|
||||
->fetch('count');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year efforts.
|
||||
* Get user contributions in this year.
|
||||
*
|
||||
* @param string $account
|
||||
* @param array $accounts
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserYearContributions($accounts, $year)
|
||||
{
|
||||
$actionGroups = array();
|
||||
foreach($this->config->report->annualData['contributions'] as $objectType => $actions)
|
||||
{
|
||||
$table = $this->config->objectTables[$objectType];
|
||||
$actionGroups[$objectType] = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1')
|
||||
->leftJoin($table)->alias('t2')->on("t1.objectType='$objectType' && t1.objectID=t2.id")
|
||||
->where('LEFT(t1.date, 4)')->eq($year)
|
||||
->andWhere('t1.objectType')->eq($objectType)
|
||||
->andWhere('t1.action')->in(array_keys($actions))
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi()
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
$contributions = array();
|
||||
foreach($actionGroups as $objectType => $actions)
|
||||
{
|
||||
foreach($actions as $action)
|
||||
{
|
||||
$lowerAction = strtolower($action->action);
|
||||
if(!isset($this->config->report->annualData['contributions'][$objectType][$lowerAction])) continue;
|
||||
|
||||
$actionName = $this->config->report->annualData['contributions'][$objectType][$lowerAction];
|
||||
|
||||
$type = ($actionName == 'svnCommit' or $actionName == 'gitCommit') ? 'repo' : $objectType;
|
||||
if(!isset($contributions[$type][$actionName])) $contributions[$type][$actionName] = 0;
|
||||
$contributions[$type][$actionName] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
$contributions['case']['run'] = $this->dao->select('count(*) as count')->from(TABLE_TESTRESULT)->alias('t1')
|
||||
->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id')
|
||||
->where('LEFT(t1.date, 4)')->eq($year)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('t1.lastRunner')->in($accounts)->fi()
|
||||
->fetch('count');
|
||||
|
||||
return $contributions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user todo stat in this year.
|
||||
*
|
||||
* @param array $accounts
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public function getUserYearEfforts($account, $year)
|
||||
public function getUserYearTodos($accounts, $year)
|
||||
{
|
||||
return $this->dao->select('count(*) as count, sum(consumed) as consumed')->from(TABLE_TASKESTIMATE)->where('account')->eq($account)->andWhere('LEFT(date, 4)')->eq($year)->fetch();
|
||||
return $this->dao->select("count(*) as count, sum(if((`status` != 'done'), 1, 0)) AS `undone`, sum(if((`status` = 'done'), 1, 0)) AS `done`")->from(TABLE_TODO)
|
||||
->where('LEFT(date, 4)')->eq($year)
|
||||
->beginIF($accounts)->andWhere('account')->in($accounts)->fi()
|
||||
->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year story.
|
||||
* Get user effort stat in this error.
|
||||
*
|
||||
* @param array $products
|
||||
* @param string $account
|
||||
* @param array $accounts
|
||||
* @param int $year
|
||||
* @param string $type requirement|story
|
||||
* @access public
|
||||
* @return array
|
||||
* @return object
|
||||
*/
|
||||
public function getUserYearStory($products, $account, $year, $type = 'story')
|
||||
public function getUserYearEfforts($accounts, $year)
|
||||
{
|
||||
$stories = $this->dao->select('*')->from(TABLE_STORY)
|
||||
->where('openedBy')->eq($account)
|
||||
->andWhere('product')->in(array_keys($products))
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($type)->andWhere('type')->eq($type)->fi()
|
||||
->fetchAll();
|
||||
$effort = $this->dao->select('count(*) as count, sum(consumed) as consumed')->from(TABLE_TASKESTIMATE)
|
||||
->where('LEFT(date, 4)')->eq($year)
|
||||
->beginIF($accounts)->andWhere('account')->in($accounts)->fi()
|
||||
->fetch();
|
||||
|
||||
$storyInfo = array();
|
||||
$storyInfo['count'] = 0;
|
||||
$storyInfo['pri'] = array();
|
||||
$storyInfo['stage'] = array();
|
||||
$storyInfo['month'] = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
foreach($stories as $story)
|
||||
{
|
||||
$storyInfo['count'] ++;
|
||||
|
||||
if(!isset($storyInfo['pri'][$story->pri])) $storyInfo['pri'][$story->pri] = 0;
|
||||
$storyInfo['pri'][$story->pri] ++;
|
||||
|
||||
if(!isset($storyInfo['stage'][$story->stage])) $storyInfo['stage'][$story->stage] = 0;
|
||||
$storyInfo['stage'][$story->stage] ++;
|
||||
|
||||
$month = (int)substr($story->openedDate, 5, 2) - 1;
|
||||
$storyInfo['month'][$month] ++;
|
||||
}
|
||||
|
||||
return $storyInfo;
|
||||
$effort->consumed = round($effort->consumed, 2);
|
||||
return $effort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year created bugs.
|
||||
* Get count of created story,plan and finished story by accounts every product in this year.
|
||||
*
|
||||
* @param string $account
|
||||
* @param array $accounts
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserYearCreatedBugs($account, $year)
|
||||
public function getUserYearProducts($accounts, $year)
|
||||
{
|
||||
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where('openedBy')->eq($account)->andWhere('LEFT(openedDate, 4)')->eq($year)->andWhere('deleted')->eq(0)->fetchAll();
|
||||
|
||||
$bugInfo = array();
|
||||
$bugInfo['count'] = 0;
|
||||
$bugInfo['pri'] = array();
|
||||
$bugInfo['month'] = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
foreach($bugs as $bug)
|
||||
{
|
||||
$bugInfo['count'] ++;
|
||||
|
||||
if(!isset($bugInfo['pri'][$bug->pri])) $bugInfo['pri'][$bug->pri] = 0;
|
||||
$bugInfo['pri'][$bug->pri] ++;
|
||||
|
||||
$month = (int)substr($bug->openedDate, 5, 2) - 1;
|
||||
$bugInfo['month'][$month] ++;
|
||||
}
|
||||
return $bugInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year resolved bugs.
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserYearResolvedBugs($account, $year)
|
||||
{
|
||||
$bugs = $this->dao->select('*')->from(TABLE_BUG)->where('resolvedBy')->eq($account)->andWhere('LEFT(resolvedDate, 4)')->eq($year)->fetchAll();
|
||||
|
||||
$bugInfo = array();
|
||||
$bugInfo['count'] = 0;
|
||||
$bugInfo['pri'] = array();
|
||||
$bugInfo['month'] = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
foreach($bugs as $bug)
|
||||
{
|
||||
$bugInfo['count'] ++;
|
||||
|
||||
if(!isset($bugInfo['pri'][$bug->pri])) $bugInfo['pri'][$bug->pri] = 0;
|
||||
$bugInfo['pri'][$bug->pri] ++;
|
||||
|
||||
$month = (int)substr($bug->resolvedDate, 5, 2) - 1;
|
||||
$bugInfo['month'][$month] ++;
|
||||
}
|
||||
return $bugInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year finished tasks.
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserYearFinishedTasks($account, $year)
|
||||
{
|
||||
$tasks = $this->dao->select('id,pri,finishedDate')->from(TABLE_TASK)
|
||||
->where('LEFT(finishedDate, 4)')->eq($year)
|
||||
->andWhere('finishedBy')->eq($account)
|
||||
->fetchAll('id');
|
||||
$tasks += $this->dao->select('t1.id,t1.pri,t2.date as finishedDate')->from(TABLE_TASK)->alias('t1')
|
||||
->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.id=t2.objectID and t2.objectType='task'")
|
||||
->leftJoin(TABLE_TEAM)->alias('t3')->on("t1.id=t3.root and t3.type='task'")
|
||||
->where('t2.actor')->eq($account)
|
||||
->andWhere('LEFT(t2.date, 4)')->eq($year)
|
||||
->andWhere('t2.action')->eq('finished')
|
||||
->andWhere('t3.account')->eq($account)
|
||||
->fetchAll('id');
|
||||
|
||||
$taskInfo = array();
|
||||
$taskInfo['count'] = 0;
|
||||
$taskInfo['pri'] = array();
|
||||
$taskInfo['month'] = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
$taskInfo['count'] ++;
|
||||
|
||||
if(!isset($taskInfo['pri'][$task->pri])) $taskInfo['pri'][$task->pri] = 0;
|
||||
$taskInfo['pri'][$task->pri] ++;
|
||||
|
||||
$month = (int)substr($task->finishedDate, 5, 2) - 1;
|
||||
$taskInfo['month'][$month] ++;
|
||||
}
|
||||
return $taskInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year created cases.
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserYearCreatedCases($account, $year)
|
||||
{
|
||||
$cases = $this->dao->select('*')->from(TABLE_CASE)->where('openedBy')->eq($account)->andWhere('LEFT(openedDate, 4)')->eq($year)->fetchAll();
|
||||
|
||||
$caseInfo = array();
|
||||
$caseInfo['count'] = 0;
|
||||
$caseInfo['pri'] = array();
|
||||
$caseInfo['month'] = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
foreach($cases as $case)
|
||||
{
|
||||
$caseInfo['count'] ++;
|
||||
|
||||
if(!isset($caseInfo['pri'][$case->pri])) $caseInfo['pri'][$case->pri] = 0;
|
||||
$caseInfo['pri'][$case->pri] ++;
|
||||
|
||||
$month = (int)substr($case->openedDate, 5, 2) - 1;
|
||||
$caseInfo['month'][$month] ++;
|
||||
}
|
||||
return $caseInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year products.
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserYearProducts($account, $year)
|
||||
{
|
||||
$products = $this->dao->select('id,name,status')->from(TABLE_PRODUCT)
|
||||
->where('LEFT(createdDate, 4)')->eq($year)
|
||||
->andWhere('createdBy', true)->eq($account)
|
||||
->orWhere('PO')->eq($account)
|
||||
->orWhere('QD')->eq($account)
|
||||
->orWhere('RD')->eq($account)
|
||||
/* Get changed products in this year. */
|
||||
$products = $this->dao->select('id,name')->from(TABLE_PRODUCT)
|
||||
->where('deleted')->eq(0)
|
||||
->andWhere('LEFT(createdDate, 4)')->eq($year)
|
||||
->beginIF($accounts)
|
||||
->andWhere('createdBy', true)->in($accounts)
|
||||
->orWhere('PO')->in($accounts)
|
||||
->orWhere('QD')->in($accounts)
|
||||
->orWhere('RD')->in($accounts)
|
||||
->markRight(1)
|
||||
->fi()
|
||||
->fetchAll('id');
|
||||
|
||||
$storyProducts = $this->dao->select('DISTINCT product')->from(TABLE_STORY)->where('openedBy')->eq($account)->andWhere('LEFT(openedDate, 4)')->eq($year)->fetchPairs('product', 'product');
|
||||
$planProducts = $this->dao->select('DISTINCT t1.product')->from(TABLE_PRODUCTPLAN)->alias('t1')
|
||||
/* Get created plans in this year. */
|
||||
$plans = $this->dao->select('t1.id,t1.product')->from(TABLE_PRODUCTPLAN)->alias('t1')
|
||||
->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.id=t2.objectID and t2.objectType='productplan'")
|
||||
->where('LEFT(t2.date, 4)')->eq($year)
|
||||
->andWhere('t2.actor')->eq($account)
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->beginIF($accounts)
|
||||
->andWhere('t2.actor')->in($accounts)
|
||||
->fi()
|
||||
->andWhere('t2.action')->eq('opened')
|
||||
->groupBy('t1.product')
|
||||
->fetchAll();
|
||||
|
||||
$planProducts = array();
|
||||
$planGroups = array();
|
||||
foreach($plans as $plan)
|
||||
{
|
||||
$planProducts[$plan->product] = $plan->product;
|
||||
$planGroups[$plan->product][$plan->id] = $plan->id;
|
||||
}
|
||||
|
||||
$createStoryProducts = $this->dao->select('DISTINCT product')->from(TABLE_STORY)
|
||||
->where('LEFT(openedDate, 4)')->eq($year)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('openedBy')->in($accounts)->fi()
|
||||
->fetchPairs('product', 'product');
|
||||
$products += $this->dao->select('id,name,status')->from(TABLE_PRODUCT)
|
||||
->where('id')->in($storyProducts + $planProducts)
|
||||
->fetchAll('id');
|
||||
$closeStoryProducts = $this->dao->select('DISTINCT product')->from(TABLE_STORY)
|
||||
->where('LEFT(closedDate, 4)')->eq($year)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('closedBy')->in($accounts)->fi()
|
||||
->fetchPairs('product', 'product');
|
||||
if($createStoryProducts or $closeStoryProducts)
|
||||
{
|
||||
$products += $this->dao->select('id,name')->from(TABLE_PRODUCT)
|
||||
->where('id')->in($createStoryProducts + $closeStoryProducts + $planProducts)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
$createdStoryStats = $this->dao->select("product,sum(if((type = 'requirement'), 1, 0)) as requirement, sum(if((type = 'story'), 1, 0)) as story")->from(TABLE_STORY)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->beginIF($accounts)->andWhere('openedBy')->in($accounts)->fi()
|
||||
->groupBy('product')
|
||||
->fetchAll('product');
|
||||
|
||||
$closedStoryStats = $this->dao->select("product,sum(if((status = 'closed'), 1, 0)) as finished")->from(TABLE_STORY)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('LEFT(closedDate, 4)')->eq($year)
|
||||
->beginIF($accounts)->andWhere('closedBy')->in($accounts)->fi()
|
||||
->groupBy('product')
|
||||
->fetchAll('product');
|
||||
|
||||
/* Merge created plan, created story and finished story in every product. */
|
||||
foreach($products as $productID => $product)
|
||||
{
|
||||
$product->plan = 0;
|
||||
$product->requirement = 0;
|
||||
$product->story = 0;
|
||||
$product->finished = 0;
|
||||
|
||||
$plans = zget($planGroups, $productID, array());
|
||||
if($plans) $product->plan = count($plans);
|
||||
|
||||
$createdStoryStat = zget($createdStoryStats, $productID, '');
|
||||
if($createdStoryStat)
|
||||
{
|
||||
$product->requirement = $createdStoryStat->requirement;
|
||||
$product->story = $createdStoryStat->story;
|
||||
}
|
||||
|
||||
$closedStoryStat = zget($closedStoryStats, $productID, '');
|
||||
if($closedStoryStat) $product->finished = $closedStoryStat->finished;
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plans by products.
|
||||
* Get count of finished task, story and resolved bug by accounts every projects in this year.
|
||||
*
|
||||
* @param array $products
|
||||
* @param string $account
|
||||
* @param array $accounts
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getPlansByProducts($products, $account, $year)
|
||||
public function getUserYearProjects($accounts, $year)
|
||||
{
|
||||
$planGroups = $this->dao->select('DISTINCT t1.*')->from(TABLE_PRODUCTPLAN)->alias('t1')
|
||||
->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.id=t2.objectID and t2.objectType='productplan'")
|
||||
->where('t1.product')->in(array_keys($products))
|
||||
->andWhere('LEFT(t2.date, 4)')->eq($year)
|
||||
->andWhere('t2.actor')->eq($account)
|
||||
->andWhere('t2.action')->eq('opened')
|
||||
->fetchGroup('product', 'id');
|
||||
|
||||
foreach($planGroups as $productID => $plans) $planGroups[$productID] = count($plans);
|
||||
return $planGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stories by products.
|
||||
*
|
||||
* @param array $products
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @param string $type requirement|story
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getStoriesByProducts($products, $account, $year, $type = 'story')
|
||||
{
|
||||
return $this->dao->select('product, count(*) as stories')->from(TABLE_STORY)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->andWhere('openedBy')->eq($account)
|
||||
->andWhere('type')->eq($type)
|
||||
->groupBy('product')
|
||||
->fetchPairs('product', 'stories');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year projects.
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getUserYearProjects($account, $year)
|
||||
{
|
||||
$projects = $this->dao->select('id,name,status')->from(TABLE_PROJECT)->where('1=1')
|
||||
/* Get changed projects in this year. */
|
||||
$projects = $this->dao->select('id,name')->from(TABLE_PROJECT)->where('deleted')->eq(0)
|
||||
->andWhere('LEFT(begin, 4)', true)->eq($year)
|
||||
->orWhere('LEFT(end, 4)')->le($year)
|
||||
->orWhere('LEFT(end, 4)')->eq($year)
|
||||
->markRight(1)
|
||||
->andWhere('openedBy', true)->eq($account)
|
||||
->orWhere('PO')->eq($account)
|
||||
->orWhere('PM')->eq($account)
|
||||
->orWhere('QD')->eq($account)
|
||||
->orWhere('RD')->eq($account)
|
||||
->beginIF($accounts)
|
||||
->andWhere('openedBy', true)->in($accounts)
|
||||
->orWhere('PO')->in($accounts)
|
||||
->orWhere('PM')->in($accounts)
|
||||
->orWhere('QD')->in($accounts)
|
||||
->orWhere('RD')->in($accounts)
|
||||
->markRight(1)
|
||||
->fi()
|
||||
->orderBy('`order` desc')
|
||||
->fetchAll('id');
|
||||
|
||||
$teamProjects = $this->dao->select('*')->from(TABLE_TEAM)->where('type')->eq('project')->andWhere('account')->eq($account)->andWhere('LEFT(`join`, 4)')->eq($year)->fetchPairs('root', 'root');
|
||||
$taskProjects = $this->dao->select('DISTINCT t1.project')->from(TABLE_TASK)->alias('t1')
|
||||
->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.id=t2.objectID and t2.objectType='task'")
|
||||
->where('t2.actor')->eq($account)
|
||||
->andWhere('LEFT(t2.date, 4)')->eq($year)
|
||||
->andWhere('t2.action')->eq('finished')
|
||||
$teamProjects = $this->dao->select('*')->from(TABLE_TEAM)
|
||||
->where('type')->eq('project')
|
||||
->beginIF($accounts)->andWhere('account')->in($accounts)->fi()
|
||||
->andWhere('LEFT(`join`, 4)')->eq($year)
|
||||
->fetchPairs('root', 'root');
|
||||
$taskProjects = $this->dao->select('project')->from(TABLE_TASK)
|
||||
->where('LEFT(finishedDate, 4)')->eq($year)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('finishedBy')->in($accounts)->fi()
|
||||
->fetchPairs('project', 'project');
|
||||
if($teamProjects or $taskProjects)
|
||||
{
|
||||
$projects += $this->dao->select('id,name')->from(TABLE_PROJECT)
|
||||
->where('id')->in($teamProjects + $taskProjects)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('`order` desc')
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/* Get count of finished task, story and resolved bug in this year. */
|
||||
$taskStats = $this->dao->select('project, count(*) as finishedTask, sum(if((story != 0), 1, 0)) as finishedStory')->from(TABLE_TASK)
|
||||
->where('project')->in(array_keys($projects))
|
||||
->andWhere('finishedBy')->ne('')
|
||||
->andWhere('LEFT(finishedDate, 4)')->eq($year)
|
||||
->andWhere('deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('finishedBy')->in($accounts)->fi()
|
||||
->groupBy('project')
|
||||
->fetchAll('project');
|
||||
$resolvedBugs = $this->dao->select('t2.project, count(*) as count')->from(TABLE_BUG)->alias('t1')
|
||||
->leftJoin(TABLE_BUILD)->alias('t2')->on('t1.resolvedBuild=t2.id')
|
||||
->where('t2.project')->in(array_keys($projects))
|
||||
->andWhere('t1.resolvedBy')->ne('')
|
||||
->andWhere('t1.deleted')->eq(0)
|
||||
->andWhere('LEFT(t1.resolvedDate, 4)')->eq($year)
|
||||
->beginIF($accounts)->andWhere('t1.resolvedBy')->in($accounts)->fi()
|
||||
->groupBy('t2.project')
|
||||
->fetchAll('project');
|
||||
|
||||
foreach($projects as $projectID => $project)
|
||||
{
|
||||
$project->task = 0;
|
||||
$project->story = 0;
|
||||
$project->bug = 0;
|
||||
|
||||
$taskStat = zget($taskStats, $projectID, '');
|
||||
if($taskStat)
|
||||
{
|
||||
$project->task = $taskStat->finishedTask;
|
||||
$project->story = $taskStat->finishedStory;
|
||||
}
|
||||
|
||||
$resolvedBug = zget($resolvedBugs, $projectID, '');
|
||||
if($resolvedBug) $project->bug = $resolvedBug->count;
|
||||
}
|
||||
|
||||
$projects += $this->dao->select('id,name,status')->from(TABLE_PROJECT)
|
||||
->where('id')->in($teamProjects + $taskProjects)
|
||||
->fetchAll('id');
|
||||
return $projects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get finished story by projects
|
||||
* Get status stat that is all time, include story, task and bug.
|
||||
*
|
||||
* @param array $projects
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getFinishedStoryByProjects($projects, $account, $year)
|
||||
public function getAllTimeStatusStat()
|
||||
{
|
||||
$storyGroups = $this->dao->select('t1.*')->from(TABLE_PROJECTSTORY)->alias('t1')
|
||||
->leftJoin(TABLE_STORY)->alias('t2')->on('t1.story=t2.id')
|
||||
->leftJoin(TABLE_TASK)->alias('t3')->on('t1.story=t3.story')
|
||||
->leftJoin(TABLE_ACTION)->alias('t4')->on("t3.id=t4.objectID and t4.objectType='task'")
|
||||
->where('t1.project')->in(array_keys($projects))
|
||||
->andWhere('LEFT(t4.date, 4)')->eq($year)
|
||||
->andWhere('t4.actor')->eq($account)
|
||||
->andWhere('t4.action')->eq('finished')
|
||||
->fetchGroup('project', 'story');
|
||||
$statusStat = array();
|
||||
$statusStat['story'] = $this->dao->select('status, count(status) as count')->from(TABLE_STORY)->where('deleted')->eq(0)->andWhere('type')->eq('story')->groupBy('status')->fetchPairs('status', 'count');
|
||||
$statusStat['task'] = $this->dao->select('status, count(status) as count')->from(TABLE_TASK)->where('deleted')->eq(0)->groupBy('status')->fetchPairs('status', 'count');
|
||||
$statusStat['bug'] = $this->dao->select('status, count(status) as count')->from(TABLE_BUG)->where('deleted')->eq(0)->groupBy('status')->fetchPairs('status', 'count');
|
||||
|
||||
foreach($storyGroups as $projectID => $stories) $storyGroups[$projectID] = count($stories);
|
||||
return $storyGroups;
|
||||
return $statusStat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get finished task by projects.
|
||||
* Get year object stat, include status and action stat
|
||||
*
|
||||
* @param array $projects
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @param array $accounts
|
||||
* @param string $year
|
||||
* @param string $objectType story|task|bug
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getFinishedTaskByProjects($projects, $account, $year)
|
||||
public function getYearObjectStat($accounts, $year, $objectType)
|
||||
{
|
||||
$tasks = $this->dao->select('*')->from(TABLE_TASK)
|
||||
->where('LEFT(finishedDate, 4)')->eq($year)
|
||||
->andWhere('finishedBy')->eq($account)
|
||||
->andWhere('project')->in(array_keys($projects))
|
||||
->fetchAll('id');
|
||||
$tasks += $this->dao->select('t1.*')->from(TABLE_TASK)->alias('t1')
|
||||
->leftJoin(TABLE_ACTION)->alias('t2')->on("t1.id=t2.objectID and t2.objectType='task'")
|
||||
->leftJoin(TABLE_TEAM)->alias('t3')->on("t1.id=t3.root and t3.type='task'")
|
||||
->where('t2.actor')->eq($account)
|
||||
->andWhere('LEFT(t2.date, 4)')->eq($year)
|
||||
->andWhere('t2.action')->eq('finished')
|
||||
->andWhere('t3.account')->eq($account)
|
||||
->andWhere('t1.project')->in(array_keys($projects))
|
||||
->fetchAll('id');
|
||||
$table = '';
|
||||
if($objectType == 'story') $table = TABLE_STORY;
|
||||
if($objectType == 'task') $table = TABLE_TASK;
|
||||
if($objectType == 'bug') $table = TABLE_BUG;
|
||||
if(empty($table)) return array();
|
||||
|
||||
$taskGroups = array();
|
||||
foreach($tasks as $taskID => $task) $taskGroups[$task->project][$taskID] = $task;
|
||||
foreach($taskGroups as $projectID => $tasks) $taskGroups[$projectID] = count($tasks);
|
||||
return $taskGroups;
|
||||
}
|
||||
$months = $this->getYearMonths($year);
|
||||
$stmt = $this->dao->select('t1.*, t2.status')->from(TABLE_ACTION)->alias('t1')
|
||||
->leftJoin($table)->alias('t2')->on('t1.objectID=t2.id')
|
||||
->where('t1.objectType')->eq($objectType)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('LEFT(t1.date, 4)')->eq($year)
|
||||
->andWhere('t1.action')->in(array_keys($this->config->report->annualData['month'][$objectType]))
|
||||
->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi()
|
||||
->query();
|
||||
|
||||
/**
|
||||
* Get resolved bug by projects.
|
||||
*
|
||||
* @param array $projects
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getResolvedBugByProjects($projects, $account, $year)
|
||||
{
|
||||
return $this->dao->select('project, count(*) as bugs')->from(TABLE_BUG)
|
||||
->where('project')->in(array_keys($projects))
|
||||
->andWhere('LEFT(resolvedDate, 4)')->eq($year)
|
||||
->andWhere('resolvedBy')->eq($account)
|
||||
->groupBy('project')
|
||||
->fetchPairs('project', 'bugs');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stat by projects.
|
||||
*
|
||||
* @param array $projects
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getStatByProjects($projects)
|
||||
{
|
||||
$projectStat = array();
|
||||
$projectStat['count'] = 0;
|
||||
$projectStat['doing'] = 0;
|
||||
$projectStat['done'] = 0;
|
||||
$projectStat['suspended'] = 0;
|
||||
foreach($projects as $project)
|
||||
/* Build object action stat and get status group. */
|
||||
$statuses = array();
|
||||
$actionStat = array();
|
||||
while($action = $stmt->fetch())
|
||||
{
|
||||
$projectStat['count']++;
|
||||
if($project->status == 'closed' or $project->status == 'done') $projectStat['done']++;
|
||||
if($project->status == 'wait' or $project->status == 'doing') $projectStat['doing']++;
|
||||
if($project->status == 'suspended') $projectStat['suspended']++;
|
||||
}
|
||||
return $projectStat;
|
||||
}
|
||||
$statuses[$action->objectID] = $action->status;
|
||||
|
||||
/**
|
||||
* Get stat by products.
|
||||
*
|
||||
* @param array $products
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @param string $type requirement|story
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getStatByProducts($products, $account, $year, $type = 'story')
|
||||
{
|
||||
$allStories = $this->dao->select('product, count(*) as count')->from(TABLE_STORY)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->beginIF($type)->andWhere('type')->eq($type)->fi()
|
||||
->groupBy('product')
|
||||
->fetchPairs('product', 'count');
|
||||
$mineStories = $this->dao->select('product, count(*) as count')->from(TABLE_STORY)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('openedBy')->eq($account)
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->beginIF($type)->andWhere('type')->eq($type)->fi()
|
||||
->groupBy('product')
|
||||
->fetchPairs('product', 'count');
|
||||
$lowerAction = strtolower($action->action);
|
||||
if(!isset($actionStat[$lowerAction]))
|
||||
{
|
||||
foreach($months as $month) $actionStat[$lowerAction][$month] = 0;
|
||||
}
|
||||
|
||||
$productStat = array();
|
||||
foreach($products as $productID => $product)
|
||||
{
|
||||
$productStat[$productID]['name'] = $product->name;
|
||||
$productStat[$productID]['count'] = zget($allStories, $productID, 0);
|
||||
$productStat[$productID]['mine'] = zget($mineStories, $productID, 0);
|
||||
$month = substr($action->date, 0, 7);
|
||||
$actionStat[$lowerAction][$month] += 1;
|
||||
}
|
||||
|
||||
return $productStat;
|
||||
/* Build status stat. */
|
||||
$statusStat = array();
|
||||
foreach($statuses as $storyID => $status)
|
||||
{
|
||||
if(!isset($statusStat[$status])) $statusStat[$status] = 0;
|
||||
$statusStat[$status] += 1;
|
||||
}
|
||||
|
||||
return array('statusStat' => $statusStat, 'actionStat' => $actionStat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get effort for month
|
||||
* Get year case stat, include result and action stat.
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @param array $accounts
|
||||
* @param string $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getEffort4Month($account, $year)
|
||||
public function getYearCaseStat($accounts, $year)
|
||||
{
|
||||
$efforts = $this->dao->select('*')->from(TABLE_TASKESTIMATE)->where('account')->eq($account)
|
||||
->andWhere('LEFT(date, 4)')->eq($year)
|
||||
->orderBy('date')
|
||||
->fetchAll();
|
||||
$months = $this->getYearMonths($year);
|
||||
$stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1')
|
||||
->leftJoin(TABLE_CASE)->alias('t2')->on('t1.objectID=t2.id')
|
||||
->where('t1.objectType')->eq('case')
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('t1.action')->eq('opened')
|
||||
->andWhere('LEFT(t1.date, 4)')->eq($year)
|
||||
->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi()
|
||||
->query();
|
||||
|
||||
$months = array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
foreach($efforts as $effort)
|
||||
/* Build create case stat. */
|
||||
$resultStat = array();
|
||||
$actionStat = array();
|
||||
foreach($months as $month)
|
||||
{
|
||||
$month = (int)substr($effort->date, 5, 2) - 1;
|
||||
$months[$month] += $effort->consumed;
|
||||
$actionStat['opened'][$month] = 0;
|
||||
$actionStat['run'][$month] = 0;
|
||||
$actionStat['createBug'][$month] = 0;
|
||||
}
|
||||
|
||||
while($action = $stmt->fetch())
|
||||
{
|
||||
$month = substr($action->date, 0, 7);
|
||||
$actionStat['opened'][$month] += 1;
|
||||
}
|
||||
|
||||
/* Build testcase result stat and run case stat. */
|
||||
$stmt = $this->dao->select('t1.*')->from(TABLE_TESTRESULT)->alias('t1')
|
||||
->leftJoin(TABLE_CASE)->alias('t2')->on('t1.case=t2.id')
|
||||
->where('LEFT(t1.date, 4)')->eq($year)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->beginIF($accounts)->andWhere('t1.lastRunner')->in($accounts)->fi()
|
||||
->query();
|
||||
while($testResult = $stmt->fetch())
|
||||
{
|
||||
if(!isset($resultStat[$testResult->caseResult])) $resultStat[$testResult->caseResult] = 0;
|
||||
$resultStat[$testResult->caseResult] += 1;
|
||||
|
||||
$month = substr($testResult->date, 0, 7);
|
||||
$actionStat['run'][$month] += 1;
|
||||
}
|
||||
|
||||
/* Build testcase create bug stat. */
|
||||
$stmt = $this->dao->select('t1.*')->from(TABLE_ACTION)->alias('t1')
|
||||
->leftJoin(TABLE_BUG)->alias('t2')->on('t1.objectID=t2.id')
|
||||
->where('t1.objectType')->eq('bug')
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->andWhere('LEFT(t1.date, 4)')->eq($year)
|
||||
->andWhere('t1.action')->eq('opened')
|
||||
->andWhere('t2.case')->ne('0')
|
||||
->beginIF($accounts)->andWhere('t1.actor')->in($accounts)->fi()
|
||||
->query();
|
||||
while($action = $stmt->fetch())
|
||||
{
|
||||
$month = substr($action->date, 0, 7);
|
||||
$actionStat['createBug'][$month] += 1;
|
||||
}
|
||||
|
||||
return array('resultStat' => $resultStat, 'actionStat' => $actionStat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get year months.
|
||||
*
|
||||
* @param string $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getYearMonths($year)
|
||||
{
|
||||
$months = array();
|
||||
for($i = 1; $i <= 12; $i ++) $months[] = $year . '-' . sprintf('%02d', $i);
|
||||
|
||||
return $months;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user year products for qa
|
||||
* Get status vverview.
|
||||
*
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @param string $objectType
|
||||
* @param array $statusStat
|
||||
* @access public
|
||||
* @return array
|
||||
* @return string
|
||||
*/
|
||||
public function getUserYearProducts4QA($account, $year)
|
||||
public function getStatusOverview($objectType, $statusStat)
|
||||
{
|
||||
$bugProducts = $this->dao->select('product')->from(TABLE_BUG)->where('openedBy')->eq($account)->andWhere('LEFT(openedDate, 4)')->eq($year)->fetchPairs('product', 'product');
|
||||
$caseProducts = $this->dao->select('product')->from(TABLE_CASE)->where('openedBy')->eq($account)->andWhere('LEFT(openedDate, 4)')->eq($year)->fetchPairs('product', 'product');
|
||||
|
||||
$products = $this->dao->select('id,name,status')->from(TABLE_PRODUCT)
|
||||
->where('id')->in($bugProducts + $caseProducts)
|
||||
->fetchAll('id');
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get bug stat by products.
|
||||
*
|
||||
* @param array $products
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getBugStatByProducts($products, $account, $year)
|
||||
{
|
||||
$allBugs = $this->dao->select('product, count(*) as count')->from(TABLE_BUG)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->groupBy('product')
|
||||
->fetchPairs('product', 'count');
|
||||
$mineBugs = $this->dao->select('product, count(*) as count')->from(TABLE_BUG)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('openedBy')->eq($account)
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->groupBy('product')
|
||||
->fetchPairs('product', 'count');
|
||||
|
||||
$productStat = array();
|
||||
foreach($products as $productID => $product)
|
||||
$allCount = 0;
|
||||
$undoneCount = 0;
|
||||
foreach($statusStat as $status => $count)
|
||||
{
|
||||
$productStat[$productID]['name'] = $product->name;
|
||||
$productStat[$productID]['count'] = zget($allBugs, $productID, 0);
|
||||
$productStat[$productID]['mine'] = zget($mineBugs, $productID, 0);
|
||||
$allCount += $count;
|
||||
if($objectType == 'story' and $status != 'closed') $undoneCount += $count;
|
||||
if($objectType == 'task' and $status != 'done' and $status != 'closed' and $status != 'cancel') $undoneCount += $count;
|
||||
if($objectType == 'bug' and $status == 'active') $undoneCount += $count;
|
||||
}
|
||||
|
||||
return $productStat;
|
||||
}
|
||||
$overview = '';
|
||||
if($objectType == 'story') $overview .= $this->lang->report->annualData->allStory;
|
||||
if($objectType == 'task') $overview .= $this->lang->report->annualData->allTask;
|
||||
if($objectType == 'bug') $overview .= $this->lang->report->annualData->allBug;
|
||||
$overview .= ' ' . $allCount;
|
||||
$overview .= '<br />';
|
||||
$overview .= $objectType == 'bug' ? $this->lang->report->annualData->unresolve : $this->lang->report->annualData->undone;
|
||||
$overview .= ' ' . $undoneCount;
|
||||
|
||||
/**
|
||||
* Get created bug by products.
|
||||
*
|
||||
* @param array $products
|
||||
* @param string $account
|
||||
* @param int $year
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getCreatedBugByProducts($products, $account, $year)
|
||||
{
|
||||
return $this->dao->select('product, count(*) as bugs')->from(TABLE_BUG)
|
||||
->where('product')->in(array_keys($products))
|
||||
->andWhere('LEFT(openedDate, 4)')->eq($year)
|
||||
->andWhere('openedBy')->eq($account)
|
||||
->groupBy('product')
|
||||
->fetchPairs('product', 'bugs');
|
||||
return $overview;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,260 +1,388 @@
|
||||
<?php include '../../common/view/header.lite.html.php';?>
|
||||
<?php include '../../common/view/chosen.html.php';?>
|
||||
<?php js::import($jsRoot . 'echarts/echarts.common.min.js'); ?>
|
||||
<?php js::import($jsRoot . 'html2canvas/min.js'); ?>
|
||||
<?php $annualDataLang = $lang->report->annualData;?>
|
||||
<?php $annualDataConfig = $config->report->annualData;?>
|
||||
<?php $soFar = sprintf($annualDataLang->soFar, $year);?>
|
||||
<div id='container' style='background-image: url(<?php echo $config->webRoot . 'theme/default/images/main/annual_data_bg.png'?>)'>
|
||||
<main id='main'>
|
||||
<div id='mainBg' style='background-image: url(<?php echo $config->webRoot . 'theme/default/images/main/annual_data_layout.png'?>)'></div>
|
||||
<main id='main' style='background: url(<?php echo $config->webRoot . 'theme/default/images/main/annual_layout_header.png'?>) top no-repeat'>
|
||||
<header id='header'>
|
||||
<h1 class='text-holder' data-id='title'></h1>
|
||||
<h1 class='text-holder' data-id='title'><?php echo $title;?></h1>
|
||||
</header>
|
||||
<section id='block1'>
|
||||
<header><h2 class='text-holder' data-id='block1.title'></h2></header>
|
||||
<div><ul id='block1List'></ul></div>
|
||||
</section>
|
||||
<section id='block2'>
|
||||
<header><h2 class='text-holder' data-id='block2.title'></h2></header>
|
||||
<div id='block2Chart' class='progress-pie inline-block space progress-pie-200' data-value='0' data-doughnut-size='70' data-color='#186bb1' data-back-color='#84cff0' data-show-tip='true'>
|
||||
<canvas width='180' height='180' style='width: 180px; height: 180px;'></canvas>
|
||||
<div class='progress-info'>
|
||||
<strong><span class='text-holder' data-id='block2.dataTotal'></span><small class='text-holder' data-id='block2.unit'></small></strong>
|
||||
</div>
|
||||
<div id='toolbar'>
|
||||
<div class='pull-left'>
|
||||
<span><?php echo $annualDataLang->scope;?></span>
|
||||
<?php echo html::select('year', $years, $year, "class='form-control'");?>
|
||||
<?php echo html::select('dept', $depts, $dept, "class='form-control chosen'");?>
|
||||
<?php echo html::select('userID', $users, $userID, "class='form-control chosen'");?>
|
||||
</div>
|
||||
<div class='pull-right'>
|
||||
<button type='button' class='btn btn-primary' id='exportBtn' title='<?php echo $lang->export;?>'><i class='icon icon-export'></i></button>
|
||||
<a id='imageDownloadBtn' class='hidden' download='annual_data.png'></a>
|
||||
</div>
|
||||
</div>
|
||||
<section id='baseInfo'>
|
||||
<header><h2 class='text-holder'><?php echo $annualDataLang->baseInfo . $soFar;?></h2></header>
|
||||
<div>
|
||||
<ul id='infoList'>
|
||||
<li>
|
||||
<?php echo $userID ? $annualDataLang->logins : ($dept ? $annualDataLang->deptUsers : $annualDataLang->companyUsers);?>
|
||||
<strong><?php echo $userID ? $data['logins'] : $data['users'];?></strong>
|
||||
</li>
|
||||
<li>
|
||||
<?php echo $annualDataLang->actions;?>
|
||||
<strong><?php echo $data['actions'];?></strong>
|
||||
</li>
|
||||
<li>
|
||||
<?php echo $annualDataLang->consumed;?>
|
||||
<strong><?php echo $data['consumed'];?></strong>
|
||||
</li>
|
||||
<li class='dropdown dropdown-hover'>
|
||||
<?php echo $annualDataLang->todos;?>
|
||||
<strong><?php echo $data['todos']->count;?></strong>
|
||||
<ul class='dropdown-menu pull-right'>
|
||||
<li><?php echo $annualDataLang->todos;?></li>
|
||||
<li><span class='todoStatus'><?php echo $annualDataLang->todoStatus['all'];?></span><span><?php echo (int)$data['todos']->count;?></span></li>
|
||||
<li><span class='todoStatus'><?php echo $annualDataLang->todoStatus['undone'];?></span><span><?php echo (int)$data['todos']->undone;?></span></li>
|
||||
<li><span class='todoStatus'><?php echo $annualDataLang->todoStatus['done'];?></span><span><?php echo (int)$data['todos']->done;?></span></li>
|
||||
</ul>
|
||||
</li>
|
||||
<?php
|
||||
$contributions = 0;
|
||||
$maxCount = 0;
|
||||
$radarData = array('product' => 0, 'project' => 0, 'devel' => 0, 'qa' => 0, 'other' => 0);
|
||||
foreach($data['contributions'] as $objectType => $objectContributions)
|
||||
{
|
||||
$sum = array_sum($objectContributions);
|
||||
if($sum > $maxCount) $maxCount = $sum;
|
||||
$contributions += $sum;
|
||||
|
||||
foreach($objectContributions as $actionName => $count)
|
||||
{
|
||||
$radarTypes = isset($annualDataConfig['radar'][$objectType][$actionName]) ? $annualDataConfig['radar'][$objectType][$actionName] : array('other');
|
||||
foreach($radarTypes as $radarType) $radarData[$radarType] += $count;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php if(!empty($dept) or !empty($userID)):?>
|
||||
<li>
|
||||
<?php echo $annualDataLang->contributions;?>
|
||||
<strong><?php echo $contributions;?></strong>
|
||||
</li>
|
||||
<?php endif;?>
|
||||
</ul>
|
||||
</div>
|
||||
<div id='block2ListWrapper'><ul id='block2List'></ul></div>
|
||||
</section>
|
||||
<section id='block3'>
|
||||
<table class='table' id='block3TableHeader'>
|
||||
<thead>
|
||||
<tr></tr>
|
||||
</thead>
|
||||
</table>
|
||||
<div class='table-wrapper'>
|
||||
<table class='table' id='block3Table'>
|
||||
<section id='actionData'>
|
||||
<header><h2 class='text-holder'><?php echo ((empty($dept) and empty($userID)) ? $annualDataLang->actionData :$annualDataLang->contributionData) . $soFar;?></h2></header>
|
||||
<div>
|
||||
<ul>
|
||||
<?php foreach($annualDataLang->objectTypeList as $objectType => $objectName):?>
|
||||
<li class='dropdown dropdown-hover'>
|
||||
<span class='name'><?php echo $objectName;?></span>
|
||||
<span class='ratio'>
|
||||
<?php
|
||||
$objectContributions = isset($data['contributions'][$objectType]) ? $data['contributions'][$objectType] : array();
|
||||
$contributionActions = zget($annualDataConfig['contributions'], $objectType, array_keys($objectContributions));
|
||||
|
||||
$colors = $annualDataConfig['colors'];
|
||||
$detail = '';
|
||||
$items = array();
|
||||
$maxWidth = 0;
|
||||
$maxWidthColor = '';
|
||||
$allPercent = 0;
|
||||
foreach($contributionActions as $actionName)
|
||||
{
|
||||
if($maxCount == 0) continue;
|
||||
if(isset($objectContributions[$actionName]))
|
||||
{
|
||||
$color = array_shift($colors);
|
||||
$count = $objectContributions[$actionName];
|
||||
if($count == 0) continue;
|
||||
|
||||
$width = floor($count / $maxCount * 100);
|
||||
if($width == 0) $width = 1;
|
||||
$length = strlen($count);
|
||||
if($width < $annualDataConfig['itemMinWidth'][$length]) $width = $annualDataConfig['itemMinWidth'][$length];
|
||||
|
||||
$allPercent += $width;
|
||||
if($maxWidth < $width)
|
||||
{
|
||||
$maxWidth = $width;
|
||||
$maxWidthColor = $color;
|
||||
}
|
||||
|
||||
$item['color'] = $color;
|
||||
$item['width'] = $width;
|
||||
$item['count'] = $count;
|
||||
$items[$color] = $item;
|
||||
|
||||
$detail .= "<li><span class='color' style='background-color:{$color}'></span><span class='item-name'>" . $annualDataLang->actionList[$actionName] . "</span><span class='count'>{$count}</span></li>";
|
||||
}
|
||||
}
|
||||
if($allPercent > 100) $items[$maxWidthColor]['width'] = $items[$maxWidthColor]['width'] - ($allPercent - 100);
|
||||
if($detail) $detail = "<li><span class='header'>{$objectName}</span></li>" . $detail;
|
||||
foreach($items as $item) echo "<span class='item' style='background-color:{$item['color']};width:{$item['width']}%'>{$item['count']}</span>";
|
||||
?>
|
||||
</span>
|
||||
<?php if($detail):?>
|
||||
<ul class='dropdown-menu'><?php echo $detail;?></ul>
|
||||
<?php endif;?>
|
||||
</li>
|
||||
<?php endforeach;?>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<section id='radar'>
|
||||
<header><h2 class='text-holder'><?php echo $annualDataLang->radar . $soFar;?></h2></header>
|
||||
<div id='radarCanvas'></div>
|
||||
</section>
|
||||
<section id='projectData'>
|
||||
<header><h2 class='text-holder'><?php echo $annualDataLang->projects . $soFar;?></h2></header>
|
||||
<div class='has-table'>
|
||||
<table class='table table-hover table-fixed table-borderless table-condensed'>
|
||||
<thead class='hidden'>
|
||||
<tr>
|
||||
<?php foreach($annualDataLang->projectFields as $field => $name):?>
|
||||
<th class='<?php echo "c-$field";?>'><?php echo $name;?></th>
|
||||
<?php endforeach?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($data['projectStat'] as $project):?>
|
||||
<tr>
|
||||
<?php foreach($annualDataLang->projectFields as $field => $name):?>
|
||||
<td class='<?php echo "c-$field";?>' title='<?php echo $project->$field;?>'><?php echo $project->$field;?></td>
|
||||
<?php endforeach?>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class='table-header-fixed'>
|
||||
<table class='table table-hover table-fixed table-borderless table-condensed'>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php foreach($annualDataLang->projectFields as $field => $name):?>
|
||||
<th class='<?php echo "c-$field";?>'><?php echo $name;?></th>
|
||||
<?php endforeach?>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
<section id='block4'>
|
||||
<header>
|
||||
<h2 class='text-holder' data-id='block4.title'></h2>
|
||||
</header>
|
||||
<div class='row'>
|
||||
<div class='col-xs-6'>
|
||||
<div id='block4chart1' class='progress-pie inline-block space progress-pie-200' data-value='0' data-doughnut-size='80' data-color='#186bb1'>
|
||||
<canvas width='160' height='160' style='width: 160px; height: 160px;'></canvas>
|
||||
<div class='progress-info'>
|
||||
<p class='text-holder' data-id='block4.chart1.title'></p>
|
||||
<strong><span class='text-holder' data-id='block4.chart1.total'></span><small class='text-holder' data-id='block4.chart1.unit'></small></strong>
|
||||
</div>
|
||||
</div>
|
||||
<ul class='clearfix' id='block4chart1Info'>
|
||||
</ul>
|
||||
</div>
|
||||
<div class='col-xs-6'>
|
||||
<div id='block4chart2' class='progress-pie inline-block space progress-pie-160' data-value='0' data-doughnut-size='80' data-color='#186bb1'>
|
||||
<canvas width='160' height='160' style='width: 160px; height: 160px;'></canvas>
|
||||
<div class='progress-info'>
|
||||
<p class='text-holder' data-id='block4.chart2.title'></p>
|
||||
<strong><span class='text-holder' data-id='block4.chart2.total'></span><small class='text-holder' data-id='block4.chart2.unit'></small></strong>
|
||||
</div>
|
||||
</div>
|
||||
<ul class='clearfix' id='block4chart2Info'>
|
||||
</ul>
|
||||
</div>
|
||||
<section id='productData'>
|
||||
<header><h2 class='text-holder'><?php echo $annualDataLang->products . $soFar;?></h2></header>
|
||||
<div class='has-table'>
|
||||
<table class='table table-hover table-borderless table-condensed'>
|
||||
<thead class='hidden'>
|
||||
<tr>
|
||||
<?php foreach($annualDataLang->productFields as $field => $name):?>
|
||||
<th class='<?php echo "c-$field";?>'><?php echo $name;?></th>
|
||||
<?php endforeach?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($data['productStat'] as $product):?>
|
||||
<tr>
|
||||
<?php foreach($annualDataLang->productFields as $field => $name):?>
|
||||
<td class='<?php echo "c-$field";?>' title='<?php echo $product->$field;?>'><?php echo $product->$field;?></td>
|
||||
<?php endforeach?>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class='table-header-fixed'>
|
||||
<table class='table table-hover table-fixed table-borderless table-condensed'>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php foreach($annualDataLang->productFields as $field => $name):?>
|
||||
<th class='<?php echo "c-$field";?>'><?php echo $name;?></th>
|
||||
<?php endforeach?>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class='table-header-fixed'>
|
||||
</section>
|
||||
<?php if(empty($dept) and empty($userID)):?>
|
||||
<section id='allTimeStatusStat'>
|
||||
<header><h2 class='text-holder'><?php echo $annualDataLang->statusStat;?></h2></header>
|
||||
<div>
|
||||
<div class='canvas' id='allStoryStatusCanvas'></div>
|
||||
<div class='canvas' id='allTaskStatusCanvas'></div>
|
||||
<div class='canvas' id='allBugStatusCanvas'></div>
|
||||
<?php
|
||||
foreach($data['statusStat'] as $objectType => $objectStatusStat):?>
|
||||
<div class='<?php echo $objectType;?>Overview hidden'><?php echo $this->report->getStatusOverview($objectType, $objectStatusStat);?></div>
|
||||
<?php endforeach;?>
|
||||
</div>
|
||||
</section>
|
||||
<section id='block5'>
|
||||
<header>
|
||||
<h2 class='text-holder' data-id='block5.title'></h2>
|
||||
<div id='block5Legend'></div>
|
||||
</header>
|
||||
<canvas id='block5Chart' width='520' height='240'></canvas>
|
||||
<?php endif;?>
|
||||
<?php
|
||||
$objectTypeList['story'] = $radarData['product'];
|
||||
$objectTypeList['task'] = $radarData['project'] > $radarData['devel'] ? $radarData['project'] : $radarData['devel'];
|
||||
$objectTypeList['bug'] = $radarData['qa'];
|
||||
$objectTypeList['case'] = $radarData['qa'];
|
||||
arsort($objectTypeList);
|
||||
?>
|
||||
<?php foreach(array_keys($objectTypeList) as $objectType):?>
|
||||
<section class='dataYearStat' id='<?php echo $objectType;?>Data'>
|
||||
<?php if($objectType == 'story') $sectionHeader = $annualDataLang->stories;?>
|
||||
<?php if($objectType == 'task') $sectionHeader = $annualDataLang->tasks;?>
|
||||
<?php if($objectType == 'bug') $sectionHeader = $annualDataLang->bugs;?>
|
||||
<?php if($objectType == 'case') $sectionHeader = $annualDataLang->cases;?>
|
||||
<?php $ucfirst = ucfirst($objectType);?>
|
||||
<header><h2 class='text-holder'><?php echo $sectionHeader . $soFar;?></h2></header>
|
||||
<div>
|
||||
<div class='canvas left' id='<?php echo $objectType == 'case' ? "yearCaseResultCanvas" : "year{$ucfirst}StatusCanvas";?>'></div>
|
||||
<div class='canvas right' id='year<?php echo $ucfirst;?>ActionCanvas'></div>
|
||||
<?php if($objectType != 'case'):?>
|
||||
<div class='year<?php echo $ucfirst;?>Overview hidden'><?php echo $this->report->getStatusOverview($objectType, $data["{$objectType}Stat"]['statusStat']);?></div>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
</section>
|
||||
<div id='toolbar'>
|
||||
<?php echo html::select('year', $years, $year, "class='form-control'");?>
|
||||
<button type='button' class='btn btn-primary' id='exportBtn' title='<?php echo $lang->export;?>'><i class='icon icon-share'></i></button>
|
||||
<a id='imageDownloadBtn' class='hidden' download='annual_data.png'></a>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
</main>
|
||||
<div id='loadIndicator' class='load-indicator'></div>
|
||||
</div>
|
||||
<?php echo js::set('exportByZentao', $annualDataLang->exportByZentao);?>
|
||||
<script>
|
||||
var annualData =
|
||||
{
|
||||
title: '<?php echo $title;?>',
|
||||
|
||||
<?php foreach($config->report->annualData[$role] as $blockKey => $blockConfig):?>
|
||||
<?php echo $blockKey;?>:
|
||||
{
|
||||
<?php if(!empty($blockConfig['title'])):?>
|
||||
title: '<?php echo $lang->report->annualData->{$blockConfig['title']};?>',
|
||||
<?php endif;?>
|
||||
<?php
|
||||
$blockData = array();
|
||||
if($blockKey == 'block1')
|
||||
{
|
||||
foreach($blockConfig['data'] as $name) $blockData[] = array('title' => $lang->report->annualData->{$name}, 'value' => $data[$name]);
|
||||
echo "data :" . json_encode($blockData);
|
||||
}
|
||||
elseif($blockKey == 'block2')
|
||||
{
|
||||
echo "unit: '" . $lang->report->annualData->unit . "',";
|
||||
if($role == 'dev')
|
||||
{
|
||||
$count = $data['projectStat']['count'];
|
||||
$blockData[] = array('title' => $lang->report->annualData->doneProject, 'value' => $data['projectStat']['done'], 'percent' => (empty($count) ? 0 : round($data['projectStat']['done'] / $count, 4) * 100 . '%'));
|
||||
$blockData[] = array('title' => $lang->report->annualData->doingProject, 'value' => $data['projectStat']['doing'], 'percent' => (empty($count) ? 0 : round($data['projectStat']['doing'] / $count, 4) * 100 . '%'));
|
||||
$blockData[] = array('title' => $lang->report->annualData->suspendProject, 'value' => $data['projectStat']['suspended'], 'percent' => (empty($count) ? 0 : round($data['projectStat']['suspended'] / $count, 4) * 100 . '%'));
|
||||
echo "data: " . json_encode($blockData);
|
||||
}
|
||||
elseif($role == 'po')
|
||||
{
|
||||
foreach($data['productStat'] as $productStat)
|
||||
{
|
||||
$count = $productStat['count'];
|
||||
$blockData[] = array('title' => $productStat['name'], 'value' => (int)$productStat['mine'], 'percent' => (empty($count) ? '0' : round($productStat['mine'] / $count, 3) * 100 . '%'));
|
||||
}
|
||||
echo "data: " . json_encode($blockData);
|
||||
}
|
||||
elseif($role == 'qa')
|
||||
{
|
||||
foreach($data['productStat'] as $productStat)
|
||||
{
|
||||
$count = $productStat['count'];
|
||||
$blockData[] = array('title' => $productStat['name'], 'value' => (int)$productStat['mine'], 'percent' => (empty($count) ? '0' : round($productStat['mine'] / $count, 3) * 100 . '%'));
|
||||
}
|
||||
echo "data: " . json_encode($blockData);
|
||||
}
|
||||
}
|
||||
elseif($blockKey == 'block3')
|
||||
{
|
||||
$cols = array();
|
||||
$rows = array();
|
||||
if($role == 'po')
|
||||
{
|
||||
$cols[] = array('title' => $lang->report->annualData->productName, 'width' => 'auto', 'align' => 'left');
|
||||
$cols[] = array('title' => $lang->report->annualData->planCount, 'width' => '80', 'align' => 'center');
|
||||
$cols[] = array('title' => $lang->report->annualData->storyCount, 'width' => '80', 'align' => 'center');
|
||||
|
||||
foreach($data['products'] as $product) $rows[] = array($product->name, $product->plans, $product->stories);
|
||||
}
|
||||
elseif($role == 'dev')
|
||||
{
|
||||
$cols[] = array('title' => $lang->report->annualData->projectName, 'width' => 'auto', 'align' => 'left');
|
||||
$cols[] = array('title' => $lang->report->annualData->finishedStory, 'width' => '80', 'align' => 'center');
|
||||
$cols[] = array('title' => $lang->report->annualData->finishedTask, 'width' => '80', 'align' => 'center');
|
||||
$cols[] = array('title' => $lang->report->annualData->resolvedBug, 'width' => '80', 'align' => 'center');
|
||||
|
||||
foreach($data['projects'] as $project) $rows[] = array($project->name, $project->stories, $project->tasks, $project->bugs);
|
||||
}
|
||||
elseif($role == 'qa')
|
||||
{
|
||||
$cols[] = array('title' => $lang->report->annualData->productName, 'width' => 'auto', 'align' => 'left');
|
||||
$cols[] = array('title' => $lang->report->annualData->foundBug, 'width' => '80', 'align' => 'center');
|
||||
|
||||
foreach($data['products'] as $product) $rows[] = array($product->name, $product->bugs);
|
||||
}
|
||||
|
||||
echo "cols: " . json_encode($cols) . ',';
|
||||
echo "rows: " . json_encode($rows);
|
||||
}
|
||||
elseif($blockKey == 'block4')
|
||||
{
|
||||
if($role == 'qa')
|
||||
{
|
||||
foreach($blockConfig['data'] as $i => $name)
|
||||
{
|
||||
$totalData = array();
|
||||
foreach($data[$name] as $pri => $value) $totalData[] = array('title' => $pri, 'value' => $value, 'legend' => 'P' . $pri);
|
||||
|
||||
if($name == 'bugPri') $title = $lang->report->annualData->totalCreatedBug;
|
||||
if($name == 'casePri') $title = $lang->report->annualData->totalCreatedCase;
|
||||
$chart = array('title' => $title, 'unit' => $lang->report->annualData->unit, 'data' => $totalData);
|
||||
echo "chart" . ($i + 1) . ': ' . json_encode($chart) . ',';
|
||||
}
|
||||
}
|
||||
elseif($role == 'po')
|
||||
{
|
||||
$this->app->loadLang('story');
|
||||
foreach($blockConfig['data'] as $i => $name)
|
||||
{
|
||||
$totalData = array();
|
||||
foreach($data[$name] as $key => $value)
|
||||
{
|
||||
$legend = 'P' . $key;
|
||||
if($name == 'storyStage')
|
||||
{
|
||||
$legend = zget($lang->story->stageList, $key);
|
||||
if(empty($legend)) $legend = 'NULL';
|
||||
}
|
||||
$totalData[] = array('title' => $key, 'value' => $value, 'legend' => $legend);
|
||||
}
|
||||
|
||||
if($name == 'storyPri') $title = $lang->report->annualData->totalStoryPri;
|
||||
if($name == 'storyStage') $title = $lang->report->annualData->totalStoryStage;
|
||||
$chart = array('title' => $title, 'unit' => $lang->report->annualData->unit, 'data' => $totalData);
|
||||
echo "chart" . ($i + 1) . ': ' . json_encode($chart) . ',';
|
||||
}
|
||||
}
|
||||
elseif($role == 'dev')
|
||||
{
|
||||
foreach($blockConfig['data'] as $i => $name)
|
||||
{
|
||||
$totalData = array();
|
||||
foreach($data[$name] as $key => $value) $totalData[] = array('title' => $key, 'value' => $value, 'legend' => 'P' . $key);
|
||||
|
||||
if($name == 'finishedTaskPri') $title = $lang->report->annualData->totalFinishedTask;
|
||||
if($name == 'resolvedBugPri') $title = $lang->report->annualData->totalResolvedBug;
|
||||
$chart = array('title' => $title, 'unit' => $lang->report->annualData->unit, 'data' => $totalData);
|
||||
echo "chart" . ($i + 1) . ': ' . json_encode($chart) . ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($blockKey == 'block5')
|
||||
{
|
||||
echo 'labels:' . json_encode($lang->datepicker->monthNames) . ',';
|
||||
|
||||
if($role == 'qa')
|
||||
{
|
||||
$datasets = array();
|
||||
foreach($blockConfig['data'] as $i => $name)
|
||||
{
|
||||
if($name == 'bugMonth') $label = $lang->report->annualData->totalCreatedBug;
|
||||
if($name == 'caseMonth') $label = $lang->report->annualData->totalCreatedCase;
|
||||
$datasets[] = array('label' => $label, 'data' => $data[$name]);
|
||||
}
|
||||
}
|
||||
elseif($role == 'po')
|
||||
{
|
||||
$datasets = array();
|
||||
foreach($blockConfig['data'] as $i => $name)
|
||||
{
|
||||
if($name == 'storyMonth') $label = $lang->report->annualData->poStatistics;
|
||||
$datasets[] = array('label' => $label, 'data' => $data[$name]);
|
||||
}
|
||||
}
|
||||
elseif($role == 'dev')
|
||||
{
|
||||
$datasets = array();
|
||||
foreach($blockConfig['data'] as $i => $name)
|
||||
{
|
||||
if($name == 'effortMonth')
|
||||
{
|
||||
$label = $lang->report->annualData->totalConsumed;
|
||||
foreach($data[$name] as $month => $consumed) $data[$name][$month] = round($consumed, 2);
|
||||
}
|
||||
if($name == 'bugMonth') $label = $lang->report->annualData->totalResolvedBug;
|
||||
if($name == 'taskMonth')$label = $lang->report->annualData->totalFinishedTask;
|
||||
$datasets[] = array('label' => $label, 'data' => $data[$name]);
|
||||
}
|
||||
}
|
||||
echo "datasets: " . json_encode($datasets);
|
||||
}
|
||||
?>
|
||||
},
|
||||
<?php endforeach;?>
|
||||
};
|
||||
|
||||
$(function()
|
||||
{
|
||||
showAnnualData(annualData);
|
||||
});
|
||||
var radarChart = echarts.init(document.getElementById('radarCanvas'));
|
||||
var radarOption = {
|
||||
tooltip: {},
|
||||
radar: {
|
||||
splitArea:{areaStyle:{color: ['#010419']}},
|
||||
radius:'65%',
|
||||
<?php
|
||||
$max = max($radarData);
|
||||
if($max == 0) $max = 1;
|
||||
$indicator = array();
|
||||
foreach($annualDataLang->radarItems as $radarKey => $radarName)
|
||||
{
|
||||
$indicator[$radarKey]['name'] = $radarName;
|
||||
$indicator[$radarKey]['max'] = $max;
|
||||
}
|
||||
?>
|
||||
indicator: <?php echo json_encode(array_values($indicator));?>
|
||||
},
|
||||
series: [{
|
||||
name:'<?php echo $annualDataLang->radar;?>',
|
||||
areaStyle:{color: 'rgb(45, 40, 33)'},
|
||||
type: 'radar',
|
||||
itemStyle: {color: "#fff", borderColor:"rgb(247, 193, 35)"},
|
||||
lineStyle: {color: "rgb(247, 193, 35)"},
|
||||
data: [{value: <?php echo json_encode(array_values($radarData));?>}]
|
||||
}]
|
||||
};
|
||||
|
||||
radarChart.setOption(radarOption);
|
||||
|
||||
var overviewCSS = {position: 'absolute', left: '172px', top: '160px'};
|
||||
|
||||
<?php unset($lang->story->statusList['']);?>
|
||||
<?php unset($lang->bug->statusList['']);?>
|
||||
<?php unset($lang->task->statusList['']);?>
|
||||
<?php if(empty($dept) and empty($userID)):?>
|
||||
<?php foreach($data['statusStat'] as $objectType => $objectStatusStat):?>
|
||||
<?php
|
||||
$statusStat = array();
|
||||
foreach($lang->$objectType->statusList as $status => $statusName)
|
||||
{
|
||||
$statusCount = zget($objectStatusStat, $status, 0);
|
||||
if($statusCount == 0) continue;
|
||||
$statusStat[$status] = array('name' => $statusName, 'value' => $statusCount);
|
||||
}
|
||||
$canvasID = 'all' . ucfirst($objectType) . 'StatusCanvas';
|
||||
$canvasTitleKey = $objectType . 'StatusStat';
|
||||
$jsonedStatusStat = json_encode(array_values($statusStat));
|
||||
echo "drawStatusPieChart('{$canvasID}', '{$annualDataLang->$canvasTitleKey}', $jsonedStatusStat,
|
||||
function()
|
||||
{
|
||||
$('#allTimeStatusStat .{$objectType}Overview').appendTo('#{$canvasID}').removeClass('hidden').css(overviewCSS)
|
||||
});\n";
|
||||
?>
|
||||
<?php endforeach;?>
|
||||
<?php endif;?>
|
||||
|
||||
var yearOverviewCSS = {position: 'absolute', left: '200px', top: '160px'};
|
||||
<?php foreach(array('story', 'task', 'bug', 'case') as $objectType):?>
|
||||
<?php
|
||||
$stat = array();
|
||||
$items = $objectType == 'case' ? $lang->testcase->resultList : $lang->$objectType->statusList;
|
||||
$statKey = $objectType == 'case' ? 'resultStat' : 'statusStat';
|
||||
foreach($items as $key => $name)
|
||||
{
|
||||
$itemCount = zget($data["{$objectType}Stat"][$statKey], $key, 0);
|
||||
if($itemCount == 0) continue;
|
||||
$stat[$key] = array('name' => $name, 'value' => $itemCount);
|
||||
}
|
||||
|
||||
$ucfirst = ucfirst($objectType);
|
||||
$canvasID = $objectType == 'case' ? 'yearCaseResultCanvas' : 'year' . $ucfirst . 'StatusCanvas';
|
||||
$canvasTitleKey = $objectType == 'case' ? 'caseResultStat' : $objectType . 'StatusStat';
|
||||
$jsonedStat = json_encode(array_values($stat));
|
||||
|
||||
$drawFunction = "drawStatusPieChart('{$canvasID}', '{$annualDataLang->$canvasTitleKey}', $jsonedStat";
|
||||
if($objectType != 'case')
|
||||
{
|
||||
$drawFunction .= ", function()
|
||||
{
|
||||
$('#{$objectType}Data .year{$ucfirst}Overview').appendTo('#{$canvasID}').removeClass('hidden').css(yearOverviewCSS)
|
||||
}";
|
||||
}
|
||||
$drawFunction .= ");\n";
|
||||
|
||||
echo $drawFunction;
|
||||
?>
|
||||
<?php endforeach;?>
|
||||
|
||||
<?php
|
||||
$commonTemplate['name'] = '';
|
||||
$commonTemplate['type'] = 'bar';
|
||||
$commonTemplate['stack'] = 'all';
|
||||
$commonTemplate['label'] = array('show' => false);
|
||||
$commonTemplate['data'] = array();
|
||||
|
||||
$jsonedMonths = json_encode($months);
|
||||
foreach($annualDataConfig['month'] as $objectType => $actions):?>
|
||||
<?php
|
||||
$legends = array();
|
||||
$monthActions = array();
|
||||
$allCount = 0;
|
||||
foreach($actions as $actionKey => $action)
|
||||
{
|
||||
if(!isset($data["{$objectType}Stat"]['actionStat'][$actionKey])) continue;
|
||||
|
||||
$actionName = $annualDataLang->actionList[$action];
|
||||
$legends[] = $actionName;
|
||||
|
||||
$monthAction = $commonTemplate;
|
||||
$monthAction['name'] = $actionName;
|
||||
$monthAction['stack'] = $objectType;
|
||||
$monthAction['data'] = array_values($data["{$objectType}Stat"]['actionStat'][$actionKey]);
|
||||
$monthActions[] = $monthAction;
|
||||
|
||||
$allCount += array_sum($monthAction['data']);
|
||||
}
|
||||
|
||||
if($allCount == 0)
|
||||
{
|
||||
$monthActions = array();
|
||||
$legends = array();
|
||||
}
|
||||
|
||||
$canvasID = 'year' . ucfirst($objectType) . 'ActionCanvas';
|
||||
$canvasTitleKey = $objectType . 'MonthActions';
|
||||
$legends = json_encode($legends);
|
||||
$monthActions = json_encode($monthActions);
|
||||
echo "drawMonthsBarChart('{$canvasID}', '{$annualDataLang->$canvasTitleKey}', {$legends}, {$jsonedMonths}, {$monthActions});\n";
|
||||
?>
|
||||
<?php endforeach;?>
|
||||
})
|
||||
</script>
|
||||
<?php include '../../common/view/footer.lite.html.php';?>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
echo html::a($url . $link, $bug->title);
|
||||
?>
|
||||
</td>
|
||||
<td style='padding: 5px; text-align: center; border: 1px solid #e5e5e5;'><?php if($bug->deadline != '0000-00-00') echo $bug->deadline;?></td>
|
||||
<td style='padding: 5px; text-align: center; border: 1px solid #e5e5e5;'><?php if(!helper::isZeroDate($bug->deadline)) echo $bug->deadline;?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</table>
|
||||
@@ -60,7 +60,7 @@
|
||||
echo html::a($url . $link, $task->name);
|
||||
?>
|
||||
</td>
|
||||
<td style='padding: 5px; text-align: center; border: 1px solid #e5e5e5;'><?php if($task->deadline != '0000-00-00') echo $task->deadline;?></td>
|
||||
<td style='padding: 5px; text-align: center; border: 1px solid #e5e5e5;'><?php if(!helper::isZeroDate($task->deadline)) echo $task->deadline;?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</table>
|
||||
|
||||
@@ -249,7 +249,6 @@ class riskModel extends model
|
||||
$riskList = $this->dao->select('*')->from(TABLE_RISK)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere($type)->eq($account)->fi()
|
||||
->beginIF($this->app->rawMethod == 'contribute')->andWhere("status")->in('closed,canceled')->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll();
|
||||
|
||||
+30
-30
@@ -162,11 +162,11 @@ $lang->story->needNotReviewList[1] = 'Need Not Review';
|
||||
$lang->story->useList[0] = 'Ja';
|
||||
$lang->story->useList[1] = 'Nein';
|
||||
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = 'Entwurf';
|
||||
$lang->story->statusList['active'] = 'Aktiv';
|
||||
$lang->story->statusList['closed'] = 'Geschlossen';
|
||||
$lang->story->statusList['changed'] = 'Geändert';
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = 'Entwurf';
|
||||
$lang->story->statusList['active'] = 'Aktiv';
|
||||
$lang->story->statusList['closed'] = 'Geschlossen';
|
||||
$lang->story->statusList['changed'] = 'Geändert';
|
||||
|
||||
$lang->story->stageList[''] = '';
|
||||
$lang->story->stageList['wait'] = 'Wartend';
|
||||
@@ -240,11 +240,11 @@ $lang->story->legendSpec = 'Beschreibung';
|
||||
$lang->story->legendVerify = 'Akzeptanz';
|
||||
$lang->story->legendMisc = 'Sonstiges ';
|
||||
|
||||
$lang->story->lblChange = 'Ändern';
|
||||
$lang->story->lblReview = 'Prüfen';
|
||||
$lang->story->lblActivate = 'Aktivieren';
|
||||
$lang->story->lblClose = 'Close';
|
||||
$lang->story->lblTBC = 'Task/Bug/Case';
|
||||
$lang->story->lblChange = 'Ändern';
|
||||
$lang->story->lblReview = 'Prüfen';
|
||||
$lang->story->lblActivate = 'Aktivieren';
|
||||
$lang->story->lblClose = 'Close';
|
||||
$lang->story->lblTBC = 'Task/Bug/Case';
|
||||
|
||||
$lang->story->checkAffection = 'Impact';
|
||||
$lang->story->affectedProjects = '' . $lang->executionCommon;
|
||||
@@ -267,10 +267,10 @@ $lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved
|
||||
$lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.';
|
||||
|
||||
$lang->story->form = new stdclass();
|
||||
$lang->story->form->area = 'Story Bereich';
|
||||
$lang->story->form->desc = 'Welche Story ist es? Was sind die Abnahmebedingungen?';
|
||||
$lang->story->form->resource = 'Wer plant die Resourcen? Wie lange wird das dauern?';
|
||||
$lang->story->form->file = 'Wenn Dateien zu dieser Story gehören, laden Sie diese bIttr hoch.';
|
||||
$lang->story->form->area = 'Story Bereich';
|
||||
$lang->story->form->desc = 'Welche Story ist es? Was sind die Abnahmebedingungen?';
|
||||
$lang->story->form->resource = 'Wer plant die Resourcen? Wie lange wird das dauern?';
|
||||
$lang->story->form->file = 'Wenn Dateien zu dieser Story gehören, laden Sie diese bIttr hoch.';
|
||||
|
||||
$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');
|
||||
@@ -297,24 +297,24 @@ $lang->story->report->select = 'Storys gruppieren nach';
|
||||
$lang->story->report->create = 'Erzeugen';
|
||||
$lang->story->report->value = 'Story Anzahl';
|
||||
|
||||
$lang->story->report->charts['storysPerProduct'] = 'nach ' . $lang->productCommon;
|
||||
$lang->story->report->charts['storysPerModule'] = 'nach Modul';
|
||||
$lang->story->report->charts['storysPerSource'] = 'nach Source';
|
||||
$lang->story->report->charts['storysPerPlan'] = 'nach Plan';
|
||||
$lang->story->report->charts['storysPerStatus'] = 'nach Status';
|
||||
$lang->story->report->charts['storysPerStage'] = 'nach Phase';
|
||||
$lang->story->report->charts['storysPerPri'] = 'nach Priorität';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'nach Stunden';
|
||||
$lang->story->report->charts['storysPerOpenedBy'] = 'nach Ersteller';
|
||||
$lang->story->report->charts['storysPerAssignedTo'] = 'nach Zuständiger';
|
||||
$lang->story->report->charts['storysPerClosedReason'] = 'nach Grund';
|
||||
$lang->story->report->charts['storysPerChange'] = 'nach Änderungszeit';
|
||||
$lang->story->report->charts['storysPerProduct'] = 'nach ' . $lang->productCommon;
|
||||
$lang->story->report->charts['storysPerModule'] = 'nach Modul';
|
||||
$lang->story->report->charts['storysPerSource'] = 'nach Source';
|
||||
$lang->story->report->charts['storysPerPlan'] = 'nach Plan';
|
||||
$lang->story->report->charts['storysPerStatus'] = 'nach Status';
|
||||
$lang->story->report->charts['storysPerStage'] = 'nach Phase';
|
||||
$lang->story->report->charts['storysPerPri'] = 'nach Priorität';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'nach Stunden';
|
||||
$lang->story->report->charts['storysPerOpenedBy'] = 'nach Ersteller';
|
||||
$lang->story->report->charts['storysPerAssignedTo'] = 'nach Zuständiger';
|
||||
$lang->story->report->charts['storysPerClosedReason'] = 'nach Grund';
|
||||
$lang->story->report->charts['storysPerChange'] = 'nach Änderungszeit';
|
||||
|
||||
$lang->story->report->options = new stdclass();
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
|
||||
$lang->story->report->storysPerProduct = new stdclass();
|
||||
$lang->story->report->storysPerModule = new stdclass();
|
||||
|
||||
+30
-30
@@ -162,11 +162,11 @@ $lang->story->needNotReviewList[1] = 'Need Not Review';
|
||||
$lang->story->useList[0] = 'Yes';
|
||||
$lang->story->useList[1] = 'No';
|
||||
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = 'Draft';
|
||||
$lang->story->statusList['active'] = 'Active';
|
||||
$lang->story->statusList['closed'] = 'Closed';
|
||||
$lang->story->statusList['changed'] = 'Changed';
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = 'Draft';
|
||||
$lang->story->statusList['active'] = 'Active';
|
||||
$lang->story->statusList['closed'] = 'Closed';
|
||||
$lang->story->statusList['changed'] = 'Changed';
|
||||
|
||||
$lang->story->stageList[''] = '';
|
||||
$lang->story->stageList['wait'] = 'Waiting';
|
||||
@@ -240,11 +240,11 @@ $lang->story->legendSpec = 'Description';
|
||||
$lang->story->legendVerify = 'Acceptance';
|
||||
$lang->story->legendMisc = 'Misc.';
|
||||
|
||||
$lang->story->lblChange = 'Change';
|
||||
$lang->story->lblReview = 'Review';
|
||||
$lang->story->lblActivate = 'Activate';
|
||||
$lang->story->lblClose = 'Close';
|
||||
$lang->story->lblTBC = 'Task/Bug/Case';
|
||||
$lang->story->lblChange = 'Change';
|
||||
$lang->story->lblReview = 'Review';
|
||||
$lang->story->lblActivate = 'Activate';
|
||||
$lang->story->lblClose = 'Close';
|
||||
$lang->story->lblTBC = 'Task/Bug/Case';
|
||||
|
||||
$lang->story->checkAffection = 'Influence';
|
||||
$lang->story->affectedProjects = '' . $lang->executionCommon . 's';
|
||||
@@ -267,10 +267,10 @@ $lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved
|
||||
$lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.';
|
||||
|
||||
$lang->story->form = new stdclass();
|
||||
$lang->story->form->area = 'Scope';
|
||||
$lang->story->form->desc = 'What story is it? What is the acceptance?';
|
||||
$lang->story->form->resource = 'Who will allocate resources? How long does it take?';
|
||||
$lang->story->form->file = 'If any file that is linked to a story, please click Here to upload it.';
|
||||
$lang->story->form->area = 'Scope';
|
||||
$lang->story->form->desc = 'What story is it? What is the acceptance?';
|
||||
$lang->story->form->resource = 'Who will allocate resources? How long does it take?';
|
||||
$lang->story->form->file = 'If any file that is linked to a story, please click Here to upload it.';
|
||||
|
||||
$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');
|
||||
@@ -297,24 +297,24 @@ $lang->story->report->select = 'Select Report Type';
|
||||
$lang->story->report->create = 'Create Report';
|
||||
$lang->story->report->value = 'Reports';
|
||||
|
||||
$lang->story->report->charts['storysPerProduct'] = 'Group by ' . $lang->productCommon . ' Story';
|
||||
$lang->story->report->charts['storysPerModule'] = 'Group by Module Story';
|
||||
$lang->story->report->charts['storysPerSource'] = 'Group by Story Source';
|
||||
$lang->story->report->charts['storysPerPlan'] = 'Group by Plan';
|
||||
$lang->story->report->charts['storysPerStatus'] = 'Group by Status';
|
||||
$lang->story->report->charts['storysPerStage'] = 'Group by Phase';
|
||||
$lang->story->report->charts['storysPerPri'] = 'Group by Priority';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'Group by Estimates';
|
||||
$lang->story->report->charts['storysPerOpenedBy'] = 'Group by CreatedBy';
|
||||
$lang->story->report->charts['storysPerAssignedTo'] = 'Group by AssignedTo';
|
||||
$lang->story->report->charts['storysPerClosedReason'] = 'Group by Closed Reason';
|
||||
$lang->story->report->charts['storysPerChange'] = 'Group by Changed Story';
|
||||
$lang->story->report->charts['storysPerProduct'] = 'Group by ' . $lang->productCommon . ' Story';
|
||||
$lang->story->report->charts['storysPerModule'] = 'Group by Module Story';
|
||||
$lang->story->report->charts['storysPerSource'] = 'Group by Story Source';
|
||||
$lang->story->report->charts['storysPerPlan'] = 'Group by Plan';
|
||||
$lang->story->report->charts['storysPerStatus'] = 'Group by Status';
|
||||
$lang->story->report->charts['storysPerStage'] = 'Group by Phase';
|
||||
$lang->story->report->charts['storysPerPri'] = 'Group by Priority';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'Group by Estimates';
|
||||
$lang->story->report->charts['storysPerOpenedBy'] = 'Group by CreatedBy';
|
||||
$lang->story->report->charts['storysPerAssignedTo'] = 'Group by AssignedTo';
|
||||
$lang->story->report->charts['storysPerClosedReason'] = 'Group by Closed Reason';
|
||||
$lang->story->report->charts['storysPerChange'] = 'Group by Changed Story';
|
||||
|
||||
$lang->story->report->options = new stdclass();
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
|
||||
$lang->story->report->storysPerProduct = new stdclass();
|
||||
$lang->story->report->storysPerModule = new stdclass();
|
||||
|
||||
+30
-30
@@ -162,11 +162,11 @@ $lang->story->needNotReviewList[1] = 'Need Not Review';
|
||||
$lang->story->useList[0] = 'Oui';
|
||||
$lang->story->useList[1] = 'Non';
|
||||
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = 'Brouillon';
|
||||
$lang->story->statusList['active'] = 'Active';
|
||||
$lang->story->statusList['closed'] = 'Fermée';
|
||||
$lang->story->statusList['changed'] = 'Changée';
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = 'Brouillon';
|
||||
$lang->story->statusList['active'] = 'Active';
|
||||
$lang->story->statusList['closed'] = 'Fermée';
|
||||
$lang->story->statusList['changed'] = 'Changée';
|
||||
|
||||
$lang->story->stageList[''] = '';
|
||||
$lang->story->stageList['wait'] = 'En Attente';
|
||||
@@ -240,11 +240,11 @@ $lang->story->legendSpec = 'Description';
|
||||
$lang->story->legendVerify = 'Acceptance';
|
||||
$lang->story->legendMisc = 'Divers';
|
||||
|
||||
$lang->story->lblChange = 'Changer';
|
||||
$lang->story->lblReview = 'Valider';
|
||||
$lang->story->lblActivate = 'Activer';
|
||||
$lang->story->lblClose = 'Fermer';
|
||||
$lang->story->lblTBC = 'Tâche/Bug/CasTest';
|
||||
$lang->story->lblChange = 'Changer';
|
||||
$lang->story->lblReview = 'Valider';
|
||||
$lang->story->lblActivate = 'Activer';
|
||||
$lang->story->lblClose = 'Fermer';
|
||||
$lang->story->lblTBC = 'Tâche/Bug/CasTest';
|
||||
|
||||
$lang->story->checkAffection = 'Influence';
|
||||
$lang->story->affectedProjects = '' . $lang->executionCommon . 's';
|
||||
@@ -267,10 +267,10 @@ $lang->story->moveChildrenTips = "Its Child {$lang->SRCommon} will be moved
|
||||
$lang->story->changeTips = 'The story associated with the requirements to change, click "Cancel" ignore this change, click "Confirm" to change the story.';
|
||||
|
||||
$lang->story->form = new stdclass();
|
||||
$lang->story->form->area = 'Périmètre';
|
||||
$lang->story->form->desc = "Quelle story est-ce ? Quel est son état d'acceptance ?";
|
||||
$lang->story->form->resource = 'Qui va allouer des resources ? Combien de temps cela va-t-il prendre ?';
|
||||
$lang->story->form->file = 'Si certains fichiers sont associés à la story, cliquez ici pour les uploader.';
|
||||
$lang->story->form->area = 'Périmètre';
|
||||
$lang->story->form->desc = "Quelle story est-ce ? Quel est son état d'acceptance ?";
|
||||
$lang->story->form->resource = 'Qui va allouer des resources ? Combien de temps cela va-t-il prendre ?';
|
||||
$lang->story->form->file = 'Si certains fichiers sont associés à la story, cliquez ici pour les uploader.';
|
||||
|
||||
$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');
|
||||
@@ -297,24 +297,24 @@ $lang->story->report->select = 'Choix Type de Rapport';
|
||||
$lang->story->report->create = 'Créer Rapport';
|
||||
$lang->story->report->value = 'Rapports';
|
||||
|
||||
$lang->story->report->charts['storysPerProduct'] = 'Regroupé par ' . $lang->productCommon . ' Story';
|
||||
$lang->story->report->charts['storysPerModule'] = 'Regroupé par Module Story';
|
||||
$lang->story->report->charts['storysPerSource'] = 'Regroupé par Source';
|
||||
$lang->story->report->charts['storysPerPlan'] = 'Regroupé par Plan';
|
||||
$lang->story->report->charts['storysPerStatus'] = 'Regroupé par Statut';
|
||||
$lang->story->report->charts['storysPerStage'] = 'Regroupé par Phase';
|
||||
$lang->story->report->charts['storysPerPri'] = 'Regroupé par Priorité';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'Regroupé par Estimés';
|
||||
$lang->story->report->charts['storysPerOpenedBy'] = 'Regroupé par Créateur';
|
||||
$lang->story->report->charts['storysPerAssignedTo'] = 'Regroupé par Détenteur';
|
||||
$lang->story->report->charts['storysPerClosedReason'] = 'Par Raison de Fermeture';
|
||||
$lang->story->report->charts['storysPerChange'] = 'Regroupé par Modif de Story';
|
||||
$lang->story->report->charts['storysPerProduct'] = 'Regroupé par ' . $lang->productCommon . ' Story';
|
||||
$lang->story->report->charts['storysPerModule'] = 'Regroupé par Module Story';
|
||||
$lang->story->report->charts['storysPerSource'] = 'Regroupé par Source';
|
||||
$lang->story->report->charts['storysPerPlan'] = 'Regroupé par Plan';
|
||||
$lang->story->report->charts['storysPerStatus'] = 'Regroupé par Statut';
|
||||
$lang->story->report->charts['storysPerStage'] = 'Regroupé par Phase';
|
||||
$lang->story->report->charts['storysPerPri'] = 'Regroupé par Priorité';
|
||||
$lang->story->report->charts['storysPerEstimate'] = 'Regroupé par Estimés';
|
||||
$lang->story->report->charts['storysPerOpenedBy'] = 'Regroupé par Créateur';
|
||||
$lang->story->report->charts['storysPerAssignedTo'] = 'Regroupé par Détenteur';
|
||||
$lang->story->report->charts['storysPerClosedReason'] = 'Par Raison de Fermeture';
|
||||
$lang->story->report->charts['storysPerChange'] = 'Regroupé par Modif de Story';
|
||||
|
||||
$lang->story->report->options = new stdclass();
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
|
||||
$lang->story->report->storysPerProduct = new stdclass();
|
||||
$lang->story->report->storysPerModule = new stdclass();
|
||||
|
||||
@@ -162,11 +162,11 @@ $lang->story->needNotReviewList[1] = '不需要评审';
|
||||
$lang->story->useList[0] = '不使用';
|
||||
$lang->story->useList[1] = '使用';
|
||||
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = '草稿';
|
||||
$lang->story->statusList['active'] = '激活';
|
||||
$lang->story->statusList['closed'] = '已关闭';
|
||||
$lang->story->statusList['changed'] = '已变更';
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = '草稿';
|
||||
$lang->story->statusList['active'] = '激活';
|
||||
$lang->story->statusList['closed'] = '已关闭';
|
||||
$lang->story->statusList['changed'] = '已变更';
|
||||
|
||||
$lang->story->stageList[''] = '';
|
||||
$lang->story->stageList['wait'] = '未开始';
|
||||
@@ -311,10 +311,10 @@ $lang->story->report->charts['storysPerClosedReason'] = '按关闭原因来进
|
||||
$lang->story->report->charts['storysPerChange'] = '按变更次数来进行统计';
|
||||
|
||||
$lang->story->report->options = new stdclass();
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
|
||||
$lang->story->report->storysPerProduct = new stdclass();
|
||||
$lang->story->report->storysPerModule = new stdclass();
|
||||
|
||||
@@ -162,11 +162,11 @@ $lang->story->needNotReviewList[1] = '不需要評審';
|
||||
$lang->story->useList[0] = '不使用';
|
||||
$lang->story->useList[1] = '使用';
|
||||
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = '草稿';
|
||||
$lang->story->statusList['active'] = '激活';
|
||||
$lang->story->statusList['closed'] = '已關閉';
|
||||
$lang->story->statusList['changed'] = '已變更';
|
||||
$lang->story->statusList[''] = '';
|
||||
$lang->story->statusList['draft'] = '草稿';
|
||||
$lang->story->statusList['active'] = '激活';
|
||||
$lang->story->statusList['closed'] = '已關閉';
|
||||
$lang->story->statusList['changed'] = '已變更';
|
||||
|
||||
$lang->story->stageList[''] = '';
|
||||
$lang->story->stageList['wait'] = '未開始';
|
||||
@@ -311,10 +311,10 @@ $lang->story->report->charts['storysPerClosedReason'] = '按關閉原因來進
|
||||
$lang->story->report->charts['storysPerChange'] = '按變更次數來進行統計';
|
||||
|
||||
$lang->story->report->options = new stdclass();
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
$lang->story->report->options->graph = new stdclass();
|
||||
$lang->story->report->options->type = 'pie';
|
||||
$lang->story->report->options->width = 500;
|
||||
$lang->story->report->options->height = 140;
|
||||
|
||||
$lang->story->report->storysPerProduct = new stdclass();
|
||||
$lang->story->report->storysPerModule = new stdclass();
|
||||
|
||||
@@ -2528,7 +2528,6 @@ class storyModel extends model
|
||||
->beginIF($type == 'reviewedBy')->andWhere("CONCAT(',', reviewedBy, ',')")->like("%,$account,%")->fi()
|
||||
->beginIF($type == 'closedBy')->andWhere('closedBy')->eq($account)->fi()
|
||||
->fi()
|
||||
->beginIF($this->app->rawMethod == 'contribute')->andWhere("t1.status")->eq('closed')->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager)
|
||||
->fetchAll('id');
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class='main-table' data-ride="table">
|
||||
<table class='table table-bordered' id="trackList">
|
||||
<thead>
|
||||
<tr>
|
||||
<tr class='text-center'>
|
||||
<th <?php echo $style;?>>
|
||||
<?php if($this->app->rawModule == 'projectstory'): ?>
|
||||
<div class="dropdown">
|
||||
|
||||
@@ -1204,7 +1204,7 @@ class task extends control
|
||||
}
|
||||
|
||||
if(!isset($this->view->members[$this->view->task->finishedBy])) $this->view->members[$this->view->task->finishedBy] = $this->view->task->finishedBy;
|
||||
$this->view->title = $this->view->project->name . $this->lang->colon .$this->lang->task->activate;
|
||||
$this->view->title = $this->view->project->name . $this->lang->colon . $this->lang->task->activate;
|
||||
$this->view->position[] = $this->lang->task->activate;
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noletter');
|
||||
$this->display();
|
||||
|
||||
@@ -52,8 +52,8 @@ class taskModel extends model
|
||||
->setIF($this->post->story != false, 'storyVersion', $this->loadModel('story')->getVersion($this->post->story))
|
||||
->setDefault('estStarted', '0000-00-00')
|
||||
->setDefault('deadline', '0000-00-00')
|
||||
->setIF(strpos($requiredFields, 'estStarted') !== false, 'estStarted', $this->post->estStarted)
|
||||
->setIF(strpos($requiredFields, 'deadline') !== false, 'deadline', $this->post->deadline)
|
||||
->setIF(strpos($requiredFields, 'estStarted') !== false, 'estStarted', helper::isZeroDate($this->post->estStarted) ? '' : $this->post->estStarted)
|
||||
->setIF(strpos($requiredFields, 'deadline') !== false, 'deadline', helper::isZeroDate($this->post->deadline) ? '' : $this->post->deadline)
|
||||
->setIF(strpos($requiredFields, 'estimate') !== false, 'estimate', $this->post->estimate)
|
||||
->setIF(strpos($requiredFields, 'left') !== false, 'left', $this->post->left)
|
||||
->setIF(strpos($requiredFields, 'story') !== false, 'story', $this->post->story)
|
||||
@@ -114,7 +114,7 @@ class taskModel extends model
|
||||
->autoCheck()
|
||||
->batchCheck($requiredFields, 'notempty')
|
||||
->checkIF($task->estimate != '', 'estimate', 'float')
|
||||
->checkIF($task->deadline != '0000-00-00', 'deadline', 'ge', $task->estStarted)
|
||||
->checkIF(!helper::isZeroDate($task->deadline), 'deadline', 'ge', $task->estStarted)
|
||||
->exec();
|
||||
|
||||
if(dao::isError()) return false;
|
||||
@@ -337,7 +337,7 @@ class taskModel extends model
|
||||
/* check data. */
|
||||
foreach($data as $i => $task)
|
||||
{
|
||||
if($task->deadline != '0000-00-00' and $task->deadline < $task->estStarted)
|
||||
if(!helper::isZeroDate($task->deadline) and $task->deadline < $task->estStarted)
|
||||
{
|
||||
dao::$errors['message'][] = $this->lang->task->error->deadlineSmall;
|
||||
return false;
|
||||
@@ -625,6 +625,7 @@ class taskModel extends model
|
||||
{
|
||||
if(!$createAction) return $task;
|
||||
|
||||
if($parentTask->story) $this->loadModel('story')->setStage($parentTask->story);
|
||||
$newParentTask = $this->dao->select('*')->from(TABLE_TASK)->where('id')->eq($parentID)->fetch();
|
||||
$changes = common::createChanges($oldParentTask, $newParentTask);
|
||||
$action = '';
|
||||
@@ -923,7 +924,7 @@ class taskModel extends model
|
||||
$this->dao->update(TABLE_TASK)->data($task)
|
||||
->autoCheck()
|
||||
->batchCheckIF($task->status != 'cancel', $requiredFields, 'notempty')
|
||||
->checkIF($task->deadline != '0000-00-00', 'deadline', 'ge', $task->estStarted)
|
||||
->checkIF(!helper::isZeroDate($task->deadline), 'deadline', 'ge', $task->estStarted)
|
||||
|
||||
->checkIF($task->estimate != false, 'estimate', 'float')
|
||||
->checkIF($task->left != false, 'left', 'float')
|
||||
@@ -1147,7 +1148,7 @@ class taskModel extends model
|
||||
$task->closedBy = $this->app->user->account;
|
||||
$task->closedDate = $now;
|
||||
}
|
||||
if($task->closedReason == 'cancel' and $task->finishedDate == '0000-00-00 00:00:00') $task->finishedDate = '';
|
||||
if($task->closedReason == 'cancel' and helper::isZeroDate($task->finishedDate)) $task->finishedDate = '';
|
||||
break;
|
||||
case 'wait':
|
||||
if($task->consumed > 0 and $task->left > 0) $task->status = 'doing';
|
||||
@@ -1565,7 +1566,7 @@ class taskModel extends model
|
||||
|
||||
$task = fixer::input('post')
|
||||
->setIF(is_numeric($this->post->consumed), 'consumed', (float)$this->post->consumed)
|
||||
->setIF($oldTask->realStarted == '0000-00-00 00:00:00', 'realStarted', $now)
|
||||
->setIF(helper::isZeroDate($oldTask->realStarted), 'realStarted', $now)
|
||||
->setDefault('left', 0)
|
||||
->setDefault('assignedTo', $oldTask->openedBy)
|
||||
->setDefault('assignedDate', $now)
|
||||
@@ -2074,7 +2075,6 @@ class taskModel extends model
|
||||
->orWhere('t1.finishedList')->like("%,{$account},%")
|
||||
->markRight(1)
|
||||
->fi()
|
||||
->beginIF($this->app->rawMethod == 'contribute')->andWhere("t1.status")->in('closed,done,cancel')->fi()
|
||||
->beginIF($type != 'all' and $type != 'finishedBy')->andWhere("t1.`$type`")->eq($account)->fi()
|
||||
->orderBy($orderBy)
|
||||
->beginIF($limit > 0)->limit($limit)->fi()
|
||||
@@ -2422,7 +2422,7 @@ class taskModel extends model
|
||||
/* Delayed or not?. */
|
||||
if($task->status !== 'done' and $task->status !== 'cancel' and $task->status != 'closed')
|
||||
{
|
||||
if($task->deadline != '0000-00-00')
|
||||
if(!helper::isZeroDate($task->deadline))
|
||||
{
|
||||
$delay = helper::diffDate($today, $task->deadline);
|
||||
if($delay > 0) $task->delay = $delay;
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
<th class='thWidth'><?php echo $lang->task->execution;?></th>
|
||||
<td><?php echo html::select('project', $projects, $task->project, 'class="form-control chosen" onchange="loadAll(this.value)"');?></td>
|
||||
</tr>
|
||||
<?php else:?>
|
||||
<?php echo html::hidden('project', $task->project);?>
|
||||
<?php endif;?>
|
||||
<tr>
|
||||
<th class='thWidth'><?php echo $lang->task->module;?></th>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<th class='w-90px'><?php echo $lang->task->realStarted;?></th>
|
||||
<td class='w-p25-f'><div class='datepicker-wrapper datepicker-date'><?php echo html::input('realStarted', $task->realStarted == '0000-00-00 00:00:00' ? helper::now() : $task->realStarted, "class='form-control form-datetime' data-picker-position='bottom-right'");?></div></td>
|
||||
<td class='w-p25-f'><div class='datepicker-wrapper datepicker-date'><?php echo html::input('realStarted', helper::isZeroDate($task->realStarted) ? helper::now() : $task->realStarted, "class='form-control form-datetime' data-picker-position='bottom-right'");?></div></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
@@ -1648,8 +1648,8 @@ class testcase extends control
|
||||
|
||||
foreach($steps as $step)
|
||||
{
|
||||
$step = trim($step);
|
||||
if(empty($step)) continue;
|
||||
$trimedStep = trim($step);
|
||||
if(empty($trimedStep)) continue;
|
||||
if(preg_match('/^(([0-9]+)\.[0-9]+)([.、]{1})/U', $step, $out))
|
||||
{
|
||||
$num = $out[1];
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<td class='text-left' title='<?php echo $bug->title?>'><?php echo html::a($sysURL . $this->createLink('bug', 'view', "bugID=$bug->id", '', true), $bug->title, '', "data-toggle='modal' data-type='iframe' data-width='90%'");?></td>
|
||||
<td><?php echo zget($users, $bug->openedBy);?></td>
|
||||
<td><?php echo zget($users, $bug->resolvedBy);?></td>
|
||||
<td><?php if($bug->resolvedDate != '0000-00-00 00:00:00') echo substr($bug->resolvedDate, 2);?></td>
|
||||
<td><?php if(!helper::isZeroDate($bug->resolvedDate)) echo substr($bug->resolvedDate, 2);?></td>
|
||||
<?php $status = $this->processStatus('bug', $bug);?>
|
||||
<td title='<?php echo $status;?>'>
|
||||
<span class="status-bug status-<?php echo $bug->status?>"><?php echo $status;?></span>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<td class='text-left' title='<?php echo $bug->title?>'><?php echo html::a($sysURL . $this->createLink('bug', 'view', "bugID=$bug->id", '', true), $bug->title, '', "data-toggle='modal' data-type='iframe' data-width='90%'");?></td>
|
||||
<td><?php echo zget($users, $bug->openedBy);?></td>
|
||||
<td><?php echo zget($users, $bug->resolvedBy);?></td>
|
||||
<td><?php if($bug->resolvedDate != '0000-00-00 00:00:00') echo substr($bug->resolvedDate, 2);?></td>
|
||||
<td><?php if(!helper::isZeroDate($bug->resolvedDate)) echo substr($bug->resolvedDate, 2);?></td>
|
||||
<?php $status = $this->processStatus('bug', $bug);?>
|
||||
<td title='<?php echo $status;?>'>
|
||||
<span class="status-bug status-<?php echo $bug->status?>"><?php echo $status;?></span>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.c-desc {overflow: scroll;}
|
||||
@@ -62,7 +62,7 @@
|
||||
<?php if($suite->type == 'private') echo "<span class='label label-info label-badge'>{$lang->testsuite->authorList['private']}</span> ";?>
|
||||
<?php echo html::a(inlink('view', "suiteID=$suite->id"), $suite->name);?>
|
||||
</td>
|
||||
<td><?php echo $suite->desc;?></td>
|
||||
<td class='c-desc'><?php echo $suite->desc;?></td>
|
||||
<td><?php echo zget($users, $suite->addedBy);?></td>
|
||||
<td><?php echo $suite->addedDate;?></td>
|
||||
<?php foreach($extendFields as $extendField) echo "<td>" . $this->loadModel('flow')->getFieldValue($extendField, $suite) . "</td>";?>
|
||||
|
||||
@@ -1201,4 +1201,18 @@ class testtask extends control
|
||||
if($id) die(html::select("testtasks[$id]", $testTasks, '', 'class="form-control"'));
|
||||
die(html::select('testtask', $testTasks, '', 'class=form-control'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax get test tasks
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $projectID
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetTestTasks($productID, $projectID = 0)
|
||||
{
|
||||
$pairs = $this->testtask->getPairs($productID, $projectID);
|
||||
die(html::select('testtask', $pairs, '', "class='form-control chosen'"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ $lang->testtask->legendBasicInfo = 'Basic Info';
|
||||
|
||||
$lang->testtask->statusList['wait'] = 'Waiting';
|
||||
$lang->testtask->statusList['doing'] = 'Doing';
|
||||
$lang->testtask->statusList['done'] = 'Done';
|
||||
$lang->testtask->statusList['done'] = 'Closed';
|
||||
$lang->testtask->statusList['blocked'] = 'Blocked';
|
||||
|
||||
$lang->testtask->priList[0] = '';
|
||||
|
||||
@@ -100,7 +100,7 @@ $lang->testtask->legendBasicInfo = '基本信息';
|
||||
|
||||
$lang->testtask->statusList['wait'] = '未开始';
|
||||
$lang->testtask->statusList['doing'] = '进行中';
|
||||
$lang->testtask->statusList['done'] = '已完成';
|
||||
$lang->testtask->statusList['done'] = '已关闭';
|
||||
$lang->testtask->statusList['blocked'] = '被阻塞';
|
||||
|
||||
$lang->testtask->priList[0] = '';
|
||||
|
||||
@@ -100,7 +100,7 @@ $lang->testtask->legendBasicInfo = '基本信息';
|
||||
|
||||
$lang->testtask->statusList['wait'] = '未開始';
|
||||
$lang->testtask->statusList['doing'] = '進行中';
|
||||
$lang->testtask->statusList['done'] = '已完成';
|
||||
$lang->testtask->statusList['done'] = '已關閉';
|
||||
$lang->testtask->statusList['blocked'] = '被阻塞';
|
||||
|
||||
$lang->testtask->priList[0] = '';
|
||||
|
||||
@@ -279,6 +279,32 @@ class testtaskModel extends model
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get testtask pairs
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $projectID
|
||||
* @param string $appendIdList
|
||||
* @param string $params noempty
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getPairs($productID, $projectID = 0, $appendIdList = '', $params = '')
|
||||
{
|
||||
$pairs = $this->dao->select('id,name')->from(TABLE_TESTTASK)
|
||||
->where('product')->eq((int)$productID)
|
||||
->beginIF($projectID)->andWhere('project')->eq((int)$projectID)->fi()
|
||||
->andWhere('auto')->ne('unit')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->orderBy('id_desc')
|
||||
->fetchPairs('id', 'name');
|
||||
|
||||
if($appendIdList) $pairs += $this->dao->select('id,name')->from(TABLE_TESTTASK)->where('id')->in($appendIdList)->fetchPairs('id', 'name');
|
||||
if(strpos($params, 'noempty') === false) $pairs = array(0 => '') + $pairs;
|
||||
|
||||
return $pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get task by idList.
|
||||
*
|
||||
|
||||
@@ -312,10 +312,6 @@ class tree extends control
|
||||
}
|
||||
|
||||
$module = $this->tree->getById($moduleID);
|
||||
if($module->owner == null and $module->root != 0 and $module->type != 'task' and $type != 'doc')
|
||||
{
|
||||
$module->owner = $this->loadModel('product')->getById($module->root)->QD;
|
||||
}
|
||||
|
||||
if($type == 'task')
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user