Merge branch 'main' of https://gitfox.zcorp.cc/git/zentao/zentaopms into main
This commit is contained in:
+10
-1
@@ -14547,7 +14547,16 @@ REPLACE INTO `zt_approvalflowspec` (`id`, `flow`, `version`, `nodes`, `createdBy
|
||||
REPLACE INTO `zt_lang` (`lang`, `module`, `section`, `key`, `value`, `system`) VALUES
|
||||
('all', 'process', 'classify', 'support', '支持过程', '1'),
|
||||
('all', 'process', 'classify', 'engineering', '工程支持', '1'),
|
||||
('all', 'process', 'classify', 'project', '项目管理', '1');
|
||||
('all', 'process', 'classify', 'project', '项目管理', '1'),
|
||||
('all', 'process', 'scrumClassify', 'support', '支持过程', '1'),
|
||||
('all', 'process', 'scrumClassify', 'engineering', '工程支持', '1'),
|
||||
('all', 'process', 'scrumClassify', 'project', '项目管理', '1'),
|
||||
('all', 'process', 'agileplusClassify', 'support', '支持过程', '1'),
|
||||
('all', 'process', 'agileplusClassify', 'engineering', '工程支持', '1'),
|
||||
('all', 'process', 'agileplusClassify', 'project', '项目管理', '1'),
|
||||
('all', 'process', 'waterfallplusClassify', 'support', '支持过程', '1'),
|
||||
('all', 'process', 'waterfallplusClassify', 'engineering', '工程支持', '1'),
|
||||
('all', 'process', 'waterfallplusClassify', 'project', '项目管理', '1');
|
||||
|
||||
REPLACE INTO `zt_process` (`id`, `model`, `name`, `type`, `abbr`, `desc`, `assignedTo`, `status`, `order`, `createdBy`, `createdDate`, `editedBy`, `editedDate`, `assignedBy`, `assignedDate`, `deleted`) VALUES
|
||||
(11, 'waterfall', '立项管理', 'project', 'PIM', '', '', '', 55, 'admin', '2020-01-09 10:29:55', '', '1970-01-01 00:00:01', '', '1970-01-01 00:00:01', '0'),
|
||||
|
||||
@@ -135,7 +135,7 @@ class form extends fixer
|
||||
}
|
||||
else
|
||||
{
|
||||
$configObject[$field->field] = array('required' => $required, 'type' => 'string');
|
||||
$configObject[$field->field] = array('required' => $required, 'type' => 'string', 'default' => '');
|
||||
if($field->control == 'richtext') $configObject[$field->field]['control'] = 'editor';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,3 +35,4 @@ $config->index->oldPages[] = 'ai-promptview';
|
||||
$config->index->oldPages[] = 'api-debug';
|
||||
$config->index->oldPages[] = 'datatable-ajaxoldcustom';
|
||||
$config->index->oldPages[] = 'weekly-index';
|
||||
$config->index->oldPages[] = 'kanban-importticket';
|
||||
|
||||
@@ -381,6 +381,8 @@ class kanban extends control
|
||||
$regionID = !isset($regions[$regionID]) ? 'all' : $regionID;
|
||||
$this->session->set('regionID', $regionID, 'kanban');
|
||||
|
||||
$this->kanbanZen->setUserAvatar();
|
||||
|
||||
$this->view->title = $this->lang->kanban->view;
|
||||
$this->view->kanban = $kanban;
|
||||
$this->view->regions = $regions;
|
||||
|
||||
@@ -114,7 +114,7 @@ window.buildColCardActions = function(col)
|
||||
if(kanban.object.indexOf('releases') != -1) items.push({text: kanbanLang.importRelease, url: $.createLink('kanban', 'importRelease', `kanbanID=${kanbanID}®ionID=${col.region}&groupID=${col.group}&columnID=${col.id}`), 'data-toggle': 'modal', 'data-size': 'lg'});
|
||||
if(kanban.object.indexOf('executions') != -1) items.push({text: kanbanLang.importExecution, url: $.createLink('kanban', 'importExecution', `kanbanID=${kanbanID}®ionID=${col.region}&groupID=${col.group}&columnID=${col.id}`), 'data-toggle': 'modal', 'data-size': 'lg'});
|
||||
if(kanban.object.indexOf('builds') != -1) items.push({text: kanbanLang.importBuild, url: $.createLink('kanban', 'importBuild', `kanbanID=${kanbanID}®ionID=${col.region}&groupID=${col.group}&columnID=${col.id}`), 'data-toggle': 'modal', 'data-size': 'lg'});
|
||||
//{text: kanbanLang.importTicket, url: $.createLink('kanban', 'importTicket', `kanbanID=${kanbanID}®ionID=${col.region}&groupID=${col.group}&columnID=${col.id}`), 'data-toggle': 'modal', 'data-size': 'lg'},
|
||||
if(kanban.object.indexOf('tickets') != -1) items.push({text: kanbanLang.importTicket, url: $.createLink('kanban', 'importTicket', `kanbanID=${kanbanID}®ionID=${col.region}&groupID=${col.group}&columnID=${col.id}`), 'data-toggle': 'modal', 'data-type': 'iframe'}),
|
||||
actions.push(
|
||||
{
|
||||
text: kanbanLang.importAB,
|
||||
@@ -301,8 +301,41 @@ window.renderProductplanItem = function(info)
|
||||
info.item.contentClass = 'text-gray clip mr-2';
|
||||
info.item.footer = {html: statusBox + date}
|
||||
}
|
||||
|
||||
window.renderTicketItem = function(info)
|
||||
{
|
||||
info.item.icon = 'ticket';
|
||||
info.item.titleUrl = canViewTicket ? $.createLink('ticket', 'view', `id=${info.item.fromID}`) : '';
|
||||
info.item.titleAttrs = {'class': 'card-title clip', 'title': info.item.title};
|
||||
|
||||
if(info.item.deleted == '0')
|
||||
{
|
||||
statusBox = '<span class="label label-' + info.item.objectStatus + '">' + ticketLang.statusList[info.item.objectStatus] + '</span>';
|
||||
}
|
||||
else
|
||||
{
|
||||
statusBox = '<span class="label label-deleted">' + ticketLang.deleted + '</span>';
|
||||
}
|
||||
|
||||
const date = info.item.deadline && info.item.deadline != '0000-00-00' ? '<span class="ml-2 label gray-pale">' + info.item.deadline.slice(5) + ' ' + cardLang.deadlineAB + '</span>' : '';
|
||||
|
||||
let avatar = '';
|
||||
if(info.item.assignedTo && typeof userList[info.item.assignedTo] != 'undefined')
|
||||
{
|
||||
const user = userList[info.item.assignedTo];
|
||||
const assignedTo = user.realname;
|
||||
const userAvatar = user.avatar ? "<img src='" + user.avatar + "' />" : info.item.assignedTo.substr(0, 1).toUpperCase();
|
||||
|
||||
avatar = "<span class='avatar rounded-full size-xs ml-1 primary' title=" + assignedTo + '>' + userAvatar + '</span>';
|
||||
}
|
||||
const content = `
|
||||
<div class='flex items-center'>
|
||||
${statusBox}
|
||||
${date}
|
||||
<div class='flex-1 flex justify-end'>${avatar}</div>
|
||||
</div>
|
||||
`;
|
||||
info.item.content = {html: content};
|
||||
}
|
||||
|
||||
function renderAvatar(avatarList)
|
||||
|
||||
@@ -63,6 +63,7 @@ jsVar('cardLang', $lang->kanbancard);
|
||||
jsVar('executionLang', $lang->execution);
|
||||
jsVar('releaseLang', $lang->release);
|
||||
jsVar('productplanLang', $lang->productplan);
|
||||
jsVar('ticketLang', isset($lang->ticket) ? $lang->ticket : '');
|
||||
jsVar('kanbanID', $kanban->id);
|
||||
jsVar('kanban', $kanban);
|
||||
jsVar('groupCols', $groupCols);
|
||||
@@ -74,6 +75,8 @@ jsVar('canViewPlan', common::hasPriv('productplan', 'view') && $config->vision !
|
||||
jsVar('canViewRelease', common::hasPriv('release', 'view') && $config->vision != 'lite');
|
||||
jsVar('canViewExecution', common::hasPriv('execution', 'task') && $config->vision != 'lite');
|
||||
jsVar('canViewBuild', common::hasPriv('build', 'view') && $config->vision != 'lite');
|
||||
jsVar('canViewTicket', common::hasPriv('ticket', 'view'));
|
||||
jsVar('userList', $userList);
|
||||
|
||||
dropmenu(set::tab('kanban'), set::objectID($kanban->id));
|
||||
|
||||
|
||||
@@ -61,4 +61,30 @@ class kanbanZen extends kanban
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置用户头像。
|
||||
* Set user avatar data.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function setUserAvatar(): void
|
||||
{
|
||||
/* Get user list. */
|
||||
$userList = array();
|
||||
$users = $this->loadModel('user')->getPairs('noletter|nodeleted');
|
||||
$avatarPairs = $this->user->getAvatarPairs('all');
|
||||
foreach($avatarPairs as $account => $avatar)
|
||||
{
|
||||
if(!isset($users[$account])) continue;
|
||||
$userList[$account]['realname'] = $users[$account];
|
||||
$userList[$account]['avatar'] = $avatar;
|
||||
}
|
||||
$userList['closed']['account'] = 'Closed';
|
||||
$userList['closed']['realname'] = 'Closed';
|
||||
$userList['closed']['avatar'] = '';
|
||||
|
||||
$this->view->userList = $userList;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1324,7 +1324,8 @@ class storyModel extends model
|
||||
}
|
||||
|
||||
$story->reviewer = implode(',', $story->reviewer);
|
||||
if($story->reviewer) $story->status = ($this->config->systemMode == 'PLM' and $oldStory->type == 'requirement' and $story->status == 'active' and $this->config->vision == 'rnd') ? 'launched' : 'reviewing';
|
||||
if($story->reviewer) $story->status = 'reviewing';
|
||||
if($this->config->systemMode == 'PLM' && $this->config->vision == 'rnd' && $oldStory->type == 'requirement' && $story->status == 'active') $story->status = 'launched';
|
||||
|
||||
$this->dao->update(TABLE_STORY)->data($story, 'reviewer')->where('id')->in($twinsIdList)->exec();
|
||||
|
||||
|
||||
@@ -120,6 +120,7 @@ $fields->field('pri')
|
||||
|
||||
$fields->field('estimate')
|
||||
->width('1/4')
|
||||
->control(array('control' => 'number'))
|
||||
->required($createFields['estimate']['required'])
|
||||
->label($lang->story->estimateAB . $lang->story->estimateUnit)
|
||||
->value($createFields['estimate']['default']);
|
||||
|
||||
@@ -97,6 +97,7 @@ $config->upgrade->execFlow['20_0_alpha1'] = array('functions' => 'revertStoryCus
|
||||
$config->upgrade->execFlow['20_0_beta1'] = array('functions' => 'hideOA,updateMetricDateType,update18101,migrateAIModelConfig');
|
||||
$config->upgrade->execFlow['20_0_beta2'] = array('functions' => 'updateWorkflowFieldDefaultValue,update1811,updateZeroDateToNull,updateProgramplanCustom');
|
||||
$config->upgrade->execFlow['20_0'] = array('functions' => 'openCacheByAPCu');
|
||||
$config->upgrade->execFlow['20_1_0'] = array('functions' => 'completeClassifyLang');
|
||||
|
||||
if(!empty($config->isINT))
|
||||
{
|
||||
|
||||
@@ -8816,4 +8816,46 @@ class upgradeModel extends model
|
||||
{
|
||||
return $this->loadModel('install')->enableDaoCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* 补充分类项语言项。
|
||||
* Complete classify lang.
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function completeClassifyLang()
|
||||
{
|
||||
$this->app->loadLang('install');
|
||||
|
||||
$classifyLang = $this->dao->select('*')->from(TABLE_LANG)
|
||||
->where('lang')->eq('all')
|
||||
->andWhere('module')->eq('process')
|
||||
->andWhere('section')->in(array('scrumClassify', 'agileplusClassify', 'waterfallplusClassify'))
|
||||
->andWhere('`key`')->in(array('support', 'engineering', 'project'))
|
||||
->andWhere('vision')->eq('rnd')
|
||||
->fetchGroup('section', 'key');
|
||||
|
||||
foreach(array('scrum', 'agileplus', 'waterfallplus') as $modal)
|
||||
{
|
||||
foreach($this->lang->install->langList as $langInfo)
|
||||
{
|
||||
if($langInfo['module'] != 'process') continue;
|
||||
if(isset($classifyLang[$modal . 'Classify'][$langInfo['key']])) continue;
|
||||
|
||||
$classifyData = new stdclass();
|
||||
$classifyData->lang = 'all';
|
||||
$classifyData->module = 'process';
|
||||
$classifyData->section = $modal . 'Classify';
|
||||
$classifyData->key = $langInfo['key'];
|
||||
$classifyData->value = $langInfo['value'];
|
||||
$classifyData->vision = 'rnd';
|
||||
$classifyData->system = 1;
|
||||
|
||||
$this->dao->replace(TABLE_LANG)->data($classifyData)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,4 +738,26 @@ class upgradeTest
|
||||
$this->objectModel->revertStoryCustomFields();
|
||||
return $this->objectModel->dao->select('*')->from(TABLE_CONFIG)->where('module')->eq('datatable')->andWhere('section')->eq('productBrowse')->andWhere('key')->eq('cols')->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试补充模型分类项。
|
||||
* Test complete classify lang.
|
||||
*
|
||||
* @param string $section
|
||||
* @param string $key
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function completeClassifyLangTest(string $section, string $key): string
|
||||
{
|
||||
$this->objectModel->completeClassifyLang();
|
||||
return $this->objectModel->dao->select('value')->from(TABLE_LANG)
|
||||
->where('lang')->eq('all')
|
||||
->andWhere('module')->eq('process')
|
||||
->andWhere('section')->eq($section)
|
||||
->andWhere('`key`')->eq($key)
|
||||
->andWhere('system')->eq(1)
|
||||
->andWhere('vision')->eq('rnd')
|
||||
->fetch('value');
|
||||
}
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
|
||||
title=测试 upgradeModel->completeClassifyLang();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
- 检查数据库中已经给融合敏捷模型添加了project分类项 @项目管理
|
||||
- 检查数据库中敏捷模型未添加project分类项 @项目管理
|
||||
- 检查数据库中已经给融合瀑布模型添加了support,engineering,没添加project分类项 @项目管理
|
||||
|
||||
*/
|
||||
|
||||
include dirname(__FILE__, 5) . '/test/lib/init.php';
|
||||
include dirname(__FILE__, 2) . '/lib/upgrade.unittest.class.php';
|
||||
su('admin');
|
||||
|
||||
$langData = zenData('lang')->loadYaml('lang_completeclassifylang')->gen(8);
|
||||
|
||||
global $tester, $app;
|
||||
|
||||
$upgrade = new upgradeTest();
|
||||
|
||||
r($upgrade->completeClassifyLangTest('agileplusClassify', 'project')) && p() && e('项目管理'); // 检查数据库中已经给融合敏捷模型添加了project分类项
|
||||
r($upgrade->completeClassifyLangTest('scrumClassify', 'project')) && p() && e('项目管理'); // 检查数据库中敏捷模型未添加project分类项
|
||||
r($upgrade->completeClassifyLangTest('waterfallplusClassify', 'project')) && p() && e('项目管理'); // 检查数据库中已经给融合瀑布模型添加了support,engineering,没添加project分类项
|
||||
@@ -0,0 +1,26 @@
|
||||
title: table zt_lang
|
||||
desc: "语言项"
|
||||
author: Fangzhou Hu
|
||||
version: "1.0"
|
||||
fields:
|
||||
- field: lang
|
||||
note: "语言"
|
||||
range: all
|
||||
- field: module
|
||||
note: "模块"
|
||||
range: process
|
||||
- field: section
|
||||
note: "板块"
|
||||
range: waterfall{3},agileplusClassify{3},waterfallplusClassify{2}
|
||||
- field: key
|
||||
note: "键"
|
||||
range: support,engineering,project
|
||||
- field: value
|
||||
note: "值"
|
||||
range: 支持过程,工程支持,项目管理
|
||||
- field: system
|
||||
note: "是否系统内置"
|
||||
range: 1
|
||||
- field: vision
|
||||
note: "界面"
|
||||
range: rnd
|
||||
Reference in New Issue
Block a user