禅道二次开发
禅道修改、php环境、bug统计
近期要对禅道做一些修改,安装了一堆php环境,但还是不晓得怎么将项目本地跑起来,索性在测试服务器部署了一个新的开源版禅道,直接连接数据库,拷贝下文件夹/opt/zbox/app/zentao中的代码,直接进行修改,服务器重启修改看效果,以下是修改过程中的记录。
一、windows安装环境
1、集成环境php环境phpStudy安装
phpStudy安装后目下即产生G:\php\phpStudy\Extensions\php\php7.3.4nts
可直接用于配置php环境变量(https://www.xp.cn/ phpStudy_64.zip),所需的其他套件如Apache、mysql等都可以通过phpStudy安装使用。
2、编辑器(PhpStorm2020.3_129854)
与idea类似,PhpStorm2020.3_129854.rar下载解压后可按说明激活、安装汉化包
百度网盘链接:https://pan.baidu.com/s/10Xe6JtXQ1uUtAJm8KaHzHg
提取码:2v15
二、centos禅道安装修改
1、安装、连接数据库
禅道官方 (推荐)linux用一键安装包文档:https://www.zentao.net/book/zentaopmshelp/90.html
文中使用修改版本ZenTaoPMS.12.5.3.zbox_64.tar.gz:
百度网盘链接:https://pan.baidu.com/s/10Xe6JtXQ1uUtAJm8KaHzHg
提取码:2v15
常用命令:
1、将安装包直接解压到/opt目录下 sudo tar -zxvf ZenTaoPMS.12.5.3.zbox_64.tar.gz -C /opt
2、 Apache和Mysql常用命令
执行/opt/zbox/zbox start 命令开启Apache和Mysql。
执行/opt/zbox/zbox stop 命令停止Apache和Mysql。
执行/opt/zbox/zbox restart 命令重启Apache和Mysql。
3、修改Apache端口
如果服务器的80端口没有开放或者端口冲突的话:
/opt/zbox/zbox -h //查看zbox的帮助命令
/opt/zbox/zbox -ap 8080 //修改Apache服务器的端口号为8080
/opt/zbox/zbox restart //重启Apache服务器
做完以上操作之后,禅道的端口号就被修改为8080了
4、修改mysql端口
修改mysql端口:
/opt/zbox/zbox -mp 8090 //修改mysql服务器的端口号为8090
/opt/zbox/zbox restart //重启Apache服务器
修改配置文件:
/opt/zbox/app/zentao/config
然后再里面找到my.php,用vi命令去操作修改:
$config->db->port
密码修改:
https://www.cnblogs.com/oukunqing/p/7278575.html
mysql -h127.0.0.1 -P8090 -uroot -p
禅道新密码
use mysql;
mysql -h127.0.0.1 -P3307 -uroot -p
update user set password = password('禅道新密码') where user = 'root';
alter user 'root'@'localhost' identified by '禅道新密码';
alter user 'root'@'localhost' identified by '禅道新密码';
SET password for 'root'@'localhost'=password('禅道新密码');
flush privileges;
安装完成正常启动之后,可使用navicat连接操作禅道数据库对数据删改,端口安全直连可能有问题先用SSH通道连接上服务器,再连接禅道数据库,开源版本库名zentao
2、修改代码
2.1、拷贝代码放入git
因为整改zentao目录包含其他服务文件整体较大,一般满足需求的话只需要将module文件夹下的代码拷贝出来放入git修改,每次改后覆盖相应文件夹到服务器对应路径即可,要是有部分代码不生效可使用/opt/zbox/zbox restart 命令重启刷新。
2.2、目录结构
修改前可以先了解下代码目录,官方文档:
https://www.zentao.net/book/zentaopmshelp/225.html
主要修改的就是module目录,module目录下面总共有30多个模块,分别对应了禅道里面的某一个功能模块。整个禅道的功能,就是由这些模块组合而成。
- lang目录下面存放的当前模块的语言文件。zh-cn对应中文简体,zh-tw中文繁体,依次类推。如果需要修改禅道里面某些字段的名称或者配置,则需要打开相应的文件进行修改。
- view目录下面存放了每一个页面所对应的模板文件。比如bug浏览页面,对应的模板就是browse.html.php。
- config.php存放了当前模块相应的配置项。
- control.php则是整个bug模块所有页面的入口。也就是说,bug相关的页面浏览都可以在这个文件里面找到相应的方法定义。
- model.php则是bug相关数据库操作的方法列表。
2.3、修改入口
每个要修改的页面都可以通过浏览器请求地址找到对应入口,比如产品–计划(productplan-browse-1-0-all.html)就可以在productplan目录下的control.php文件找到browse方法,查看页面数据的来源
2.4、新建、编辑、查询
就从这个列表改起,view目录下有对应browse.html.php文件,就是计划的页面,比如这个th标签中的type就是列表中新增的发布状态(至于为啥是type单纯就是懒库里表加上字段后懒得改了)字段,
对应的简体中文zh-cn文件中也要添加对应字段,正常显示标题
在列表中添加完成之后,对应的新建、编辑页面也在view文件夹下对应文件名create.html.php、edit.html.php,以下是修改对应文件位置的截图、及部分代码的理解注释。
<tr>
// zh-cn.php中的type字段,对应加载出发布状态的中文名字
<th><?php echo $lang->productplan->type;?></th>
<td>
// 我去这行应是我从bug模块复制出来的,应该没啥用忘记删了..忽略
<span class='input-group-addon fix-border'><?php echo $lang->bug->type?></span>
// 这个就是下拉框中的内容了,需要在zh-cn.php中添加个配置内容,$plan->type返回值 保证编辑的时候还是当前这条数据的值
<?php echo html::select('type', $lang->productplan->pubList, $plan->type, "class='form-control'");?>
</td>
</tr>
2.5、标签页切换查询
在block模块中有写好的全部,及遍历未过期、已过期状态,所以只需要加$lang->productplan->featureBar[‘browse’]中加上所需要的,已发布、未发布状态,就能正常显示
但是出来后点击没有效果,还是原来的数据,并不会按状态过滤,观察请求最后一个参数即为刚添加的状态
所以顺着请求找到control,发现$browseType类型参数传到了getList方法中
然后在model.php文件中顺利找到getList,这个文件就与java中的xml相似,可以拼接修改sql,组成想要的结果
2.6、批量编辑
选择单条数据后,会出现批量编辑的按钮不用逐条修改数据,所以在批量编辑页面也加上这个状态
可以通过访问地址找到view中对应的文件,在对应位置复制编辑页的代码,[$plan->id] 这个参数一定要加上,因为参数格式后都带有id不然批量修改找不到对应数据
页面参数一致后,发现并没有生效,于是又通过control找到model发现批量更新需要重新给参数复制,加上后批量编辑成功。
2.7、添加菜单
因为之前新写了一个bug统计,只用其他服务生成的页面,并没有添加的禅道中,于是看到这边可以添加菜单尝试了一下
菜单修改文档:https://www.zentao.net/book/zentaopmshelp/40.html#0,暂时添加了一下,可以新窗口访问,权限页面日后续优化,bug统计sql在下文中。
假设我们要在禅道顶级菜单挂一个新浪的网址,并且要在新窗口打开这个网址。
1、在module/common/ext/view下新建文件footer.sina.html.hook.php
2、加入如下内容保存后,打开禅道即可看到顶级菜单出现新增的链接,并且是在新窗口打开的:
<script>
$(document).ready(function()
{
$("#navbar ul.nav").append('<li><a id="menusina" href="http://www.sina.com.cn" target="_blank">bug统计</ a><\/li>');
});
</script>
2.8、大部分页面创建默认值
创建bug页面默认值 bug类型
大部分都在都在创建接口 Init vars 下
2.9、创建页面判空、权限提醒
//判空
empty($plan->version)
//字符串比较
hash_equals("published",$plan->type)
//打印显示异常
sprintf($this->lang->productplan->errorNoVersionOne, $this->lang->productplan->version);
//权限
!($this->app->user->role == '' or $this->app->user->role == 'qa' or $this->app->user->role == 'qd')
2.10、抄送功能 发送邮件
// 抄送下拉框 放到创建(编辑)或者想要的页面的位置
// $users 为下拉用户数据
<tr>
<th><?php echo $lang->productplan->lblMailto;?></th>
<td>
<div class='input-group' id='contactListGroup'>
<?php
echo html::select('mailto[]', $users, str_replace(' ', '', $mailto), "class='form-control chosen' multiple");
echo $this->fetch('my', 'buildContactLists');
?>
</div>
</td>
</tr>
// 创建(编辑)接口一定要添加默认值 下拉选取用户才有数据
//抄送用户
$this->view->users = $this->loadModel('user')->getPairs('noletter');
//抄送用户 字段
$this->view->mailto = $plan->mailto;
// 一般会请求两次新建(编辑)接口 第一遍访问页面 会加载默认值 第二遍就是保存了
// 保存带数据的请求 都是post 所以这里有判断 邮件的方法(其他要保存触发的同理)也放进去调用下
if(!empty($_POST))
/**
* 计划邮件
* 邮件发送 正常应该有别的方式 如果用户多会慢 没有速度要求的话直接用也没关系
* @param $planID
* @param string $createFlag 1|0
*/
public function sendmailPlan($planID, $createFlag)
{
$plan = $this->productplan->getByID($planID);
/* 设置发送人和抄送人. */
$toList = $plan->mailto;
$ccList = '';
/* 设置邮件标题和正文. */
$plan = $this->productplan->getByID($planID);
$this->commonAction($plan->product, $plan->branch);
$createString = hash_equals($createFlag ,'1')?'创建':'变更';
$mailTitle = '禅道计划信息变更通知 '.$this->app->user->account.$createString.'计划:'.$plan->title;
//状态
$typeName = '状态 判断一下。。。。';
//会根据上面的参数拼接地址、状态、、、、的数据
$mailContent = '邮件里的内容 balblalblababablab 会根据上面的参数拼接一下的';
// 字符串拼接都是用 ''.$mailContent.''
$bodyString = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>禅道计划信息变更通知</title><style> th {padding: 0 12px;text-align: center;} table {border-spacing: 10px;}</style></head><body><table border="1" style="text-align: center; border-collapse: collapse; word-break: break-word;">'.$mailContent.'</table></body></html>';
// 发送 系统中主要的邮件方法 调用这个就好了
$this->loadModel('mail')->send($toList, $mailTitle, $bodyString, $ccList,true);
}
2.11、获取当前页面地址 选取项目跳转地址修改
// 要修改的模块菜单接口
/**
*
* Set menu.
*
* @param array $products
* @param int $productID
* @param int $branch
* @param int $module
* @param string $moduleType
* @param string $extra
*
* @access public
* @return void
*/
public function setMenu($products, $productID, $branch = 0, $module = 0, $moduleType = '', $extra = '')
{
/* Has access privilege?. */
if($products and !isset($products[$productID]) and !$this->checkPriv($productID)) $this->accessDenied();
$currentModule = $this->app->getModuleName();
$currentMethod = $this->app->getMethodName();
/* init currentModule and currentMethod for report and story. */
if($currentModule == 'story')
{
if($currentMethod != 'create' and $currentMethod != 'batchcreate') $currentModule = 'product';
if($currentMethod == 'view' || $currentMethod == 'change' || $currentMethod == 'review') $currentMethod = 'browse';
}
// 初始化项目主页 左上角搜索跳转为计划 不太好确定参数 直接使用当前页面地址判断
$uri = $this->app->getURI(true);
if($uri == '/zentao/product-index-no.html')
{
// 模块名称 productplan
if($currentMethod != 'create' and $currentMethod != 'batchcreate') $currentModule = 'productplan';
if($currentMethod == 'view' || $currentMethod == 'change' || $currentMethod == 'review') $currentMethod = 'browse';
}
......
}
2.12、获取模块负责人 新建默认值
/**
* AJAX: Get bug owner of a module.
*
* @param int $moduleID
* @param int $productID
* @access public
* @return string
*/
public function ajaxGetModuleOwner($moduleID, $productID = 0)
{
//指派 默认获取模块负责人
// $account = $this->bug->getModuleOwner($moduleID, $productID);
// $realName = '';
// if(!empty($account))
// {
// $user = $this->dao->select('realname')->from(TABLE_USER)->where('account')->eq($account)->fetch();
// $firstLetter = ucfirst(substr($account, 0, 1)) . ':';
// if(!empty($this->config->isINT)) $firstLetter = '';
// $realName = $firstLetter . ($user->realname ? $user->realname : $account);
// }
// die(json_encode(array($account, $realName)));
//不默认 模块负责人 返回空
die(json_encode(array()));
}
3、禅道日志
zentao/config/my.php 中debug的值改成true 重新操作一下 看日志文件(zentao/tmp/log/php开头的今天的文件)有什么报错。
三、禅道sql
1、指定时间段统计bug
-- openedDate创建时间
-- resolvedDate解决时间
-- active 激活
-- resolved 已解决
-- closed 已关闭
select tmp.* from(
select zpd.id,zpd.name as '项目名称','' as '空格',
-- 可以根据创建时间统计,如XX一XX创建时间内的问题数量
(
SELECT count(*) FROM `zt_bug` where 1=1
and openedDate>='2021-10-25 00:00:0'
and openedDate<='2021-11-01 00:00:0'
and deleted='0'
and zpd.id=product
) as '新增',
-- 统计XX创建时间内属于bug的个数
-- 代码错误&设计缺陷&生产事故&需求缺漏
(
SELECT count(*) FROM `zt_bug` where 1=1
and openedDate>='2021-10-25 00:00:0'
and openedDate<='2021-11-01 00:00:0'
and deleted='0'
and type in ('codeerror','designdefect','accident','demand')
and zpd.id=product
) as 'bug数',
-- -- 统计XX创建时间内状态是激活的bug数
(
SELECT count(*) FROM `zt_bug` where 1=1
and openedDate>='2021-10-25 00:00:0'
and openedDate<='2021-11-01 00:00:0'
and `status`='active'
and deleted='0'
and zpd.id=product
) as '其中未解决',
-- -- 统计所有激活状态的问题数
(
SELECT count(*) FROM `zt_bug` where 1=1
and `status`='active'
and deleted='0'
and zpd.id=product
) as '所有未解决',
-- -- 统计xx创建时间内状态不等于关闭的bug数
(
SELECT count(*) FROM `zt_bug` where 1=1
and `status`='resolved'
and zpd.id=product
and deleted='0'
) as '已解决待关闭',
-- -- 按照解决时间统计,如解决日期是xX一xX区间的
(
SELECT count(*) FROM `zt_bug` where 1=1
and resolvedDate>='2021-10-25 00:00:0'
and resolvedDate<='2021-11-01 00:00:0'
and zpd.id=product
and deleted='0'
) as '本周解决'
from zt_bug as zb
left join zt_project as zp on zp.id=zb.product
left join zt_product as zpd on zpd.id=zb.product
GROUP BY zb.product
) as tmp
where tmp.新增!=0
2、按周统计项目bug
-- openedDate创建时间
-- resolvedDate解决时间
-- active 激活
-- resolved 已解决
-- closed 已关闭
select
str_to_date(concat(tmp.weeks, " ", 'Monday'), '%X%V %W') as fristWeek,str_to_date(concat(tmp.weeks+1, " ", 'Sunday'), '%X%V %W') as endWeek
,tmp.* from(
select DATE_FORMAT(zb.openedDate,'%Y%u') weeks,zpd.id,zpd.name as '项目名称','' as '空格',
-- 可以根据创建时间统计,如XX一XX创建时间内的问题数量
(
SELECT count(*) FROM `zt_bug` where 1=1
and openedDate>=concat(str_to_date(concat(weeks, " ", 'Monday'), '%X%V %W'),' ','00:00:0')
and openedDate<=concat(str_to_date(concat(weeks+1, " ", 'Sunday'), '%X%V %W'),' ','23:59:59')
and DATE_FORMAT(openedDate,'%Y%u') =weeks
and deleted='0'
and zpd.id=product
) as '新增',
-- 统计XX创建时间内属于bug的个数
-- 代码错误&设计缺陷&生产事故&需求缺漏
(
SELECT count(*) FROM `zt_bug` where 1=1
and openedDate>=concat(str_to_date(concat(weeks, " ", 'Monday'), '%X%V %W'),' ','00:00:0')
and openedDate<=concat(str_to_date(concat(weeks+1, " ", 'Sunday'), '%X%V %W'),' ','23:59:59')
and DATE_FORMAT(openedDate,'%Y%u') =weeks
and deleted='0'
and type in ('codeerror','designdefect','accident','demand')
and zpd.id=product
) as 'bug数',
-- -- 统计XX创建时间内状态是激活的bug数
(
SELECT count(*) FROM `zt_bug` where 1=1
and openedDate>=concat(str_to_date(concat(weeks, " ", 'Monday'), '%X%V %W'),' ','00:00:0')
and openedDate<=concat(str_to_date(concat(weeks+1, " ", 'Sunday'), '%X%V %W'),' ','23:59:59')
and DATE_FORMAT(openedDate,'%Y%u') =weeks
and `status`='active'
and deleted='0'
and zpd.id=product
) as '其中未解决',
-- -- 统计所有激活状态的问题数
(
SELECT count(*) FROM `zt_bug` where 1=1
and `status`='active'
and deleted='0'
-- and DATE_FORMAT(openedDate,'%Y%u') =weeks
and zpd.id=product
) as '所有未解决',
-- -- 统计xx创建时间内状态不等于关闭的bug数
(
SELECT count(*) FROM `zt_bug` where 1=1
and `status`='resolved'
and zpd.id=product
-- and DATE_FORMAT(openedDate,'%Y%u') =weeks
and deleted='0'
) as '已解决待关闭',
-- -- 按照解决时间统计,如解决日期是xX一xX区间的
(
SELECT count(*) FROM `zt_bug` where 1=1
and resolvedDate>=concat(str_to_date(concat(weeks, " ", 'Monday'), '%X%V %W'),' ','00:00:0')
and resolvedDate<=concat(str_to_date(concat(weeks+1, " ", 'Sunday'), '%X%V %W'),' ','23:59:59')
-- and DATE_FORMAT(resolvedDate,'%Y%u') =weeksR
and zpd.id=product
and deleted='0'
) as '本周解决'
from zt_bug as zb
left join zt_project as zp on zp.id=zb.product
left join zt_product as zpd on zpd.id=zb.product
GROUP BY zb.product,weeks
) as tmp
where tmp.新增!=0
3、常用表
-- 项目表
select * from zt_product order by id desc limit 100;
-- bug表
select * from zt_bug order by id desc limit 100;
-- 动态记录表、要是有调试记录可以删删mysql
select * from zt_action order by id desc limit 100;
以上就是禅道修改的一些记录理解,会持续更新欢迎指点~
更多推荐
所有评论(0)