近期要对禅道做一些修改,安装了一堆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安装使用。

image-20211226192540211

image-20211226192257132

image-20211226192335699

2、编辑器(PhpStorm2020.3_129854)

与idea类似,PhpStorm2020.3_129854.rar下载解压后可按说明激活、安装汉化包

百度网盘链接:https://pan.baidu.com/s/10Xe6JtXQ1uUtAJm8KaHzHg
提取码:2v15

image-20211226193538107

二、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

image-20211226195515984

image-20211226195702093

2、修改代码

2.1、拷贝代码放入git

因为整改zentao目录包含其他服务文件整体较大,一般满足需求的话只需要将module文件夹下的代码拷贝出来放入git修改,每次改后覆盖相应文件夹到服务器对应路径即可,要是有部分代码不生效可使用/opt/zbox/zbox restart 命令重启刷新。

image-20211226200013199

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方法,查看页面数据的来源

image-20211226200647113

image-20211226201047453

2.4、新建、编辑、查询

就从这个列表改起,view目录下有对应browse.html.php文件,就是计划的页面,比如这个th标签中的type就是列表中新增的发布状态(至于为啥是type单纯就是懒库里表加上字段后懒得改了)字段,

image-20211226201311209

对应的简体中文zh-cn文件中也要添加对应字段,正常显示标题

image-20211226201643215

在列表中添加完成之后,对应的新建、编辑页面也在view文件夹下对应文件名create.html.php、edit.html.php,以下是修改对应文件位置的截图、及部分代码的理解注释。

image-20211226201812896

image-20211226202206176

image-20211226202305180

<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’]中加上所需要的,已发布、未发布状态,就能正常显示

image-20211226203203925

image-20211226203527278

但是出来后点击没有效果,还是原来的数据,并不会按状态过滤,观察请求最后一个参数即为刚添加的状态

image-20211226203622749

所以顺着请求找到control,发现$browseType类型参数传到了getList方法中

image-20211226203826637

然后在model.php文件中顺利找到getList,这个文件就与java中的xml相似,可以拼接修改sql,组成想要的结果

image-20211226204254036

2.6、批量编辑

选择单条数据后,会出现批量编辑的按钮不用逐条修改数据,所以在批量编辑页面也加上这个状态

image-20211226204349766

image-20211226204730621

可以通过访问地址找到view中对应的文件,在对应位置复制编辑页的代码,[$plan->id] 这个参数一定要加上,因为参数格式后都带有id不然批量修改找不到对应数据

image-20211226204853821

image-20211226205224300

页面参数一致后,发现并没有生效,于是又通过control找到model发现批量更新需要重新给参数复制,加上后批量编辑成功。

image-20211226205336653

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>

image-20211226210431243

image-20211226210612415

2.8、大部分页面创建默认值

创建bug页面默认值 bug类型

image-20220510185049823

image-20220510185107009

大部分都在都在创建接口 Init vars 下

image-20220510185126317

2.9、创建页面判空、权限提醒

image-20220510185457995

//判空 
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')

image-20220510185637542

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>

image-20220511092957710

// 创建(编辑)接口一定要添加默认值   下拉选取用户才有数据

//抄送用户
$this->view->users       = $this->loadModel('user')->getPairs('noletter');
//抄送用户 字段
$this->view->mailto      = $plan->mailto;

image-20220511093748655

// 一般会请求两次新建(编辑)接口   第一遍访问页面 会加载默认值     第二遍就是保存了
// 保存带数据的请求  都是post 所以这里有判断   邮件的方法(其他要保存触发的同理)也放进去调用下
if(!empty($_POST))

image-20220511094022150

/**
     * 计划邮件
     * 邮件发送   正常应该有别的方式  如果用户多会慢 没有速度要求的话直接用也没关系
     * @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、获取当前页面地址 选取项目跳转地址修改

image-20220511095630555

// 要修改的模块菜单接口
/**
     *
     * 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;

以上就是禅道修改的一些记录理解,会持续更新欢迎指点~

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐