Merge branch 'master' of https://git.zcorp.cc/easycorp/zentaopms
This commit is contained in:
Vendored
+1
-1
@@ -37,7 +37,7 @@ pipeline {
|
||||
container('sonar') {
|
||||
withSonarQubeEnv('sonarqube') {
|
||||
sh 'git config --global --add safe.directory $(pwd)'
|
||||
sh 'sonar-scanner -Dsonar.inclusions=$(git diff --name-only HEAD~1|tr "\\n" ",") -Dsonar.analysis.user=$(git show -s --format=%an)'
|
||||
sh 'sonar-scanner -Dsonar.analysis.user=$(git show -s --format=%an)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
ALTER TABLE `zt_block` ADD `dashboard` varchar(20) NOT NULL DEFAULT '' AFTER `account`;
|
||||
UPDATE `zt_block` SET `dashboard` = `module`;
|
||||
UPDATE `zt_block` SET `module` = IF(`source` != '', `source`, `block`);
|
||||
|
||||
ALTER TABLE `zt_todo` CHANGE `idvalue` `objectID` mediumint(8) unsigned default '0' NOT NULL AFTER `type`;
|
||||
|
||||
@@ -283,8 +283,16 @@ $config->block->modules['doc']->moreLinkList->projectdoc = 'doc|projectspac
|
||||
$config->block->form = new stdclass();
|
||||
$config->block->form->create = array();
|
||||
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['block'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
|
||||
$config->block->form->create['hidden'] = array('type' => 'int', 'required' => false, 'default' => '0');
|
||||
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
|
||||
|
||||
$config->block->form = new stdclass();
|
||||
$config->block->form->create = array();
|
||||
$config->block->form->create['module'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['block'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['title'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->block->form->create['grid'] = array('type' => 'int', 'required' => false, 'default' => '4');
|
||||
$config->block->form->create['params'] = array('type' => 'array', 'required' => false, 'default' => array());
|
||||
|
||||
@@ -26,7 +26,7 @@ class block extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a block.
|
||||
* Create a block under a dashboard.
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
@@ -50,9 +50,9 @@ class block extends control
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true, 'callback' => 'loadCurrentPage()'));
|
||||
}
|
||||
|
||||
|
||||
$this->view->title = $this->lang->block->createBlock;
|
||||
$this->view->dashboard = $dashboard;
|
||||
$this->view->module = $module;
|
||||
$this->view->block = $block;
|
||||
$this->view->modules = $this->blockZen->getAvailableModules($dashboard);
|
||||
$this->view->blocks = $this->blockZen->getAvailableBlocks($dashboard, $module);
|
||||
@@ -64,20 +64,34 @@ class block extends control
|
||||
* Update a block.
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param int $blockID
|
||||
* @param string $module
|
||||
* @param string $block
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function edit(string $dashboard, int $blockID)
|
||||
public function edit(string $blockID, string $module = '', string $block = '')
|
||||
{
|
||||
$blockID = (int)$blockID;
|
||||
if($_POST)
|
||||
{
|
||||
$formData = form::use($this->config->example->edit)->get();
|
||||
$formData = form::data($this->config->block->form->edit)->get();
|
||||
$formData->id = $blockID;
|
||||
$formData->params = helper::jsonEncode($formData->params);
|
||||
|
||||
$this->block->update($formData);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => 'reload'));
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => true, 'closeModal' => true, 'callback' => 'loadCurrentPage()'));
|
||||
}
|
||||
$this->blockZen->buildCreateForm($dashboard);
|
||||
|
||||
$blockData = $this->block->getByID($blockID);
|
||||
|
||||
$this->view->title = $this->lang->block->editBlock;
|
||||
$this->view->blockData = $blockData;
|
||||
$this->view->block = $block ? $block : $blockData->block;
|
||||
$this->view->module = $module ? $module : $blockData->module;
|
||||
$this->view->modules = $this->blockZen->getAvailableModules($blockData->dashboard);
|
||||
$this->view->blocks = $this->blockZen->getAvailableBlocks($blockData->dashboard, $this->view->module);
|
||||
$this->view->params = $this->blockZen->getAvailableParams($blockData->dashboard, $this->view->module, $this->view->block);
|
||||
$this->display();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
function getForm(event)
|
||||
{
|
||||
const field = $(event.target).attr('id');
|
||||
const module = $('#module').val();
|
||||
const block = field == 'module' ? '' : $('#block').val();
|
||||
const url = $.createLink('block', 'edit', 'blockID=' + blockID + '&module=' + module + '&block=' + (block ? block : ''));
|
||||
loadPage(url, '#blockRow, #paramsRow');
|
||||
}
|
||||
@@ -187,10 +187,10 @@ class blockModel extends model
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getParams(string $type, string $module): string
|
||||
public function getParams(string $block, string $module): string
|
||||
{
|
||||
$type = $type == 'todo' ? $module : $type;
|
||||
$params = zget($this->config->block->params, $type, '');
|
||||
$block = $block == 'todo' ? $module : $block;
|
||||
$params = zget($this->config->block->params, $block, '');
|
||||
return json_encode($params);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ function initData()
|
||||
|
||||
/**
|
||||
|
||||
title=14:11:23 ERROR: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry &
|
||||
title=测试 block 模块 model下的 create 方法
|
||||
timeout=0
|
||||
cid=39
|
||||
|
||||
|
||||
@@ -18,4 +18,4 @@ global $config;
|
||||
$block = new blockTest();
|
||||
$data = $block->getClosedBlockPairsTest('');
|
||||
|
||||
r($data) && p('massage') && e('未获取到关闭的区域'); //测试获取关闭的区块键值对
|
||||
r($data) && p('massage') && e('未获取到关闭的区域'); //测试获取关闭的区块键值对
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/block.class.php';
|
||||
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$block = zdTable('block');
|
||||
$block->id->range('2-3');
|
||||
$block->account->range('admin');
|
||||
$block->vision->range('rnd');
|
||||
$block->module->range('test,my');
|
||||
$block->title->prefix('区块')->range('3,2');
|
||||
$block->hidden->range('0-1');
|
||||
$block->order->range('3-2');
|
||||
$block->dashboard->range('test,my');
|
||||
|
||||
$block->gen(2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 block 模块 model下的 getMyDashboard 方法
|
||||
timeout=0
|
||||
cid=39
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('block');
|
||||
|
||||
initData();
|
||||
|
||||
r($tester->block->getMyDashboard('test')) && p('2:account,title') && e('admin,区块3');
|
||||
r($tester->block->getMyDashboard('my', 1)) && p('3:account,title') && e('admin,区块2');
|
||||
@@ -67,7 +67,7 @@ form
|
||||
set::id('paramsRow'),
|
||||
set::class('form-grid'),
|
||||
$paramsRows,
|
||||
$block
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->name),
|
||||
@@ -75,7 +75,7 @@ form
|
||||
set::class('form-row'),
|
||||
set::control('input')
|
||||
) : null,
|
||||
$block
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->grid),
|
||||
|
||||
@@ -29,7 +29,7 @@ foreach($longBlocks as $index => $block)
|
||||
set::items
|
||||
([
|
||||
['text' => $lang->block->refresh, 'url' => ''],
|
||||
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "dashboard=$dashboard&blockID=$block->id"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "blockID=$block->id"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->hidden, 'url' => ''],
|
||||
['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "create", "dashboard=$dashboard"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->reset, 'url' => ''],
|
||||
@@ -77,7 +77,7 @@ foreach($shortBlocks as $index => $block)
|
||||
set::items
|
||||
([
|
||||
['text' => $lang->block->refresh, 'url' => ''],
|
||||
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "dashboard=$dashboard&blockID=$block->id"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "blockID=$block->id"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->hidden, 'url' => ''],
|
||||
['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "create", "dashboard=$dashboard"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->reset, 'url' => ''],
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The ui file of block module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author liuruogu<liuruogu@easycorp.ltd>
|
||||
* @package block
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
set::title($title);
|
||||
jsVar('blockID', $blockData->id);
|
||||
|
||||
$paramsRows = array();
|
||||
|
||||
foreach($params as $code => $row)
|
||||
{
|
||||
$paramsRows[] = formGroup
|
||||
(
|
||||
set::label($row['name']),
|
||||
set::name('params'),
|
||||
set::class('form-row'),
|
||||
set::value($blockData->params->{$code}),
|
||||
set::control(array
|
||||
(
|
||||
'type' => $row['control'],
|
||||
'items' => isset($row['options']) ? $row['options'] : null
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
form
|
||||
(
|
||||
on::change('#module', 'getForm'),
|
||||
on::change('#block', 'getForm'),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->block->lblModule),
|
||||
set::name('module'),
|
||||
set::value($blockData->module),
|
||||
set::control(array
|
||||
(
|
||||
'type' => 'select',
|
||||
'items' => $modules
|
||||
))
|
||||
),
|
||||
div
|
||||
(
|
||||
set::id('blockRow'),
|
||||
set::class('form-row'),
|
||||
$blocks
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->lblBlock),
|
||||
set::name('block'),
|
||||
set::value($block),
|
||||
set::control(array
|
||||
(
|
||||
'type' => 'select',
|
||||
'items' => array('') + $blocks
|
||||
))
|
||||
) : null
|
||||
),
|
||||
div
|
||||
(
|
||||
set::id('paramsRow'),
|
||||
set::class('form-grid'),
|
||||
$paramsRows,
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->name),
|
||||
set::name('title'),
|
||||
set::class('form-row'),
|
||||
set::value($blockData->title),
|
||||
set::control('input')
|
||||
) : null,
|
||||
(($module and $block) or ($module and !$blocks))
|
||||
? formGroup
|
||||
(
|
||||
set::label($lang->block->grid),
|
||||
set::name("grid"),
|
||||
set::class('form-row'),
|
||||
set::value($blockData->grid),
|
||||
set::control(array
|
||||
(
|
||||
'type' => 'select',
|
||||
'items' => $lang->block->gridOptions
|
||||
))
|
||||
) : null,
|
||||
)
|
||||
);
|
||||
|
||||
render('modalDialog');
|
||||
+13
-3
@@ -3,7 +3,7 @@ class blockZen extends block
|
||||
{
|
||||
/**
|
||||
* Get module options when adding or editing blocks.
|
||||
* 添加或编辑区块时获取模块选项
|
||||
* 添加或编辑区块时获取可使用的模块选项
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @access protected
|
||||
@@ -52,7 +52,7 @@ class blockZen extends block
|
||||
|
||||
/**
|
||||
* Get block options when adding or editing blocks.
|
||||
* 添加或编辑区块时获取区块选项
|
||||
* 添加或编辑区块时获取可使用的区块选项
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
@@ -61,6 +61,16 @@ class blockZen extends block
|
||||
*/
|
||||
protected function getAvailableBlocks($dashboard, $module): array|bool
|
||||
{
|
||||
if(!$this->selfCall)
|
||||
{
|
||||
$lang = str_replace('_', '-', $this->get->lang);
|
||||
$this->app->setClientLang($lang);
|
||||
$this->app->loadLang('common');
|
||||
$this->app->loadLang('block');
|
||||
|
||||
if(!$this->block->checkAPI($this->get->hash)) return array();
|
||||
}
|
||||
|
||||
$blocks = $this->block->getAvailableBlocks($dashboard, $module);
|
||||
|
||||
if(!$this->selfCall)
|
||||
@@ -80,7 +90,7 @@ class blockZen extends block
|
||||
* @param string $module
|
||||
* @param string $block
|
||||
* @access protected
|
||||
* @return array[]
|
||||
* @return array
|
||||
*/
|
||||
protected function getAvailableParams(string $dashboard, string $module = '', string $block = ''): array
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The control file of product module of ZenTaoPMS.
|
||||
*
|
||||
@@ -17,10 +16,12 @@ class product extends control
|
||||
/**
|
||||
* Construct function.
|
||||
*
|
||||
* @param moduleName
|
||||
* @param methodName
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($moduleName = '', $methodName = '')
|
||||
public function __construct(string $moduleName = '', string $methodName = ''): void
|
||||
{
|
||||
parent::__construct($moduleName, $methodName);
|
||||
|
||||
@@ -394,8 +395,8 @@ class product extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
|
||||
* Create a product.
|
||||
* 创建产品。可以是顶级产品,也可以是项目集下的产品。
|
||||
*
|
||||
* @param int $programID
|
||||
* @param string $extra
|
||||
@@ -410,26 +411,11 @@ class product extends control
|
||||
{
|
||||
$data = form::data($this->config->product->form->create);
|
||||
$data = $this->productZen->prepareCreateExtras($data);
|
||||
if(!$data) return $this->productZen->errorBeforeEdit();
|
||||
if(!$data) return $this->productZen->sendError4Create();
|
||||
|
||||
$result = $this->product->create($data);
|
||||
if(!$result) return $this->productZen->errorAfterEdit();
|
||||
return $this->productZen->responseAfterEdit($result);
|
||||
$productID = $this->product->create();
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
$this->loadModel('action')->create('product', $productID, 'opened');
|
||||
|
||||
$message = $this->executeHooks($productID);
|
||||
if($message) $this->lang->saveSuccess = $message;
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
|
||||
|
||||
$tab = $this->app->tab;
|
||||
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
|
||||
$methodName = $tab == 'program'? 'product' : 'browse';
|
||||
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
|
||||
$locate = isonlybody() ? 'parent' : $this->createLink($moduleName, $methodName, $param);
|
||||
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locate));
|
||||
$productID = $this->product->create($data);
|
||||
if(!$productID) return $this->productZen->sendError4Create();
|
||||
return $this->productZen->responseAfterCreate($productID, $data);
|
||||
}
|
||||
|
||||
$this->productZen->setMenu4Create($programID);
|
||||
|
||||
+75
-90
@@ -319,13 +319,13 @@ class productModel extends model
|
||||
/**
|
||||
* Get product pairs.
|
||||
*
|
||||
* @param string $mode
|
||||
* @param string $mode nocode
|
||||
* @param string $programID
|
||||
* @param string|array $append
|
||||
* @param string|int $shadow all | 0 | 1
|
||||
* @return array
|
||||
*/
|
||||
public function getPairs($mode = '', $programID = 0, $append = '', $shadow = 0)
|
||||
public function getPairs(string $mode = '', int $programID = 0, string|array $append = '', string|int $shadow = 0): array
|
||||
{
|
||||
if(defined('TUTORIAL')) return $this->loadModel('tutorial')->getProductPairs();
|
||||
|
||||
@@ -678,103 +678,22 @@ class productModel extends model
|
||||
|
||||
/**
|
||||
* Create a product.
|
||||
* 直接用对象数据创建产品
|
||||
*
|
||||
* @param object $product
|
||||
* @access public
|
||||
* @return int
|
||||
* @return int|false
|
||||
*/
|
||||
public function create()
|
||||
public function create(object $product): int|false
|
||||
{
|
||||
$product = fixer::input('post')
|
||||
->callFunc('name', 'trim')
|
||||
->setDefault('status', 'normal')
|
||||
->setDefault('line', 0)
|
||||
->setDefault('createdBy', $this->app->user->account)
|
||||
->setDefault('createdDate', helper::now())
|
||||
->setDefault('createdVersion', $this->config->version)
|
||||
->setIF($this->post->acl == 'open', 'whitelist', '')
|
||||
->setIF(!isset($_POST['whitelist']), 'whitelist', '')
|
||||
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
|
||||
->join('whitelist', ',')
|
||||
->join('reviewer', ',')
|
||||
->remove('uid,newLine,lineName,contactListMenu')
|
||||
->get();
|
||||
|
||||
$this->lang->error->unique = $this->lang->error->repeat;
|
||||
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
|
||||
|
||||
/* Lean mode relation defaultProgram. */
|
||||
$programID = isset($product->program) ? $product->program : 0;
|
||||
if($this->config->systemMode == 'light')
|
||||
{
|
||||
$programID = $this->config->global->defaultProgram;
|
||||
$product->program = $this->config->global->defaultProgram;
|
||||
}
|
||||
|
||||
$this->dao->insert(TABLE_PRODUCT)->data($product)->autoCheck()
|
||||
->batchCheck($this->config->product->create->requiredFields, 'notempty')
|
||||
->checkIF(!empty($product->name), 'name', 'unique', "`program` = $programID and `deleted` = '0'")
|
||||
->checkIF(!empty($product->name), 'name', 'unique', "`program` = {$product->program} and `deleted` = '0'")
|
||||
->checkIF(!empty($product->code), 'code', 'unique', "`deleted` = '0'")
|
||||
->checkFlow()
|
||||
->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$productID = $this->dao->lastInsertID();
|
||||
|
||||
if(!empty($_POST['lineName']))
|
||||
{
|
||||
/* Create product line. */
|
||||
$maxOrder = $this->dao->select("max(`order`) as maxOrder")->from(TABLE_MODULE)->where('type')->eq('line')->fetch('maxOrder');
|
||||
$maxOrder = $maxOrder ? $maxOrder + 10 : 0;
|
||||
|
||||
$line = new stdClass();
|
||||
$line->type = 'line';
|
||||
$line->parent = 0;
|
||||
$line->grade = 1;
|
||||
$line->name = $this->post->lineName;
|
||||
$line->root = $this->config->systemMode == 'ALM' ? $product->program : 0;
|
||||
$line->order = $maxOrder;
|
||||
|
||||
$lines = $this->dao->select('name')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch();
|
||||
if(!empty($lines))
|
||||
{
|
||||
dao::$errors['lineName'] = sprintf($this->lang->product->nameIsDuplicated, $line->name);
|
||||
return false;
|
||||
}
|
||||
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
$lineID = $this->dao->lastInsertID();
|
||||
$path = ",$lineID,";
|
||||
|
||||
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->where('id')->eq($lineID)->exec();
|
||||
|
||||
$this->dao->update(TABLE_PRODUCT)->set('line')->eq($lineID)->where('id')->eq($productID)->exec();
|
||||
}
|
||||
}
|
||||
|
||||
$this->file->updateObjectID($this->post->uid, $productID, 'product');
|
||||
$this->dao->update(TABLE_PRODUCT)->set('`order`')->eq($productID * 5)->where('id')->eq($productID)->exec();
|
||||
|
||||
$whitelist = explode(',', $product->whitelist);
|
||||
$this->loadModel('personnel')->updateWhitelist($whitelist, 'product', $productID);
|
||||
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
|
||||
|
||||
/* Create doc lib. */
|
||||
$this->app->loadLang('doc');
|
||||
$lib = new stdclass();
|
||||
$lib->product = $productID;
|
||||
$lib->name = $this->lang->doclib->main['product'];
|
||||
$lib->type = 'product';
|
||||
$lib->main = '1';
|
||||
$lib->acl = 'default';
|
||||
$lib->addedBy = $this->app->user->account;
|
||||
$lib->addedDate = helper::now();
|
||||
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
|
||||
|
||||
return $productID;
|
||||
}
|
||||
if(dao::isError()) return false;
|
||||
return $this->dao->lastInsertID();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1025,6 +944,72 @@ class productModel extends model
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create product line.
|
||||
* 创建产品线。
|
||||
*
|
||||
* @param int programID
|
||||
* @access public
|
||||
* @return int|false
|
||||
*/
|
||||
public function createLine(int $programID): int|false
|
||||
{
|
||||
if($programID <= 0) return false;
|
||||
if(empty($_POST['lineName'])) return false;
|
||||
|
||||
$line = new stdClass();
|
||||
$line->type = 'line';
|
||||
$line->parent = 0;
|
||||
$line->grade = 1;
|
||||
$line->name = htmlSpecialString($this->post->lineName);
|
||||
$line->root = $programID;
|
||||
|
||||
$existedLineID = $this->dao->select('id')->from(TABLE_MODULE)->where('type')->eq('line')->andWhere('root')->eq($line->root)->andWhere('name')->eq($line->name)->fetch('id');
|
||||
if($existedLineID) return $existedLineID;
|
||||
|
||||
$this->dao->insert(TABLE_MODULE)->data($line)->exec();
|
||||
if(dao::isError()) return false;
|
||||
|
||||
$lineID = $this->dao->lastInsertID();
|
||||
$path = ",$lineID,";
|
||||
$this->dao->update(TABLE_MODULE)->set('path')->eq($path)->set('`order`')->eq($lineID)->where('id')->eq($lineID)->exec();
|
||||
|
||||
return $lineID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create main lib for product
|
||||
* 关联创建产品主库
|
||||
*
|
||||
* @param int productID
|
||||
* @access public
|
||||
* @return int|false
|
||||
*/
|
||||
public function createMainLib(int $productID): int|false
|
||||
{
|
||||
if($productID <= 0) return false;
|
||||
|
||||
$existedLibID = $this->dao->select('id')->from(TABLE_DOCLIB)->where('product')->eq($productID)
|
||||
->andWhere('type')->eq('product')
|
||||
->andWhere('main')->eq('1')
|
||||
->fetch('id');
|
||||
if($existedLibID) return $existedLibID;
|
||||
|
||||
$this->app->loadLang('doc');
|
||||
$lib = new stdclass();
|
||||
$lib->product = $productID;
|
||||
$lib->name = $this->lang->doclib->main['product'];
|
||||
$lib->type = 'product';
|
||||
$lib->main = '1';
|
||||
$lib->acl = 'default';
|
||||
$lib->addedBy = $this->app->user->account;
|
||||
$lib->addedDate = helper::now();
|
||||
$this->dao->insert(TABLE_DOCLIB)->data($lib)->exec();
|
||||
|
||||
if(dao::isError())return false;
|
||||
return $this->dao->lastInsertID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stories.
|
||||
*
|
||||
|
||||
@@ -235,5 +235,4 @@ class productTao extends productModel
|
||||
|
||||
return $closedBugs;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,7 +47,3 @@ $stories2 = array($story4, $story5, $story6);
|
||||
$stories3 = array($story7, $story8, $story9);
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->batchGetStoryStageTest($stories1)) && p('1;2;3') && e('wait;planned;projected'); // 测试获取需求1 2 3的阶段
|
||||
r($product->batchGetStoryStageTest($stories2)) && p('4;5;6') && e('developing;developed;testing'); // 测试获取需求4 5 6的阶段
|
||||
r($product->batchGetStoryStageTest($stories3)) && p('7;8;9') && e('tested;verified;released'); // 测试获取需求7 8 9的阶段
|
||||
@@ -4,6 +4,7 @@ include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
#su('admin');
|
||||
zdTable('product')->gen(0);
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,20 +25,14 @@ pid=1
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
$t_create = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$t_noid = array('name' => 'case2');
|
||||
$t_repeat = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$t_noname = array('code' => 'testcase1');
|
||||
$t_namecode = array('name' => 'case3', 'code' => 'testcase3');
|
||||
$t_pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
|
||||
$t_intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
|
||||
$t_noacl = array('name' => 'case12', 'code' => 'testcase1', 'acl' => '');
|
||||
$create = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$repeat = array('name' => 'case1', 'code' => 'testcase1');
|
||||
$namecode = array('name' => 'case3', 'code' => 'testcase3');
|
||||
$pronamecode = array('program' => '3', 'name' => 'case4', 'code' => 'testcase4');
|
||||
$intypestatus = array('program' => '4', 'name' => 'case5', 'code' => 'testcase5', 'type' => 'branch', 'status' => 'closed');
|
||||
|
||||
r($product->createObject($t_create)) && p('name') && e('case1'); // 测试正常的创建
|
||||
r($product->createObject($t_noid)) && p('code:0') && e('『产品代号』不能为空。'); // 测试不填产品代号的情况
|
||||
r($product->createObject($t_repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
|
||||
r($product->createObject($t_noname)) && p('name:0') && e('『产品名称』不能为空。'); // 测试不填产品名称的情况
|
||||
r($product->createObject($t_namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
|
||||
r($product->createObject($t_pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
|
||||
r($product->createObject($t_intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
|
||||
r($product->createObject($t_noacl)) && p('acl:0') && e('『访问控制』不符合格式,应当为:『/open|private|custom/』。'); // 测试不填权限控制的情况
|
||||
r($product->createObject($create)) && p('name') && e('case1'); // 测试正常的创建
|
||||
r($product->createObject($repeat)) && p('code:0') && e('『产品代号』已经有『testcase1』这条记录了。'); // 测试创建重复的产品
|
||||
r($product->createObject($namecode)) && p('name,code') && e('case3,testcase3'); // 测试传入name和code
|
||||
r($product->createObject($pronamecode)) && p('program,name,code') && e('3,case4,testcase4'); // 测试传入program、name、code
|
||||
r($product->createObject($intypestatus)) && p('program,type,status') && e('4,branch,closed'); // 测试传入program、name、code、type、status
|
||||
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('module')->gen(0);
|
||||
|
||||
/**
|
||||
|
||||
title=productModel->createLine();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
*/
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->createLineTest('1', 'test line1')) && p('root,name') && e('1,test line1');
|
||||
r($product->createLineTest('0', 'test line1')) && p() && e('0');
|
||||
r($product->createLineTest('1', '')) && p() && e('0');
|
||||
r($product->createLineTest('1', "<script>alert('test')</script>")) && p('root,name') && e('1,<script>alert('test')</script>');
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/product.class.php';
|
||||
|
||||
zdTable('doclib')->gen(0);
|
||||
|
||||
/**
|
||||
|
||||
title=productModel->createmainlib();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
*/
|
||||
|
||||
$product = new productTest('admin');
|
||||
|
||||
r($product->createMainLibTest('-1')) && p() && e('0');
|
||||
r($product->createMainLibTest('0')) && p() && e('0');
|
||||
r($product->createMainLibTest('1')) && p('product,name,type,main') && e('1,产品主库,product,1');
|
||||
@@ -22,19 +22,28 @@ class productTest
|
||||
*
|
||||
* @param array $param
|
||||
* @access public
|
||||
* @return object
|
||||
* @return object|array
|
||||
*/
|
||||
public function createObject($param = array()): object
|
||||
public function createObject(array $param = array()): object|array
|
||||
{
|
||||
global $createFields;
|
||||
$whitelist = array();
|
||||
$createFields = array('program' => 1, 'line' => 0, 'lineName' => '', 'newLine' => 0, 'name' => '', 'code' => '', 'PO' => 'admin', 'QD' => '', 'RD' => '',
|
||||
'reviewer' => '', 'type' => 'normal', 'status' => 'normal', 'desc' => '', 'acl' => 'open', 'uid' => '');
|
||||
foreach($createFields as $field => $defaultValue) $_POST[$field] = $defaultValue;
|
||||
foreach($param as $key => $value) $_POST[$key] = $value;
|
||||
$createFields = array();
|
||||
$createFields['program'] = 1;
|
||||
$createFields['line'] = 0;
|
||||
$createFields['name'] = '';
|
||||
$createFields['code'] = '';
|
||||
$createFields['PO'] = 'admin';
|
||||
$createFields['QD'] = '';
|
||||
$createFields['RD'] = '';
|
||||
$createFields['reviewer'] = '';
|
||||
$createFields['type'] = 'normal';
|
||||
$createFields['status'] = 'normal';
|
||||
$createFields['desc'] = '';
|
||||
$createFields['acl'] = 'open';
|
||||
|
||||
$objectID = $this->objectModel->create();
|
||||
unset($_POST);
|
||||
$data = new stdclass();
|
||||
foreach($createFields as $field => $defaultValue) $data->$field = zget($param, $field, $defaultValue);
|
||||
|
||||
$objectID = $this->objectModel->create($data);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
@@ -1113,4 +1122,54 @@ class productTest
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试创建产品线
|
||||
* Test for create line.
|
||||
*
|
||||
* @param int programID
|
||||
* @param string lineName
|
||||
* @access public
|
||||
* @return object|array
|
||||
*/
|
||||
public function createLineTest(int $programID, string $lineName): object|array
|
||||
{
|
||||
$_POST['lineName'] = $lineName;
|
||||
$lineID = $this->objectModel->createLine($programID);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$lineID) return array();
|
||||
$object = $this->objectModel->dao->select('*')->from(TABLE_MODULE)->where('id')->eq($lineID)->fetch();
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试创建产品主库
|
||||
* Test for create main lib.
|
||||
*
|
||||
* @param int productID
|
||||
* @access public
|
||||
* @return object|array
|
||||
*/
|
||||
public function createMainLibTest(int $productID): object|array
|
||||
{
|
||||
$libID = $this->objectModel->createMainLib($productID);
|
||||
|
||||
if(dao::isError())
|
||||
{
|
||||
return dao::getError();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!$libID) return array();
|
||||
$object = $this->objectModel->dao->select('*')->from(TABLE_DOCLIB)->where('id')->eq($libID)->fetch();
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,84 @@ class productZen extends product
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set menu for create product page.
|
||||
* 为创建产品设置导航数据,主要是替换占位符。
|
||||
*
|
||||
* @param int $programID
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function setMenu4Create(int $program): void
|
||||
{
|
||||
if($this->app->tab == 'program') $this->loadModel('program')->setMenu($programID);
|
||||
if($this->app->tab == 'doc') unset($this->lang->doc->menu->product['subMenu']);
|
||||
if($this->app->getViewType() != 'mhtml') return;
|
||||
|
||||
if($this->app->rawModule == 'projectstory' and $this->app->rawMethod == 'story')
|
||||
{
|
||||
$this->loadModel('project')->setMenu();
|
||||
return;
|
||||
}
|
||||
$this->product->setMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get goback link for create by extra.
|
||||
* 通过extra获取返回链接。
|
||||
*
|
||||
* @param string $extra
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
private function getBackLink4Create(string $extra): string
|
||||
{
|
||||
$extra = str_replace(array(',', ' '), array('&', ''), $extra);
|
||||
parse_str($extra, $output);
|
||||
|
||||
$backLink = '';
|
||||
$from = zget($output, 'from', '');
|
||||
if($from == 'qa') $backLink = $this->createLink('qa', 'index');
|
||||
if($from == 'global') $backLink = $this->createLink('product', 'all');
|
||||
return $backLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get form fields for create.
|
||||
* 获取创建产品页面的表单配置。
|
||||
*
|
||||
* @param int $programID
|
||||
* @access private
|
||||
* @return array
|
||||
*/
|
||||
private function getFormFields4Create(int $programID = 0): array
|
||||
{
|
||||
$fields = $this->config->product->form->create;
|
||||
|
||||
$this->loadModel('user');
|
||||
$poUsers = $this->user->getPairs('nodeleted|pofirst|noclosed');
|
||||
$qdUsers = $this->user->getPairs('nodeleted|qdfirst|noclosed');
|
||||
$rdUsers = $this->user->getPairs('nodeleted|devfirst|noclosed');
|
||||
$users = $this->user->getPairs('nodeleted|noclosed');
|
||||
|
||||
foreach($fields as $field => $attr)
|
||||
{
|
||||
if(isset($attr['options']) and $attr['options'] == 'users') $fields[$field]['options'] = $users;
|
||||
$fields[$field]['name'] = $field;
|
||||
$fields[$field]['title'] = $this->lang->product->$field;
|
||||
}
|
||||
|
||||
$fields['program']['options'] = array('') + $this->loadModel('program')->getTopPairs('', 'noclosed');
|
||||
$fields['PO']['options'] = $poUsers;
|
||||
$fields['QD']['options'] = $qdUsers;
|
||||
$fields['RD']['options'] = $rdUsers;
|
||||
|
||||
if($programID) $fields['line']['options'] = array('') + $this->product->getLinePairs($programID);
|
||||
if(empty($programID) or $this->config->systemMode != 'ALM') unset($fields['line']);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product lines and product lines of program.
|
||||
*
|
||||
@@ -54,4 +132,119 @@ class productZen extends product
|
||||
|
||||
return array($productLines, $programLines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build form fields for create.
|
||||
* 构建创建产品页面数据。
|
||||
*
|
||||
* @param int $programID
|
||||
* @param string $extra
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function buildCreateForm(int $programID = 0, string $extra = ''): void
|
||||
{
|
||||
$this->view->title = $this->lang->product->create;
|
||||
$this->view->gobackLink = $this->getBackLink4Create($extra);
|
||||
$this->view->programID = $programID;
|
||||
$this->view->fields = $this->getFormFields4Create($programID);
|
||||
unset($this->lang->product->typeList['']);
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare data for create.
|
||||
* 追加创建信息,处理白名单、评审者、项目集字段,还有富文本内容处理。
|
||||
*
|
||||
* @param int $programID
|
||||
* @param string $extra
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function prepareCreateExtras(object $data): object
|
||||
{
|
||||
$product = $data->setDefault('createdBy', $this->app->user->account)
|
||||
->setDefault('createdDate', helper::now())
|
||||
->setDefault('createdVersion', $this->config->version)
|
||||
->setIF($this->config->systemMode == 'light', 'program', (int)zget($this->config->global, 'defaultProgram', 0))
|
||||
->setIF($this->post->acl == 'open', 'whitelist', '')
|
||||
->stripTags($this->config->product->editor->create['id'], $this->config->allowedTags)
|
||||
->join('whitelist', ',')
|
||||
->join('reviewer', ',')
|
||||
->remove('uid,newLine,lineName,contactListMenu')
|
||||
->get();
|
||||
$product = $this->loadModel('file')->processImgURL($product, $this->config->product->editor->create['id'], $this->post->uid);
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process after create product.
|
||||
* 成功插入产品数据后,其他的额外操作。
|
||||
*
|
||||
* @param int $productID
|
||||
* @param object $product
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function responseAfterCreate(int $productID, object $product): void
|
||||
{
|
||||
$fixData = new stdclass();
|
||||
$fixData->order = $productID * 5;
|
||||
if(!empty($_POST['lineName']))
|
||||
{
|
||||
$lineID = $this->product->createLine((int)$product->program);
|
||||
if($lineID) $fixData->line = $lineID;
|
||||
}
|
||||
|
||||
$this->dao->update(TABLE_PRODUCT)->data($fixData)->where('id')->eq($productID)->exec();
|
||||
$this->file->updateObjectID($this->post->uid, $productID, 'product');
|
||||
|
||||
$this->loadModel('personnel')->updateWhitelist(explode(',', $product->whitelist), 'product', $productID);
|
||||
if($product->acl != 'open') $this->loadModel('user')->updateUserView($productID, 'product');
|
||||
|
||||
$this->product->createMainLib($productID);
|
||||
|
||||
$this->loadModel('action')->create('product', $productID, 'opened');
|
||||
|
||||
$message = $this->executeHooks($productID);
|
||||
if($message) $this->lang->saveSuccess = $message;
|
||||
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'id' => $productID));
|
||||
$this->sendCreateLocate($productID, (int)$product->program);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate after create product.
|
||||
* 创建完成后,做页面跳转。
|
||||
*
|
||||
* @param int $productID
|
||||
* @param int $programID
|
||||
* @access private
|
||||
* @return void
|
||||
*/
|
||||
private function sendCreateLocate(int $productID, int $programID): void
|
||||
{
|
||||
$tab = $this->app->tab;
|
||||
$moduleName = $tab == 'program'? 'program' : $this->moduleName;
|
||||
$methodName = $tab == 'program'? 'product' : 'browse';
|
||||
$param = $tab == 'program' ? "programID=$programID" : "productID=$productID";
|
||||
$locate = isonlybody() ? 'true' : $this->createLink($moduleName, $methodName, $param);
|
||||
if($tab == 'doc') $locate = $this->createLink('doc', 'productSpace', "objectID=$productID");
|
||||
|
||||
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'load' => $locate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send error for create.
|
||||
* 输出创建产品产生的错误。
|
||||
*
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function sendError4Create(): void
|
||||
{
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
}
|
||||
}
|
||||
|
||||
+23
-11
@@ -193,13 +193,14 @@ class project extends control
|
||||
/**
|
||||
* Ajax get unlink tips when unlink team member.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param int $account
|
||||
* @param string $projectID
|
||||
* @param string $account
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxGetUnlinkTips($projectID, $account)
|
||||
public function ajaxGetUnlinkTips(string $projectID, string $account)
|
||||
{
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
if(!$project->multiple) return;
|
||||
|
||||
@@ -271,6 +272,7 @@ class project extends control
|
||||
|
||||
if(!empty($objectID))
|
||||
{
|
||||
$objectID = (int)$objectID;
|
||||
$object = $objectType == 'project' ? $this->project->getByID($objectID) : $this->loadModel('program')->getByID($objectID);
|
||||
|
||||
if(isset($availableBudget)) $availableBudget = $object->parent == $selectedProgramID ? $availableBudget + (int)$object->budget : $availableBudget;
|
||||
@@ -325,6 +327,7 @@ class project extends control
|
||||
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
/* Locate to task when set no execution. */
|
||||
@@ -549,6 +552,7 @@ class project extends control
|
||||
$this->loadModel('program');
|
||||
$this->loadModel('execution');
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
$programID = $project->parent;
|
||||
$this->project->setMenu($projectID);
|
||||
@@ -889,6 +893,7 @@ class project extends control
|
||||
*/
|
||||
public function dynamic($projectID = 0, $type = 'today', $param = '', $recTotal = 0, $date = '', $direction = 'next')
|
||||
{
|
||||
$projectID = (int)$projectID;
|
||||
$this->loadModel('execution');
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
@@ -974,6 +979,7 @@ class project extends control
|
||||
|
||||
if($this->cookie->showTask) $this->session->set('taskList', $this->app->getURI(true), 'project');
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$projects = $this->project->getPairsByProgram();
|
||||
$projectID = $this->project->saveState($projectID, $projects);
|
||||
$project = $this->project->getByID($projectID);
|
||||
@@ -1057,11 +1063,12 @@ class project extends control
|
||||
$this->session->set('bugList', $this->app->getURI(true), 'project');
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
$product = $this->product->getById($productID);
|
||||
$project = $this->project->getByID($projectID);
|
||||
$type = strtolower($type);
|
||||
$queryID = ($type == 'bysearch') ? (int)$param : 0;
|
||||
$products = $this->product->getProducts($projectID);
|
||||
$projectID = (int)$projectID;
|
||||
$product = $this->product->getById($productID);
|
||||
$project = $this->project->getByID($projectID);
|
||||
$type = strtolower($type);
|
||||
$queryID = ($type == 'bysearch') ? (int)$param : 0;
|
||||
$products = $this->product->getProducts($projectID);
|
||||
|
||||
if(!$project->multiple) unset($this->config->bug->datatable->fieldList['execution']);
|
||||
if(!$project->hasProduct)
|
||||
@@ -1258,6 +1265,7 @@ class project extends control
|
||||
$this->session->set('testtaskList', $this->app->getURI(true), 'qa');
|
||||
$this->session->set('buildList', $this->app->getURI(true), 'execution');
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
/* Load pager. */
|
||||
@@ -1301,6 +1309,7 @@ class project extends control
|
||||
/* Load module and get project. */
|
||||
$this->loadModel('build');
|
||||
$this->loadModel('product');
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
@@ -1459,7 +1468,7 @@ class project extends control
|
||||
$this->view->version = $version;
|
||||
|
||||
/* Unset not project privs. */
|
||||
$project = $this->project->getByID($group->project);
|
||||
$project = $this->project->getByID((int)$group->project);
|
||||
if($project->hasProduct)
|
||||
{
|
||||
if($this->config->URAndSR) unset($this->lang->resource->requirement);
|
||||
@@ -1650,7 +1659,7 @@ class project extends control
|
||||
}
|
||||
|
||||
$group = $this->group->getById($groupID);
|
||||
$project = $this->project->getByID($group->project);
|
||||
$project = $this->project->getByID((int)$group->project);
|
||||
$groupUsers = $this->group->getUserPairs($groupID);
|
||||
$allUsers = $this->loadModel('dept')->getDeptUserPairs($deptID);
|
||||
$otherUsers = array_diff_assoc($allUsers, $groupUsers);
|
||||
@@ -1806,6 +1815,7 @@ class project extends control
|
||||
public function close($projectID)
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$projectID = (int)$projectID;
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1841,7 +1851,8 @@ class project extends control
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$this->app->loadLang('execution');
|
||||
$project = $this->project->getByID($projectID);
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
@@ -1883,6 +1894,7 @@ class project extends control
|
||||
*/
|
||||
public function delete($projectID, $confirm = 'no', $from = 'browse')
|
||||
{
|
||||
$projectID = (int)$projectID;
|
||||
if($confirm == 'no')
|
||||
{
|
||||
$project = $this->project->getByID($projectID);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
helper::import(dirname(__FILE__) . 'config/form.php');
|
||||
|
||||
$config->todo = new stdclass();
|
||||
$config->todo->batchCreate = 8;
|
||||
@@ -21,7 +22,7 @@ $config->todo->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
|
||||
$config->todo->editor->view = array('id' => 'comment,lastComment', 'tools' => 'simpleTools');
|
||||
|
||||
$config->todo->list = new stdclass();
|
||||
$config->todo->list->exportFields = 'id, account, date, begin, end, type, idvalue, pri, name, desc, status, private';
|
||||
$config->todo->list->exportFields = 'id, account, date, begin, end, type, objectID, pri, name, desc, status, private';
|
||||
$config->todo->list->customBatchCreateFields = 'type,pri,desc,beginAndEnd';
|
||||
$config->todo->list->customBatchEditFields = 'pri,beginAndEnd,status';
|
||||
|
||||
@@ -41,4 +42,4 @@ $config->todo->objectList = array();
|
||||
$config->todo->objectList['bug'] = 'bugs';
|
||||
$config->todo->objectList['task'] = 'tasks';
|
||||
$config->todo->objectList['story'] = 'stories';
|
||||
$config->todo->objectList['testtask'] = 'testtasks';
|
||||
$config->todo->objectList['testtask'] = 'testtasks';
|
||||
|
||||
@@ -21,3 +21,7 @@ $config->todo->create->form['uid'] = array('required' => false, 'type'
|
||||
|
||||
$config->todo->edit->form = array();
|
||||
$config->todo->edit->form['name'] = array('required' => true, 'type' => 'string');
|
||||
|
||||
$config->todo->batchClose = new stdclass;
|
||||
$config->todo->batchClose->form = array();
|
||||
$config->todo->batchClose->form['todoIDList'] = array('required' => true, 'type' => 'array');
|
||||
|
||||
+32
-27
@@ -1,13 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* The control file of todo module of ZenTaoPMS.
|
||||
* The control file of example module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author lanzongjun@easycorp.ltd;
|
||||
* @author Lanzongjun <lanzongjun@easycorp.ltd>
|
||||
* @package todo
|
||||
* @link http://www.zentao.net
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class todo extends control
|
||||
{
|
||||
@@ -20,6 +21,7 @@ class todo extends control
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->app->loadClass('date');
|
||||
$this->loadModel('task');
|
||||
$this->loadModel('bug');
|
||||
@@ -33,7 +35,7 @@ class todo extends control
|
||||
* @param string $date
|
||||
* @param string $from todo|feedback|block
|
||||
* @access public
|
||||
* @return void
|
||||
* @return int|void
|
||||
*/
|
||||
public function create(string $date = 'today', string $from = 'todo')
|
||||
{
|
||||
@@ -41,20 +43,21 @@ class todo extends control
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$formData = form::data($this->config->todo->create->form);
|
||||
$todo = form::data($this->config->todo->create->form)
|
||||
->remove(implode(',', $this->config->todo->moduleList) . ',uid')
|
||||
->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)
|
||||
->get();
|
||||
|
||||
$todo = $this->todoZen->beforeCreate($formData);
|
||||
$todoID = $this->todoZen->doCreate($todo);
|
||||
$todoID = $this->todo->create($todo);
|
||||
if($todoID === false) return print(js::error(dao::getError()));
|
||||
|
||||
$todo->id = $todoID;
|
||||
$this->todoZen->afterCreate($todo);
|
||||
|
||||
if(!empty($_POST['idvalue'])) return $this->send(array('result' => 'success'));
|
||||
if(!empty($_POST['objectID'])) return $this->send(array('result' => 'success'));
|
||||
|
||||
if($from == 'block')
|
||||
{
|
||||
// TODO
|
||||
$todo = $this->todo->getById($todoID);
|
||||
$todo->begin = date::formatTime($todo->begin);
|
||||
return $this->send(array('result' => 'success', 'id' => $todoID, 'name' => $todo->name, 'pri' => $todo->pri, 'priName' => $this->lang->todo->priList[$todo->pri], 'time' => date(DT_DATE4, strtotime($todo->date)) . ' ' . $todo->begin));
|
||||
@@ -214,7 +217,7 @@ class todo extends control
|
||||
if($todo->type != 'custom')
|
||||
{
|
||||
if(!isset($objectIDList[$todo->type])) $objectIDList[$todo->type] = array();
|
||||
$objectIDList[$todo->type][$todo->idvalue] = $todo->idvalue;
|
||||
$objectIDList[$todo->type][$todo->objectID] = $todo->objectID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -486,13 +489,13 @@ class todo extends control
|
||||
{
|
||||
$confirmNote = 'confirm' . ucfirst($todo->type);
|
||||
$okTarget = isonlybody() ? 'parent' : 'window.parent.$.apps.open';
|
||||
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->idvalue");
|
||||
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->objectID");
|
||||
if($todo->type == 'bug') $app = 'qa';
|
||||
if($todo->type == 'task') $app = 'execution';
|
||||
if($todo->type == 'story') $app = 'product';
|
||||
$cancelURL = $this->server->HTTP_REFERER;
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->idvalue), 'locate' => $confirmURL));
|
||||
return print(strpos($cancelURL, 'calendar') ? json_encode(array(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL)) : js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success', 'message' => sprintf($this->lang->todo->$confirmNote, $todo->objectID), 'locate' => $confirmURL));
|
||||
return print(strpos($cancelURL, 'calendar') ? json_encode(array(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL)) : js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
|
||||
}
|
||||
if(defined('RUN_MODE') && RUN_MODE == 'api') return $this->send(array('status' => 'success'));
|
||||
if(isonlybody()) return print(js::reload('parent.parent'));
|
||||
@@ -519,17 +522,19 @@ class todo extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch close todos.
|
||||
* Batch close todos. The status of todo which need to close should be done.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchClose()
|
||||
public function batchClose(): void
|
||||
{
|
||||
$waitIdList = array();
|
||||
foreach($_POST['todoIDList'] as $todoID)
|
||||
$todoIdlist = form::data($this->config->todo->batchClose->form)->get('todoIDList');
|
||||
foreach($todoIdlist as $todoID)
|
||||
{
|
||||
$todo = $this->todo->getById($todoID);
|
||||
$todoID = (int) $todoID;
|
||||
$todo = $this->todo->getById($todoID);
|
||||
if($todo->status == 'done') $this->todo->close($todoID);
|
||||
if($todo->status != 'done' and $todo->status != 'closed') $waitIdList[] = $todoID;
|
||||
}
|
||||
@@ -578,7 +583,7 @@ class todo extends control
|
||||
$fields[$fieldName] = isset($todoLang->$fieldName) ? $todoLang->$fieldName : $fieldName;
|
||||
unset($fields[$key]);
|
||||
}
|
||||
unset($fields['idvalue']);
|
||||
unset($fields['objectID']);
|
||||
unset($fields['private']);
|
||||
|
||||
/* Get bugs. */
|
||||
@@ -609,18 +614,18 @@ class todo extends control
|
||||
|
||||
$type = $todo->type;
|
||||
if(isset($users[$todo->account])) $todo->account = $users[$todo->account];
|
||||
if($type == 'bug') $todo->name = isset($bugs[$todo->idvalue]) ? $bugs[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'story') $todo->name = isset($stories[$todo->idvalue]) ? $stories[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'task') $todo->name = isset($tasks[$todo->idvalue]) ? $tasks[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'bug') $todo->name = isset($bugs[$todo->objectID]) ? $bugs[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
if($type == 'story') $todo->name = isset($stories[$todo->objectID]) ? $stories[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
if($type == 'task') $todo->name = isset($tasks[$todo->objectID]) ? $tasks[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
|
||||
if($this->config->edition == 'max')
|
||||
{
|
||||
if($type == 'issue') $todo->name = isset($issues[$todo->idvalue]) ? $issues[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'risk') $todo->name = isset($risks[$todo->idvalue]) ? $risks[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'opportunity') $todo->name = isset($opportunities[$todo->idvalue]) ? $opportunities[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'issue') $todo->name = isset($issues[$todo->objectID]) ? $issues[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
if($type == 'risk') $todo->name = isset($risks[$todo->objectID]) ? $risks[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
if($type == 'opportunity') $todo->name = isset($opportunities[$todo->objectID]) ? $opportunities[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
}
|
||||
if($type == 'testtask') $todo->name = isset($testTasks[$todo->idvalue]) ? $testTasks[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'review' && isset($this->config->qcVersion)) $todo->name = isset($reviews[$todo->idvalue]) ? $reviews[$todo->idvalue] . "(#$todo->idvalue)" : '';
|
||||
if($type == 'testtask') $todo->name = isset($testTasks[$todo->objectID]) ? $testTasks[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
if($type == 'review' && isset($this->config->qcVersion)) $todo->name = isset($reviews[$todo->objectID]) ? $reviews[$todo->objectID] . "(#$todo->objectID)" : '';
|
||||
|
||||
if(isset($todoLang->typeList[$type])) $todo->type = $todoLang->typeList[$type];
|
||||
if(isset($todoLang->priList[$todo->pri])) $todo->pri = $todoLang->priList[$todo->pri];
|
||||
@@ -628,7 +633,7 @@ class todo extends control
|
||||
if($todo->private == 1) $todo->desc = $this->lang->todo->thisIsPrivate;
|
||||
|
||||
/* drop some field that is not needed. */
|
||||
unset($todo->idvalue);
|
||||
unset($todo->objectID);
|
||||
unset($todo->private);
|
||||
}
|
||||
if($this->config->edition != 'open') list($fields, $todos) = $this->loadModel('workflowfield')->appendDataFromFlow($fields, $todos);
|
||||
|
||||
@@ -14,11 +14,11 @@ function switchDateTodo(switcher)
|
||||
* @param type $type Type of selected todo.
|
||||
* @param id $id ID of selected todo.
|
||||
* @param defaultType $defaultType Default type of selected todo.
|
||||
* @param idvalue $idvalue ID of the closed todo type.
|
||||
* @param objectID $objectID ID of the closed todo type.
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function loadList(type, id, defaultType, idvalue)
|
||||
function loadList(type, id, defaultType, objectID)
|
||||
{
|
||||
if(id)
|
||||
{
|
||||
@@ -34,7 +34,7 @@ function loadList(type, id, defaultType, idvalue)
|
||||
id = id ? id : '';
|
||||
var param = 'userID=' + userID + '&id=' + id;
|
||||
if(type == "task") param += '&status=wait,doing';
|
||||
if(type == defaultType && idvalue != 0) param += '&idvalue=' + idvalue;
|
||||
if(type == defaultType && objectID != 0) param += '&objectID=' + objectID;
|
||||
|
||||
if(moduleList.indexOf(type) !== -1)
|
||||
{
|
||||
@@ -45,7 +45,7 @@ function loadList(type, id, defaultType, idvalue)
|
||||
if(data.length != 0)
|
||||
{
|
||||
$(divClass).html(data).find('select').chosen();
|
||||
if(config.currentMethod == 'edit' || type == 'feedback') $(divClass).find('select').val(idvalue).trigger('chosen:updated');
|
||||
if(config.currentMethod == 'edit' || type == 'feedback') $(divClass).find('select').val(objectID).trigger('chosen:updated');
|
||||
if($(divClass + " select").val() == null) $(divClass + " select").attr("data-placeholder", noOptions.replace("%s", chosenType[type])).trigger('chosen:updated');
|
||||
}
|
||||
else
|
||||
@@ -68,7 +68,7 @@ function loadList(type, id, defaultType, idvalue)
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#nameBoxLabel').text(nameBoxLabel.idvalue);
|
||||
$('#nameBoxLabel').text(nameBoxLabel.objectID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
$(function()
|
||||
{
|
||||
loadList($('#type').val(), '', defaultType, idvalue);
|
||||
loadList($('#type').val(), '', defaultType, objectID);
|
||||
|
||||
$('#pri').on('change', function()
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ $lang->todo->end = 'Ende';
|
||||
$lang->todo->beginAB = 'Start';
|
||||
$lang->todo->endAB = 'Ende';
|
||||
$lang->todo->beginAndEnd = 'Dauer';
|
||||
$lang->todo->idvalue = 'Link ID';
|
||||
$lang->todo->objectID = 'Link ID';
|
||||
$lang->todo->type = 'Typ';
|
||||
$lang->todo->pri = 'Priorität';
|
||||
$lang->todo->name = 'Titel';
|
||||
|
||||
@@ -51,7 +51,7 @@ $lang->todo->end = 'End';
|
||||
$lang->todo->beginAB = 'Begin';
|
||||
$lang->todo->endAB = 'End';
|
||||
$lang->todo->beginAndEnd = 'Begin and End';
|
||||
$lang->todo->idvalue = 'Link ID';
|
||||
$lang->todo->objectID = 'Link ID';
|
||||
$lang->todo->type = 'Type';
|
||||
$lang->todo->pri = 'Priority';
|
||||
$lang->todo->name = 'Title';
|
||||
|
||||
@@ -51,7 +51,7 @@ $lang->todo->end = 'Fin';
|
||||
$lang->todo->beginAB = 'Début';
|
||||
$lang->todo->endAB = 'Fin';
|
||||
$lang->todo->beginAndEnd = 'Début et Fin';
|
||||
$lang->todo->idvalue = 'Link ID';
|
||||
$lang->todo->objectID = 'Link ID';
|
||||
$lang->todo->type = 'Type';
|
||||
$lang->todo->pri = 'Priorité';
|
||||
$lang->todo->name = 'Titre';
|
||||
|
||||
@@ -49,7 +49,7 @@ $lang->todo->end = 'Kết thúc';
|
||||
$lang->todo->beginAB = 'Bắt đầu';
|
||||
$lang->todo->endAB = 'Kết thúc';
|
||||
$lang->todo->beginAndEnd = 'Thời gian';
|
||||
$lang->todo->idvalue = 'Liên kết ID';
|
||||
$lang->todo->objectID = 'Liên kết ID';
|
||||
$lang->todo->type = 'Loại';
|
||||
$lang->todo->pri = 'Ưu tiên';
|
||||
$lang->todo->name = 'Tiêu đề';
|
||||
|
||||
@@ -51,7 +51,7 @@ $lang->todo->end = '结束';
|
||||
$lang->todo->beginAB = '开始';
|
||||
$lang->todo->endAB = '结束';
|
||||
$lang->todo->beginAndEnd = '起止时间';
|
||||
$lang->todo->idvalue = '关联编号';
|
||||
$lang->todo->objectID = '关联编号';
|
||||
$lang->todo->type = '类型';
|
||||
$lang->todo->pri = '优先级';
|
||||
$lang->todo->name = '待办名称';
|
||||
|
||||
@@ -50,7 +50,7 @@ $lang->todo->end = '結束';
|
||||
$lang->todo->beginAB = '開始';
|
||||
$lang->todo->endAB = '結束';
|
||||
$lang->todo->beginAndEnd = '起止時間';
|
||||
$lang->todo->idvalue = '關聯編號';
|
||||
$lang->todo->objectID = '關聯編號';
|
||||
$lang->todo->type = '類型';
|
||||
$lang->todo->pri = '優先順序';
|
||||
$lang->todo->name = '待辦名稱';
|
||||
|
||||
+67
-135
@@ -1,13 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* The model file of todo module of ZenTaoPMS.
|
||||
* The model file of example module of ZenTaoPMS.
|
||||
*
|
||||
* @copyright Copyright 2009-2015 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.cnezsoft.com)
|
||||
* @license ZPL(http://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
|
||||
* @copyright Copyright 2009-2023 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
|
||||
* @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
|
||||
* @author Lanzongjun <lanzongjun@easycorp.ltd>
|
||||
* @package todo
|
||||
* @version $Id: model.php 5035 2013-07-06 05:21:58Z wyd621@gmail.com $
|
||||
* @link http://www.zentao.net
|
||||
* @link https://www.zentao.net
|
||||
*/
|
||||
class todoModel extends model
|
||||
{
|
||||
@@ -18,10 +19,13 @@ class todoModel extends model
|
||||
* @param object $todo
|
||||
* @return int|false
|
||||
*/
|
||||
public function create(object $todo): int|bool
|
||||
public function create(object $todo): int|false
|
||||
{
|
||||
$todoID = $this->todoTao->insert($todo);
|
||||
/* 处理 $todo 信息 */
|
||||
$processedTodo = $this->todoTao->beforeCreate($todo);
|
||||
if(!$processedTodo) return false;
|
||||
|
||||
$todoID = $this->todoTao->insert($processedTodo);
|
||||
if(dao::isError()) return false;
|
||||
|
||||
return $todoID;
|
||||
@@ -74,18 +78,18 @@ class todoModel extends model
|
||||
$todo->end = isset($todos->ends[$i]) ? $todos->ends[$i] : 2400;
|
||||
$todo->status = "wait";
|
||||
$todo->private = 0;
|
||||
$todo->idvalue = 0;
|
||||
$todo->objectID = 0;
|
||||
$todo->assignedTo = $assignedTo;
|
||||
$todo->assignedBy = $this->app->user->account;
|
||||
$todo->assignedDate = $now;
|
||||
$todo->vision = $this->config->vision;
|
||||
|
||||
if(in_array($todo->type, $this->config->todo->moduleList)) $todo->idvalue = isset($todos->{$this->config->todo->objectList[$todo->type]}[$i + 1]) ? $todos->{$this->config->todo->objectList[$todo->type]}[$i + 1] : 0;
|
||||
if(in_array($todo->type, $this->config->todo->moduleList)) $todo->objectID = isset($todos->{$this->config->todo->objectList[$todo->type]}[$i + 1]) ? $todos->{$this->config->todo->objectList[$todo->type]}[$i + 1] : 0;
|
||||
|
||||
if($todo->type != 'custom' and $todo->idvalue)
|
||||
if($todo->type != 'custom' and $todo->objectID)
|
||||
{
|
||||
$type = $todo->type;
|
||||
$object = $this->loadModel($type)->getByID($todo->idvalue);
|
||||
$object = $this->loadModel($type)->getByID($todo->objectID);
|
||||
if(isset($object->name)) $todo->name = $object->name;
|
||||
if(isset($object->title)) $todo->name = $object->title;
|
||||
}
|
||||
@@ -140,7 +144,7 @@ class todoModel extends model
|
||||
|
||||
$this->loadModel('file')->updateObjectID($todo->uid, $todoID, 'todo');
|
||||
if(!empty($oldTodo->cycle)) $this->createByCycle(array($todoID => $todo));
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->idvalue) $this->loadModel('feedback')->updateStatus('todo', $todo->idvalue, $todo->status);
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->objectID) $this->loadModel('feedback')->updateStatus('todo', $todo->objectID, $todo->status);
|
||||
return common::createChanges($oldTodo, (array)$todo);
|
||||
}
|
||||
|
||||
@@ -177,7 +181,7 @@ class todoModel extends model
|
||||
|
||||
if(in_array($todo->type, $this->config->todo->moduleList))
|
||||
{
|
||||
$todo->idvalue = isset($data->{$this->config->todo->objectList[$todo->type]}[$todoID]) ? $data->{$this->config->todo->objectList[$todo->type]}[$todoID] : 0;
|
||||
$todo->objectID = isset($data->{$this->config->todo->objectList[$todo->type]}[$todoID]) ? $data->{$this->config->todo->objectList[$todo->type]}[$todoID] : 0;
|
||||
}
|
||||
if($todo->end < $todo->begin) return print(js::alert(sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin)));
|
||||
|
||||
@@ -191,15 +195,15 @@ class todoModel extends model
|
||||
$this->dao->update(TABLE_TODO)->data($todo)
|
||||
->autoCheck()
|
||||
->checkIF(!in_array($todo->type, $this->config->todo->moduleList), $this->config->todo->edit->requiredFields, 'notempty')
|
||||
->checkIF($todo->type == 'bug' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'task' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'story' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'issue' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'risk' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'opportunity' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'review' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'testtask' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'feedback' and $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF($todo->type == 'bug' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'task' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'story' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'issue' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'risk' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'opportunity' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'review' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'testtask' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->checkIF($todo->type == 'feedback' and $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->where('id')->eq($todoID)
|
||||
->exec();
|
||||
|
||||
@@ -207,10 +211,10 @@ class todoModel extends model
|
||||
|
||||
if(!dao::isError())
|
||||
{
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->idvalue && !isset($feedbacks[$todo->idvalue]))
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max') && $todo->type == 'feedback' && $todo->objectID && !isset($feedbacks[$todo->objectID]))
|
||||
{
|
||||
$feedbacks[$todo->idvalue] = $todo->idvalue;
|
||||
$this->loadModel('feedback')->updateStatus('todo', $todo->idvalue, $todo->status);
|
||||
$feedbacks[$todo->objectID] = $todo->objectID;
|
||||
$this->loadModel('feedback')->updateStatus('todo', $todo->objectID, $todo->status);
|
||||
}
|
||||
|
||||
$allChanges[$todoID] = common::createChanges($oldTodo, $todo);
|
||||
@@ -264,7 +268,7 @@ class todoModel extends model
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max'))
|
||||
{
|
||||
$feedbackID = $this->dao->select('idvalue')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('idvalue');
|
||||
$feedbackID = $this->dao->select('objectID')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('objectID');
|
||||
if($feedbackID) $this->loadModel('feedback')->updateStatus('todo', $feedbackID, 'done');
|
||||
}
|
||||
return true;
|
||||
@@ -286,15 +290,15 @@ class todoModel extends model
|
||||
if(!$todo) return false;
|
||||
$todo = $this->loadModel('file')->replaceImgURL($todo, 'desc');
|
||||
if($setImgSize) $todo->desc = $this->file->setImgSize($todo->desc);
|
||||
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_STORY)->fetch('title');
|
||||
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name');
|
||||
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title');
|
||||
if($todo->type == 'issue' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_ISSUE)->fetch('title');
|
||||
if($todo->type == 'risk' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_RISK)->fetch('name');
|
||||
if($todo->type == 'opportunity' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_OPPORTUNITY)->fetch('name');
|
||||
if($todo->type == 'review' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_REVIEW)->fetch('title');
|
||||
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TESTTASK)->fetch('name');
|
||||
if($todo->type == 'feedback') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_FEEDBACK)->fetch('title');
|
||||
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_STORY)->fetch('title');
|
||||
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TASK)->fetch('name');
|
||||
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_BUG)->fetch('title');
|
||||
if($todo->type == 'issue' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_ISSUE)->fetch('title');
|
||||
if($todo->type == 'risk' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_RISK)->fetch('name');
|
||||
if($todo->type == 'opportunity' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_OPPORTUNITY)->fetch('name');
|
||||
if($todo->type == 'review' and $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_REVIEW)->fetch('title');
|
||||
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TESTTASK)->fetch('name');
|
||||
if($todo->type == 'feedback') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title');
|
||||
$todo->date = str_replace('-', '', $todo->date);
|
||||
return $todo;
|
||||
}
|
||||
@@ -404,15 +408,15 @@ class todoModel extends model
|
||||
|
||||
while($todo = $stmt->fetch())
|
||||
{
|
||||
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_STORY)->fetch('title');
|
||||
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TASK)->fetch('name');
|
||||
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_BUG)->fetch('title');
|
||||
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_TESTTASK)->fetch('name');
|
||||
if($todo->type == 'issue' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_ISSUE)->fetch('title');
|
||||
if($todo->type == 'risk' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_RISK)->fetch('name');
|
||||
if($todo->type == 'opportunity' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_OPPORTUNITY)->fetch('name');
|
||||
if($todo->type == 'review' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_REVIEW)->fetch('title');
|
||||
if($todo->type == 'feedback' and $this->config->edition != 'open') $todo->name = $this->dao->findById($todo->idvalue)->from(TABLE_FEEDBACK)->fetch('title');
|
||||
if($todo->type == 'story') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_STORY)->fetch('title');
|
||||
if($todo->type == 'task') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TASK)->fetch('name');
|
||||
if($todo->type == 'bug') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_BUG)->fetch('title');
|
||||
if($todo->type == 'testtask') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_TESTTASK)->fetch('name');
|
||||
if($todo->type == 'issue' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_ISSUE)->fetch('title');
|
||||
if($todo->type == 'risk' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_RISK)->fetch('name');
|
||||
if($todo->type == 'opportunity' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_OPPORTUNITY)->fetch('name');
|
||||
if($todo->type == 'review' && $this->config->edition == 'max') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_REVIEW)->fetch('title');
|
||||
if($todo->type == 'feedback' and $this->config->edition != 'open') $todo->name = $this->dao->findById($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title');
|
||||
$todo->begin = date::formatTime($todo->begin);
|
||||
$todo->end = date::formatTime($todo->end);
|
||||
|
||||
@@ -467,22 +471,23 @@ class todoModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* CreateByCycle
|
||||
* Create todo by cycle.
|
||||
*
|
||||
* @param int $todoList
|
||||
* @param array $todoList
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function createByCycle($todoList)
|
||||
public function createByCycle(array $todoList): void
|
||||
{
|
||||
$this->loadModel('action');
|
||||
$today = helper::today();
|
||||
$now = helper::now();
|
||||
$lastCycleList = $this->dao->select('*')->from(TABLE_TODO)->where('type')->eq('cycle')->andWhere('deleted')->eq('0')->andWhere('idvalue')->in(array_keys($todoList))->orderBy('date_asc')->fetchAll('idvalue');
|
||||
$activedUsers = $this->dao->select('account')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs('account', 'account');
|
||||
$today = helper::today();
|
||||
$now = helper::now();
|
||||
$cycleList = $this->todoTao->getCycleList($todoList);
|
||||
$validUsers = $this->dao->select('account')->from(TABLE_USER)->where('deleted')->eq(0)->fetchPairs('account', 'account');
|
||||
|
||||
foreach($todoList as $todoID => $todo)
|
||||
{
|
||||
if(!isset($activedUsers[$todo->account])) continue;
|
||||
if(!isset($validUsers[$todo->account])) continue;
|
||||
|
||||
$todo->config = json_decode($todo->config);
|
||||
$begin = $todo->config->begin;
|
||||
@@ -491,19 +496,7 @@ class todoModel extends model
|
||||
if(!empty($beforeDays) && $beforeDays > 0) $begin = date('Y-m-d', strtotime("$begin -{$beforeDays} days"));
|
||||
if($today < $begin or (!empty($end) && $today > $end)) continue;
|
||||
|
||||
$newTodo = new stdclass();
|
||||
$newTodo->account = $todo->account;
|
||||
$newTodo->begin = $todo->begin;
|
||||
$newTodo->end = $todo->end;
|
||||
$newTodo->type = 'cycle';
|
||||
$newTodo->idvalue = $todoID;
|
||||
$newTodo->pri = $todo->pri;
|
||||
$newTodo->name = $todo->name;
|
||||
$newTodo->desc = $todo->desc;
|
||||
$newTodo->status = 'wait';
|
||||
$newTodo->private = isset($todo->private) ? $todo->private : '';
|
||||
$newTodo->assignedTo = isset($todo->assignedTo) ? $todo->assignedTo : '';
|
||||
$newTodo->assignedBy = isset($todo->assignedBy) ? $todo->assignedBy : '';
|
||||
$newTodo = $this->todoTao->buildCycleTodo($todo);
|
||||
if(isset($todo->assignedTo) and $todo->assignedTo) $newTodo->assignedDate = $now;
|
||||
|
||||
$start = strtotime($begin);
|
||||
@@ -511,83 +504,22 @@ class todoModel extends model
|
||||
foreach(range($start, $finish, 86400) as $today)
|
||||
{
|
||||
$today = date('Y-m-d', $today);
|
||||
$lastCycle = zget($lastCycleList, $todoID, '');
|
||||
$date = '';
|
||||
$lastCycle = zget($cycleList, $todoID, '');
|
||||
|
||||
if($todo->config->type == 'day')
|
||||
{
|
||||
if(isset($todo->config->day))
|
||||
{
|
||||
$day = (int)$todo->config->day;
|
||||
if($day <= 0) continue;
|
||||
|
||||
/* If no data, judge the interval from the begin time. */
|
||||
if(empty($lastCycle))
|
||||
{
|
||||
$todayTime = new DateTime($today);
|
||||
$beginTime = new DateTime($todo->config->begin);
|
||||
$interval = $todayTime->diff($beginTime)->days;
|
||||
|
||||
if($interval != $day) continue;
|
||||
|
||||
$date = $today;
|
||||
}
|
||||
|
||||
/* If have data, judge the interval from the last cycle time. */
|
||||
if(!empty($lastCycle->date))
|
||||
{
|
||||
$todayTime = new DateTime($today);
|
||||
$lastCycleTime = new DateTime($lastCycle->date);
|
||||
$interval = $todayTime->diff($lastCycleTime)->days;
|
||||
|
||||
if($interval != $day) continue;
|
||||
|
||||
$date = date('Y-m-d', strtotime("{$lastCycle->date} +{$day} days"));
|
||||
}
|
||||
}
|
||||
if(isset($todo->config->specifiedDate))
|
||||
{
|
||||
$date = $today;
|
||||
$specifiedDate = $todo->config->specify->month + 1 . '-' . $todo->config->specify->day;
|
||||
|
||||
/* If not set cycle every year and have data, continue. */
|
||||
if(!empty($lastCycle) and !isset($todo->config->cycleYear)) continue;
|
||||
|
||||
/* If set specified date, only judge month and day. */
|
||||
if(date('m-d', strtotime($date)) != $specifiedDate) continue;
|
||||
}
|
||||
}
|
||||
elseif($todo->config->type == 'week')
|
||||
{
|
||||
$week = date('w', strtotime($today));
|
||||
if(strpos(",{$todo->config->week},", ",{$week},") !== false)
|
||||
{
|
||||
if(empty($lastCycle)) $date = $today;
|
||||
if($lastCycle and $lastCycle->date < $today) $date = $today;
|
||||
}
|
||||
}
|
||||
elseif($todo->config->type == 'month')
|
||||
{
|
||||
$day = date('j', strtotime($today));
|
||||
if(strpos(",{$todo->config->month},", ",{$day},") !== false)
|
||||
{
|
||||
if(empty($lastCycle)) $date = $today;
|
||||
if($lastCycle and $lastCycle->date < $today) $date = $today;
|
||||
}
|
||||
}
|
||||
$date = $this->todoTao->getCycleTodoDate($todo, $lastCycle, $today);
|
||||
if($date === false) continue;
|
||||
|
||||
if(!$date) continue;
|
||||
if($date < $todo->config->begin) continue;
|
||||
if($date < date('Y-m-d')) continue;
|
||||
if($date > date('Y-m-d', $finish)) continue;
|
||||
if($date < date('Y-m-d')) continue;
|
||||
if($date > date('Y-m-d', $finish)) continue;
|
||||
if(!empty($end) && $date > $end) continue;
|
||||
if($lastCycle and ($date == $lastCycle->date)) continue;
|
||||
|
||||
$newTodo->date = $date;
|
||||
|
||||
$this->dao->insert(TABLE_TODO)->data($newTodo)->exec();
|
||||
$this->todoTao->insert($newTodo);
|
||||
$this->action->create('todo', $this->dao->lastInsertID(), 'opened', '', '', $newTodo->account);
|
||||
$lastCycleList[$todoID] = $newTodo;
|
||||
$cycleList[$todoID] = $newTodo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -625,7 +557,7 @@ class todoModel extends model
|
||||
|
||||
if(($this->config->edition == 'biz' || $this->config->edition == 'max'))
|
||||
{
|
||||
$feedbackID = $this->dao->select('idvalue')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('idvalue');
|
||||
$feedbackID = $this->dao->select('objectID')->from(TABLE_TODO)->where('id')->eq($todoID)->andWhere('type')->eq('feedback')->fetch('objectID');
|
||||
if($feedbackID) $this->loadModel('feedback')->updateStatus('todo', $feedbackID, 'closed');
|
||||
}
|
||||
return true;
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ class todoTao extends todoModel
|
||||
$this->dao->insert(TABLE_TODO)->data($todo)
|
||||
->autoCheck()
|
||||
->checkIF(!in_array($todo->type, $this->config->todo->moduleList), $this->config->todo->create->requiredFields, 'notempty')
|
||||
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->exec();
|
||||
|
||||
return (int)$this->dao->lastInsertID();
|
||||
@@ -34,7 +34,7 @@ class todoTao extends todoModel
|
||||
$this->dao->update(TABLE_TODO)->data($todo)
|
||||
->autoCheck()
|
||||
->checkIF(in_array($todo->type, array('custom', 'feedback')), $this->config->todo->edit->requiredFields, 'notempty')
|
||||
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->idvalue == 0, 'idvalue', 'notempty')
|
||||
->checkIF(in_array($todo->type, $this->config->todo->moduleList) && $todo->objectID == 0, 'objectID', 'notempty')
|
||||
->where('id')->eq($todoID)
|
||||
->exec();
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ su('admin');
|
||||
function initData()
|
||||
{
|
||||
$todo = zdTable('todo');
|
||||
$todo->id->range('1-4');
|
||||
$todo->account->prefix('admin')->range('1-4');
|
||||
$todo->id->range('1-3');
|
||||
$todo->account->prefix('admin')->range('1-3');
|
||||
$todo->begin->range('1710');
|
||||
$todo->end->range('1740');
|
||||
$todo->feedback->range('0');
|
||||
@@ -16,18 +16,18 @@ function initData()
|
||||
$todo->cycle->range('0');
|
||||
$todo->idvalue->range('0');
|
||||
$todo->pri->range("3");
|
||||
$todo->name->prefix('测试待办')->range('1-4');
|
||||
$todo->name->prefix('测试待办')->range('1-3');
|
||||
$todo->desc->range('描述');
|
||||
$todo->status->range('wait');
|
||||
$todo->status->range('wait{1},doing{1},done{1}');
|
||||
$todo->private->range('0');
|
||||
$todo->assignedTo->prefix('admin')->range('1-4');
|
||||
$todo->assignedBy->prefix('admin')->range('1-4');
|
||||
$todo->finishedBy->prefix('admin')->range('1-4');
|
||||
$todo->closedBy->prefix('admin')->range('1-4');
|
||||
$todo->assignedTo->prefix('admin')->range('1-3');
|
||||
$todo->assignedBy->prefix('admin')->range('1-3');
|
||||
$todo->finishedBy->prefix('admin')->range('1-3');
|
||||
$todo->closedBy->prefix('admin')->range('1-3');
|
||||
$todo->deleted->range('0');
|
||||
$todo->vision->range('1.0');
|
||||
|
||||
$todo->gen(4);
|
||||
$todo->gen(3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,4 +54,4 @@ initData();
|
||||
|
||||
r($todo->activateTest($todoIDList[0])) && p('status') && e('wait'); // 激活一个状态为wait的todo
|
||||
r($todo->activateTest($todoIDList[1])) && p('status') && e('wait'); // 激活一个状态为doing的todo
|
||||
r($todo->activateTest($todoIDList[2])) && p('status') && e('wait'); // 激活一个状态为done的todo
|
||||
r($todo->activateTest($todoIDList[2])) && p('status') && e('wait'); // 激活一个状态为done的todo
|
||||
@@ -36,5 +36,5 @@ $except_create = array('types' => $types, 'pris' => $pris, 'names' => $names, 'd
|
||||
|
||||
$todo = new todoTest();
|
||||
|
||||
r($todo->batchCreateTest($noname_create)) && p('2006:name,desc,pri,type,idvalue;2007:name,desc,pri,type,idvalue;2008:name,desc,pri,type,idvalue') && e('批量创建待办1,desc1,1,custom,0;批量创建待办2,desc2,2,custom,0;批量创建待办3,desc4,4,custom,0'); // 批量创建有个没有名字的待办
|
||||
r($todo->batchCreateTest($except_create)) && p('2009:name,desc,pri,type,idvalue;2010:name,desc,pri,type,idvalue;2011:name,desc,pri,type,idvalue;2012:name,desc,pri,type,idvalue') && e('测试单转Bug13,desc1,1,bug,313;软件需求版本一551,desc2,2,story,1;开发任务11,desc3,3,task,1;测试单1,desc4,4,testtask,1'); // 批量创建的待办
|
||||
r($todo->batchCreateTest($noname_create)) && p('2006:name,desc,pri,type,objectID;2007:name,desc,pri,type,objectID;2008:name,desc,pri,type,objectID') && e('批量创建待办1,desc1,1,custom,0;批量创建待办2,desc2,2,custom,0;批量创建待办3,desc4,4,custom,0'); // 批量创建有个没有名字的待办
|
||||
r($todo->batchCreateTest($except_create)) && p('2009:name,desc,pri,type,objectID;2010:name,desc,pri,type,objectID;2011:name,desc,pri,type,objectID;2012:name,desc,pri,type,objectID') && e('测试单转Bug13,desc1,1,bug,313;软件需求版本一551,desc2,2,story,1;开发任务11,desc3,3,task,1;测试单1,desc4,4,testtask,1'); // 批量创建的待办
|
||||
|
||||
@@ -13,23 +13,18 @@ cid=1
|
||||
pid=1
|
||||
|
||||
*/
|
||||
function initData()
|
||||
{
|
||||
$todo = zdTable('todo');
|
||||
$todo->id->range('1');
|
||||
$todo->name->prefix("待办")->range('1');
|
||||
$todo->date->range('`2023-04-23`');
|
||||
$todo->type->range('custom');
|
||||
$todo->status->range('wait');
|
||||
$todo->gen(1, '', true);
|
||||
}
|
||||
|
||||
initData();
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('todo');
|
||||
|
||||
$todo = zdTable('todo');
|
||||
$todo->id->range('1');
|
||||
$todo->name->prefix("待办")->range('1');
|
||||
$todo->date->range('`2023-04-23`');
|
||||
$todo->type->range('custom');
|
||||
$todo->status->range('wait');
|
||||
$todo->gen(1, '', true);
|
||||
|
||||
r($tester->todo->getByID(1)) && p('status') && e('wait');
|
||||
r($tester->todo->close(1)) && p() && e(1);
|
||||
r($tester->todo->close(1)) && p() && e(1);
|
||||
r($tester->todo->getByID(1)) && p('status') && e('closed');
|
||||
|
||||
@@ -7,8 +7,8 @@ su('admin');
|
||||
function initData()
|
||||
{
|
||||
$todo = zdTable('todo');
|
||||
$todo->id->range('1-5');
|
||||
$todo->account->prefix('admin')->range('1-5');
|
||||
$todo->id->range('1-3');
|
||||
$todo->account->prefix('admin')->range('1-3');
|
||||
$todo->begin->range('1710');
|
||||
$todo->end->range('1740');
|
||||
$todo->feedback->range('0');
|
||||
@@ -16,18 +16,18 @@ function initData()
|
||||
$todo->cycle->range('0');
|
||||
$todo->idvalue->range('0');
|
||||
$todo->pri->range("3");
|
||||
$todo->name->prefix('测试待办')->range('1-5');
|
||||
$todo->name->prefix('测试待办')->range('1-3');
|
||||
$todo->desc->range('描述');
|
||||
$todo->status->range('wait');
|
||||
$todo->status->range('wait{1},doing{1},done{1}');
|
||||
$todo->private->range('0');
|
||||
$todo->assignedTo->prefix('admin')->range('1-5');
|
||||
$todo->assignedBy->prefix('admin')->range('1-5');
|
||||
$todo->finishedBy->prefix('admin')->range('1-5');
|
||||
$todo->closedBy->prefix('admin')->range('1-5');
|
||||
$todo->assignedTo->prefix('admin')->range('1-3');
|
||||
$todo->assignedBy->prefix('admin')->range('1-3');
|
||||
$todo->finishedBy->prefix('admin')->range('1-3');
|
||||
$todo->closedBy->prefix('admin')->range('1-3');
|
||||
$todo->deleted->range('0');
|
||||
$todo->vision->range('1.0');
|
||||
|
||||
$todo->gen(5);
|
||||
$todo->gen(3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -36,9 +36,12 @@ title=测试 todoModel->start();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
读取文件/var/www/html/studyProject/zin//var/www/html/studyProject/zin/module/todo/test/model/data/todo_start.yaml失败。
|
||||
- 执行todo模块的start方法,参数是1,属性status @doing
|
||||
- 执行todo模块的start方法,参数是2,属性status @doing
|
||||
- 执行todo模块的start方法,参数是1属性status @doing
|
||||
|
||||
- 执行todo模块的start方法,参数是2属性status @doing
|
||||
|
||||
- 执行todo模块的start方法,参数是3属性status @doing
|
||||
|
||||
|
||||
|
||||
*/
|
||||
@@ -47,5 +50,6 @@ $todo = new todoTest();
|
||||
|
||||
initData();
|
||||
|
||||
r($todo->startTest(1)) && p('status') && e('doing');
|
||||
r($todo->startTest(2)) && p('status') && e('doing');
|
||||
r($todo->startTest(1)) && p('status') && e('doing'); //开启一个状态为wait的todo
|
||||
r($todo->startTest(2)) && p('status') && e('doing'); //开启一个状态为doing的todo
|
||||
r($todo->startTest(3)) && p('status') && e('doing'); //开启一个状态为done的todo
|
||||
@@ -46,7 +46,7 @@ $tester->loadModel('todo');
|
||||
initData();
|
||||
|
||||
$t_upname = array('name' => 'john');
|
||||
$t_uptype = array('type' => 'bug', 'idvalue' => '1');
|
||||
$t_uptype = array('type' => 'bug', 'objectID' => '1');
|
||||
$t_unname = array('name' => 'john');
|
||||
|
||||
$todo = new todoTest();
|
||||
|
||||
@@ -270,7 +270,7 @@ class todoTest
|
||||
$todo->begin = '0830';
|
||||
$todo->end = '0900';
|
||||
$todo->account = 'admin';
|
||||
$todo->idvalue = '0';
|
||||
$todo->objectID = '0';
|
||||
$todo->vision = 'rnd';
|
||||
$todo->assignedTo = 'admin';
|
||||
$todo->assignedBy = 'admin';
|
||||
@@ -285,7 +285,7 @@ class todoTest
|
||||
|
||||
$this->objectModel->createByCycle(array($todoID => $todo));
|
||||
|
||||
$objects = $tester->dao->select('id')->from(TABLE_TODO)->where('idvalue')->eq($todoID)->andWhere('deleted')->eq('0')->fetchAll();
|
||||
$objects = $tester->dao->select('id')->from(TABLE_TODO)->where('objectID')->eq($todoID)->andWhere('deleted')->eq('0')->fetchAll();
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
echo html::select("types[$todo->id]", $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, {$todo->id}, \"{$todo->type}\", {$todo->idvalue})' class='form-control'");
|
||||
echo html::select("types[$todo->id]", $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, {$todo->id}, \"{$todo->type}\", {$todo->objectID})' class='form-control'");
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
@@ -77,39 +77,39 @@
|
||||
}
|
||||
elseif($todo->type == 'task')
|
||||
{
|
||||
echo html::select("tasks[$todo->id]", $tasks, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("tasks[$todo->id]", $tasks, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'bug')
|
||||
{
|
||||
echo html::select("bugs[$todo->id]", $bugs, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("bugs[$todo->id]", $bugs, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'story')
|
||||
{
|
||||
echo html::select("stories[$todo->id]", $storys, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("stories[$todo->id]", $storys, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'issue')
|
||||
{
|
||||
echo html::select("issues[$todo->id]", $issues, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("issues[$todo->id]", $issues, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'risk')
|
||||
{
|
||||
echo html::select("risks[$todo->id]", $risks, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("risks[$todo->id]", $risks, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'review')
|
||||
{
|
||||
echo html::select("reviews[$todo->id]", $reviews, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("reviews[$todo->id]", $reviews, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'testtask')
|
||||
{
|
||||
echo html::select("testtasks[$todo->id]", $testtasks, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("testtasks[$todo->id]", $testtasks, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'opportunity')
|
||||
{
|
||||
echo html::select("opportunities[$todo->id]", $opportunities, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("opportunities[$todo->id]", $opportunities, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
elseif($todo->type == 'feedback')
|
||||
{
|
||||
echo html::select("feedbacks[$todo->id]", $feedbacks, $todo->idvalue, 'class="form-control chosen"');
|
||||
echo html::select("feedbacks[$todo->id]", $feedbacks, $todo->objectID, 'class="form-control chosen"');
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<?php js::set('noTodo', $lang->todo->noTodo);?>
|
||||
<?php js::set('moduleList', $config->todo->moduleList)?>
|
||||
<?php js::set('objectsMethod', $config->todo->getUserObjectsMethod)?>
|
||||
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'idvalue' => $lang->todo->idvalue));?>
|
||||
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'objectID' => $lang->todo->objectID));?>
|
||||
<?php js::set('vision', $config->vision);?>
|
||||
<?php js::set('noOptions', $lang->todo->noOptions);?>
|
||||
<?php js::set('chosenType', $lang->todo->typeList);?>
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
<?php include '../../common/view/kindeditor.html.php';?>
|
||||
<?php js::set('moduleList', $config->todo->moduleList)?>
|
||||
<?php js::set('objectsMethod', $config->todo->getUserObjectsMethod)?>
|
||||
<?php js::set('idvalue', $todo->idvalue);?>
|
||||
<?php js::set('objectID', $todo->objectID);?>
|
||||
<?php js::set('defaultType', $todo->type);?>
|
||||
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'idvalue' => $lang->todo->idvalue));?>
|
||||
<?php js::set('nameBoxLabel', array('custom' => $lang->todo->name, 'objectID' => $lang->todo->objectID));?>
|
||||
<?php js::set('vision', $config->vision);?>
|
||||
<?php js::set('noOptions', $lang->todo->noOptions);?>
|
||||
<?php js::set('chosenType', $lang->todo->typeList);?>
|
||||
@@ -127,7 +127,7 @@
|
||||
<div class="row form-group">
|
||||
<label class="col-sm-1"><?php echo $lang->todo->type;?></label>
|
||||
<div class="col-sm-4 dateWidth">
|
||||
<?php echo html::select('type', $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, \"\", \"{$todo->type}\", {$todo->idvalue})' class='form-control'");?>
|
||||
<?php echo html::select('type', $lang->todo->typeList, $todo->type, "onchange='loadList(this.value, \"\", \"{$todo->type}\", {$todo->objectID})' class='form-control'");?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif;?>
|
||||
@@ -138,7 +138,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<label id='nameBoxLabel' class="col-sm-1"><?php echo ($todo->type == 'custom' or $config->vision == 'rnd') ? $lang->todo->name : $lang->todo->idvalue;?></label>
|
||||
<label id='nameBoxLabel' class="col-sm-1"><?php echo ($todo->type == 'custom' or $config->vision == 'rnd') ? $lang->todo->name : $lang->todo->objectID;?></label>
|
||||
<div class="col-sm-10">
|
||||
<div id='nameBox' class='hidden'><?php echo html::input('name', $todo->name, "class='form-control'");?></div>
|
||||
<div class='input-group title-group required'>
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
<div class='detail-title'>
|
||||
<?php
|
||||
echo $lang->todo->desc;
|
||||
if($todo->type == 'bug') common::printLink('bug', 'view', "id={$todo->idvalue}", ' BUG#' . $todo->idvalue);
|
||||
if($todo->type == 'task') common::printLink('task', 'view', "id={$todo->idvalue}", ' TASK#' . $todo->idvalue);
|
||||
if($todo->type == 'story') common::printLink('story', 'view', "id={$todo->idvalue}", ' STORY#' . $todo->idvalue);
|
||||
if($todo->type == 'bug') common::printLink('bug', 'view', "id={$todo->objectID}", ' BUG#' . $todo->objectID);
|
||||
if($todo->type == 'task') common::printLink('task', 'view', "id={$todo->objectID}", ' TASK#' . $todo->objectID);
|
||||
if($todo->type == 'story') common::printLink('story', 'view', "id={$todo->objectID}", ' STORY#' . $todo->objectID);
|
||||
?>
|
||||
</div>
|
||||
<div class='detail-content article-content'><?php echo $todo->desc;?></div>
|
||||
|
||||
+62
-8
@@ -3,6 +3,60 @@ declare(strict_types=1);
|
||||
|
||||
class todoZen extends todo
|
||||
{
|
||||
/**
|
||||
* 处理请求数据
|
||||
* Processing request data.
|
||||
*
|
||||
* @param object $formData
|
||||
* @return object|false
|
||||
*/
|
||||
protected function beforeCreate(object $formData): object|bool
|
||||
{
|
||||
$formData = $formData->remove(implode(',', $this->config->todo->moduleList) . ',uid')->stripTags($this->config->todo->editor->create['id'], $this->config->allowedTags)->get();
|
||||
|
||||
$objectID = 0;
|
||||
$hasObject = in_array($formData->type, $this->config->todo->moduleList);
|
||||
if($hasObject && $formData->type) $objectID = $formData->uid ? $formData->type : $formData->objectID;
|
||||
|
||||
$formData->account = $this->app->user->account;
|
||||
$formData->assignedTo = zget($formData, 'assignedTo', $this->app->user->account);
|
||||
$formData->assignedBy = zget($formData, 'assignedBy', $this->app->user->account);
|
||||
if($hasObject && $formData->type) $formData->objectID = $objectID;
|
||||
if($formData->status == 'done') $formData->finishedBy = $this->app->user->account;
|
||||
if($formData->status == 'done') $formData->finishedDate = helper::now();
|
||||
|
||||
if(!isset($formData->pri) and in_array($formData->type, $this->config->todo->moduleList) and $formData->type !== 'review' and $formData->type !== 'feedback')
|
||||
{
|
||||
// TODO
|
||||
$formData->pri = $this->dao->select('pri')->from($this->config->objectTables[$formData->type])->where('id')->eq($formData->objectID)->fetch('pri');
|
||||
|
||||
if($formData->pri == 'high') $formData->pri = 1;
|
||||
if($formData->pri == 'middle') $formData->pri = 2;
|
||||
if($formData->pri == 'low') $formData->pri = 3;
|
||||
}
|
||||
|
||||
if($formData->type != 'custom' and $formData->objectID)
|
||||
{
|
||||
$type = $formData->type;
|
||||
$object = $this->loadModel($type)->getByID($formData->$type);
|
||||
if(isset($object->name)) $formData->name = $object->name;
|
||||
if(isset($object->title)) $formData->name = $object->title;
|
||||
}
|
||||
|
||||
if($formData->end < $formData->begin)
|
||||
{
|
||||
dao::$errors[] = sprintf($this->lang->error->gt, $this->lang->todo->end, $this->lang->todo->begin);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!empty($formData->cycle)) $formData = $this->setCycle($formData);
|
||||
else unset($formData->config);
|
||||
|
||||
$formData = $this->loadModel('file')->processImgURL($formData, $this->config->todo->editor->create['id'], $this->post->uid);
|
||||
|
||||
return $formData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建待办
|
||||
* Create a todo.
|
||||
@@ -24,7 +78,7 @@ class todoZen extends todo
|
||||
*/
|
||||
protected function afterCreate(object $todo): object
|
||||
{
|
||||
$this->file->updateObjectID($this->post->uid, $todo->id, 'todo');
|
||||
$this->loadModel('file')->updateObjectID($this->post->uid, $todo->id, 'todo');
|
||||
|
||||
$this->loadModel('score')->create('todo', 'create', $todo->id);
|
||||
|
||||
@@ -47,20 +101,20 @@ class todoZen extends todo
|
||||
* @param object $formData
|
||||
* @return object|false
|
||||
*/
|
||||
protected function beforeEdit(int $todoID, object $formData)
|
||||
protected function beforeEdit(int $todoID, object $formData): object|false
|
||||
{
|
||||
$oldTodo = $this->dao->findById($todoID)->from(TABLE_TODO)->fetch();
|
||||
|
||||
$idvalue = 0;
|
||||
$objectID = 0;
|
||||
$rowData = $formData->rawdata;
|
||||
$objectType = $rowData->type;
|
||||
$hasObject = in_array($objectType, $this->config->todo->moduleList);
|
||||
if($hasObject && $objectType) $idvalue = $rowData->uid ? $rowData->$objectType : $rowData->idvalue;
|
||||
if($hasObject && $objectType) $objectID = $rowData->uid ? $rowData->$objectType : $rowData->objectID;
|
||||
|
||||
$todo = $formData->add('account', $oldTodo->account)
|
||||
->cleanInt('pri, begin, end, private')
|
||||
->setIF(in_array($rowData->type, array('bug', 'task', 'story')), 'name', '')
|
||||
->setIF($hasObject && $objectType, 'idvalue', $idvalue)
|
||||
->setIF($hasObject && $objectType, 'objectID', $objectID)
|
||||
->setIF($rowData->date == false, 'date', '2030-01-01')
|
||||
->setIF($rowData->begin == false, 'begin', '2400')
|
||||
->setIF($rowData->end == false, 'end', '2400')
|
||||
@@ -70,7 +124,7 @@ class todoZen extends todo
|
||||
->remove(implode(',', $this->config->todo->moduleList) . ',uid')
|
||||
->get();
|
||||
|
||||
$todo = (object) array_merge((array) $todo, (array) $rowData);
|
||||
$todo = (object) array_merge((array) $rowData, (array) $todo);
|
||||
|
||||
if(in_array($todo->type, $this->config->todo->moduleList))
|
||||
{
|
||||
@@ -196,12 +250,12 @@ class todoZen extends todo
|
||||
protected function printConfirm(object $todo): int
|
||||
{
|
||||
$confirmNote = 'confirm' . ucfirst($todo->type);
|
||||
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->idvalue");
|
||||
$confirmURL = $this->createLink($todo->type, 'view', "id=$todo->objectID");
|
||||
$okTarget = isonlybody() ? 'parent' : 'window.parent.$.apps.open';
|
||||
if($todo->type == 'bug') $app = 'qa';
|
||||
if($todo->type == 'task') $app = 'execution';
|
||||
if($todo->type == 'story') $app = 'product';
|
||||
$cancelURL = $this->server->HTTP_REFERER;
|
||||
return print(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->idvalue), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
|
||||
return print(js::confirm(sprintf($this->lang->todo->$confirmNote, $todo->objectID), $confirmURL, $cancelURL, $okTarget, 'parent', $app));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user