一、为什么要给禅道加自定义业务字段

咱们平时用禅道做项目管理时,大概率都碰到过这种情况:比如团队做电商项目,开发任务里有个对接第三方支付接口的活,要是出问题可能导致用户资金出错,风险很高,但禅道内置的字段只有优先级、预计工时这些通用项,根本没法精准区分“风险等级”;还有统计开发工作量时,内置的“预计工时”和“实际工时”没法按业务模块拆分,想统计支付模块的总工作量得手动翻所有任务,特别费时间。

更头疼的是列表检索,比如想找所有“高风险+支付模块”的任务,内置的筛选条件根本没这些选项,只能一个个点进去看描述,上次我们团队评审项目风险,就花了12分钟才找全5个高风险的核心任务,要是项目再大些,这时间根本耗不起。所以,给禅道加业务专属的自定义字段,顺便解决列表检索和展示的问题,就成了刚需。

二、禅道扩展自定义字段的具体实现

禅道本身有官方的扩展机制,不用改核心代码,后续升级也不会覆盖我们的修改,这是最稳妥的方式。咱们用PHP技术栈来做,因为禅道核心也是PHP写的,扩展文件放在custom目录就行。

2.1 找到禅道扩展的正确位置

禅道的扩展代码统一放在你的禅道目录/custom/里,比如要扩展任务模块(就是开发任务那块),就对应找custom/module/task/,模型文件放在custom/module/model/,视图文件放在custom/module/view/,别碰禅道自带的module/目录,这个是核心,改了容易出问题还丢代码。

2.2 新增业务专属字段的代码实现

咱们以加“风险等级”字段为例,这个字段的取值是低、中、高、极高,用来标记任务的风险程度。直接新建custom/module/model/task.php,代码如下:

<?php
// 扩展禅道的任务模型,新增风险等级字段
class model_task extends model
{
    // 重写获取任务列表的方法,给每个任务附上风险等级
    public function getList($query = '')
    {
        // 先调用禅道原生方法获取任务原始数据
        $tasks = parent::getList($query);
        
        // 遍历每个任务,按业务规则判断风险等级(这里用任务描述里的关键词简单演示,实际可以对接业务数据库)
        foreach ($tasks as $task) {
            // 如果任务描述里有“高风险”“核心支付”这类词,就标记极高风险
            if (strpos($task->desc, '高风险') !== false || strpos($task->name, '支付') !== false) {
                $task->risk_level = '极高';
            } elseif (strpos($task->desc, '中风险') !== false) {
                $task->risk_level = '中';
            } else {
                $task->risk_level = '低';
            }
        }
        
        return $tasks;
    }

    // 重写保存任务的方法,让风险等级能存入数据库
    public function save($task)
    {
        // 如果提交了风险等级,就加入要保存的字段
        if (isset($task->risk_level) && in_array($task->risk_level, ['低', '中', '高', '极高'])) {
            $task->fields['risk_level'] = $task->risk_level;
        }
        // 调用原生方法保存
        return parent::save($task);
    }
}
?>

这段代码的核心是“重写父类方法”,不修改原来的代码,只加自己的逻辑,后续禅道升级时,只要扩展文件还在custom目录就会生效。

2.3 列表页展示自定义字段的修改

要让风险等级在任务列表里显示,得改视图文件,新建custom/module/view/task/browse.html.php,代码如下:

<?php include '../../common/view/header.html.php';?>
<!-- 这里是扩展的任务列表页面,加入风险等级列 -->
<div id="mainContent" class="main-content fade">
  <div class="main-table">
    <table class="table table-bordered table-striped table-hover">
      <thead>
        <tr>
          <th class="w-60">ID</th>
          <th>任务名称</th>
          <!-- 新增风险等级列,用颜色区分更直观 -->
          <th class="w-100">风险等级</th>
          <th>负责人</th>
          <th>预计工时</th>
        </tr>
      </thead>
      <tbody>
        <?php foreach($tasks as $task):?>
        <tr>
          <td><?php echo $task->id;?></td>
          <td><?php echo $task->name;?></td>
          <!-- 风险等级显示,极高用红色,中用橙色,低用绿色 -->
          <td style="font-weight: bold; color: <?php echo $task->risk_level == '极高' ? 'red' : ($task->risk_level == '中' ? '#FF9900' : 'green');?>">
            <?php echo $task->risk_level;?>
          </td>
          <td><?php echo $task->assignedTo;?></td>
          <td><?php echo $task->estimate;?></td>
        </tr>
        <?php endforeach;?>
      </tbody>
    </table>
  </div>
</div>
<?php include '../../common/view/footer.html.php';?>

这样改完后,打开任务列表就能看到风险等级了,颜色区分也方便快速识别高风险任务。

三、解决列表检索的落地问题

光展示不行,还得能按风险等级筛选,比如想找所有极高风险的任务,得给列表加检索条件。

3.1 新增检索条件的代码扩展

同样在刚才的custom/module/model/task.php里,重写检索方法,代码如下:

<?php
// 接上面的模型代码,继续加检索方法
public function getSearchQuery()
{
    // 先调用原生方法获取原有查询条件
    $query = parent::getSearchQuery();
    
    // 新增风险等级的检索条件,防止SQL注入用quote过滤
    if (isset($_GET['risk_level']) && $_GET['risk_level'] != '') {
        $risk_level = $this->db->quote($_GET['risk_level']);
        $query .= " AND risk_level = $risk_level";
    }
    
    return $query;
}
?>

改完后,在列表页面的顶部加个风险等级的下拉筛选框,用户选了就会自动筛选出对应等级的任务,不用手动翻页。

四、实际应用场景

我之前所在的生鲜电商团队,用这个方法扩展后,解决了两个核心问题:一是风险管控,之前找高风险任务要10分钟,现在点一下下拉选“极高”,1秒就出来;二是工作量统计,后来又加了“业务模块”字段,把任务拆分到支付、物流、用户等模块,统计支付模块的总工作量不用再手动统计,直接选模块就能看到所有任务的工时总和,每月做成本核算省了不少时间。 还有次对接冷链API的任务,因为标记了极高风险,测试团队提前做了3轮针对API异常的测试,最后上线时没出问题,要是没这个字段,很可能漏测这个核心风险点。

五、技术优缺点分析

优点

  1. 不碰核心代码,升级禅道不怕覆盖,安全稳定;
  2. 完全贴合业务,想要什么字段就加什么,不用凑合用通用字段;
  3. 检索和展示都能自定义,灵活度高,解决实际痛点;
  4. 扩展代码独立,后续维护方便,加新字段只要改对应文件就行。

缺点

  1. 需要一点开发基础,不能像后台配置那样点点完成;
  2. 要是扩展的模块多,代码量会增加,维护要细心;
  3. 字段类型的扩展要注意数据库的同步,忘了加字段会报错。

六、落地注意事项

  1. 数据库要同步改:加自定义字段前,得给对应的表(比如task表)加字段,类型选varchar足够存中文,比如risk_level设为varchar(10);
  2. 扩展文件要放在custom目录:千万别改禅道自带的module文件,不然升级后扩展就没了,后果严重;
  3. 检索条件要安全:用db->quote过滤用户输入,防止SQL注入,这个很重要,别漏;
  4. 测试要覆盖全面:扩展后要测任务的增删改查、列表加载、检索,别影响原有功能,比如会不会导致任务编辑时风险等级没保存。

七、总结

禅道内置字段是通用型的,没法覆盖每个团队的个性化业务需求,通过它的扩展机制加自定义字段,再解决列表检索和展示的问题,是个低风险、高收益的方案。不管是开发工作量的精准统计,还是项目风险的提前管控,都能通过这个方法落地,特别适合有个性化管理需求的团队,能大幅提升项目管理的效率,减少项目风险。