Merge branch 'master' of https://git.zcorp.cc/easycorp/zentaopms
This commit is contained in:
+41
-99
@@ -27,10 +27,10 @@ class block extends control
|
||||
|
||||
/**
|
||||
* Create a block under a dashboard.
|
||||
*
|
||||
* @param string $dashboard
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
* @param string $code
|
||||
* @param string $code
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -61,11 +61,11 @@ class block extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a block.
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
* @param string $code
|
||||
* Update a block.
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
* @param string $code
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
@@ -97,81 +97,39 @@ class block extends control
|
||||
$this->display();
|
||||
}
|
||||
|
||||
public function set($id, $type, $module = '')
|
||||
{
|
||||
$block = $this->block->getByID($id);
|
||||
if($block and empty($type)) $type = $block->code;
|
||||
if(isset($block->params->num) and !isset($block->params->count))
|
||||
{
|
||||
$block->params->count = $block->params->num;
|
||||
unset($block->params->num);
|
||||
}
|
||||
|
||||
if(isset($this->lang->block->moduleList[$module]))
|
||||
{
|
||||
$params = $this->block->getParams($type, $module);
|
||||
$this->view->params = json_decode($params, true);
|
||||
}
|
||||
elseif($type == 'assigntome')
|
||||
{
|
||||
$params = $this->block->getParams('assignedToMe');
|
||||
$this->view->params = json_decode($params, true);
|
||||
}
|
||||
|
||||
$this->view->source = $module;
|
||||
$this->view->type = $type;
|
||||
$this->view->id = $id;
|
||||
$this->view->block = ($block) ? $block : array();
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete block
|
||||
* Delete or hidd block by blockid.
|
||||
*
|
||||
* @param int $id
|
||||
* @param string $sys
|
||||
* @param string $type
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function delete($id, $module = 'my', $type = 'delete')
|
||||
public function delete($blockID, $type = 'delete')
|
||||
{
|
||||
if($type == 'hidden')
|
||||
{
|
||||
$this->dao->update(TABLE_BLOCK)->set('hidden')->eq(1)->where('`id`')->eq($id)->andWhere('account')->eq($this->app->user->account)->andWhere('module')->eq($module)->exec();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_BLOCK)->where('`id`')->eq($id)->andWhere('account')->eq($this->app->user->account)->andWhere('module')->eq($module)->exec();
|
||||
}
|
||||
$blockID = (int)$blockID;
|
||||
if($type == 'delete') $this->block->deleteBlock($blockID);
|
||||
if($type == 'hidden') $this->block->hidden($blockID);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->loadModel('score')->create('block', 'set');
|
||||
return $this->send(array('result' => 'success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort block.
|
||||
* Sort dashboard blocks.
|
||||
*
|
||||
* @param string $oldOrder
|
||||
* @param string $newOrder
|
||||
* @param string $module
|
||||
* @param string $orders
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function sort($orders, $module = 'my')
|
||||
public function sort($orders)
|
||||
{
|
||||
$orders = explode(',', $orders);
|
||||
$blockList = $this->block->getMyDashboard($module);
|
||||
|
||||
foreach ($orders as $order => $blockID)
|
||||
{
|
||||
$block = $blockList[$blockID];
|
||||
if(!isset($block)) continue;
|
||||
$block->order = $order;
|
||||
$this->dao->replace(TABLE_BLOCK)->data($block)->exec();
|
||||
}
|
||||
$orders = explode(',', $orders);
|
||||
foreach($orders as $order => $blockID) $this->block->setOrder($blockID, $order);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail'));
|
||||
|
||||
$this->loadModel('score')->create('block', 'set');
|
||||
return $this->send(array('result' => 'success'));
|
||||
}
|
||||
@@ -182,26 +140,22 @@ class block extends control
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function resize($id, $type, $data)
|
||||
public function resize($blockID, $type, $data)
|
||||
{
|
||||
$block = $this->block->getByID($id);
|
||||
if($block)
|
||||
{
|
||||
$field = '';
|
||||
if($type == 'vertical') $field = 'height';
|
||||
if($type == 'horizontal') $field = 'grid';
|
||||
if(empty($field)) return $this->send(array('result' => 'fail', 'code' => 400));
|
||||
$block = $this->block->getByID($blockID);
|
||||
if(!$block) return $this->send(array('result' => 'fail', 'code' => 404));
|
||||
|
||||
$block->$field = $data;
|
||||
$block->params = helper::jsonEncode($block->params);
|
||||
$this->dao->replace(TABLE_BLOCK)->data($block)->exec();
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'code' => 500));
|
||||
return $this->send(array('result' => 'success'));
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->send(array('result' => 'fail', 'code' => 404));
|
||||
}
|
||||
$field = '';
|
||||
if($type == 'vertical') $field = 'height';
|
||||
if($type == 'horizontal') $field = 'grid';
|
||||
if(empty($field)) return $this->send(array('result' => 'fail', 'code' => 400));
|
||||
|
||||
$block->$field = $data;
|
||||
$block->params = helper::jsonEncode($block->params);
|
||||
$this->block->update($block);
|
||||
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'code' => 500));
|
||||
return $this->send(array('result' => 'success'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1862,7 +1816,7 @@ class block extends control
|
||||
/* load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager(0, 3, 1);
|
||||
$this->view->projects = $this->loadModel('project')->getInfoList('all', 'id_desc', $pager, 1);
|
||||
$this->view->projects = $this->loadModel('project')->getList('all', 'id_desc', 1, $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2155,30 +2109,18 @@ class block extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax reset.
|
||||
* Reset dashboard blocks.
|
||||
*
|
||||
* @param string $module
|
||||
* @param string $confirm
|
||||
* @param string $dashboard
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function ajaxReset($module, $confirm = 'no')
|
||||
public function reset($dashboard)
|
||||
{
|
||||
if($confirm != 'yes') return print(js::confirm($this->lang->block->confirmReset, inlink('ajaxReset', "module=$module&confirm=yes")));
|
||||
$this->block->reset($dashboard);
|
||||
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
|
||||
|
||||
$this->dao->delete()->from(TABLE_BLOCK)
|
||||
->where('module')->eq($module)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->andWhere('account')->eq($this->app->user->account)
|
||||
->exec();
|
||||
|
||||
$this->dao->delete()->from(TABLE_CONFIG)
|
||||
->where('module')->eq($module)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->andWhere('owner')->eq($this->app->user->account)
|
||||
->andWhere('`key`')->eq('blockInited')
|
||||
->exec();
|
||||
return print(js::reload('parent'));
|
||||
return $this->send(array('result' => 'success'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.welcome-block {background-image: linear-gradient( 90deg, #EDF7FE 0%, #FFF 20%);}
|
||||
.border-right {position: relative;}
|
||||
.border-right::after {content: ''; position: absolute; right: 0px; width: 1px; height: 40px; background: #EEE; top: 50%; margin-top: -20px;}
|
||||
.avatar-border-one {width: 4.2rem; height: 4.2rem; background: #f4f5f3; position: relative;}
|
||||
.avatar-border-two {width: 3.6rem; height: 3.6rem; background: #F5EBDE; position: absolute;}
|
||||
.welcome-avatar {border: 2px solid #FBC962; position: absolute;}
|
||||
.tile-amount {font-size: 32px; font-weight: 700; line-height: 56px; }
|
||||
|
||||
@@ -6,3 +6,27 @@ function getForm(event)
|
||||
const url = $.createLink('block', 'create', 'dashboard='+ dashboard +'&module=' + module + '&code=' + (code ? code : ''));
|
||||
loadPage(url, '#codesRow, #paramsRow');
|
||||
}
|
||||
|
||||
function onParamsTypeChange(event)
|
||||
{
|
||||
const lang = config.clientLang;
|
||||
const $code = document.querySelector('#code');
|
||||
|
||||
if($('#module').val() == 'scrumtest' && $('#paramstype').val() != 'all')
|
||||
{
|
||||
$('#title').val($code.options[$code.selectedIndex].text);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(lang.indexOf('zh') >= 0)
|
||||
{
|
||||
const $paramstype = document.querySelector('#paramstype');
|
||||
const blockTitle = $paramstype.options[$paramstype.selectedIndex].text + of + $code.options[$code.selectedIndex].text;
|
||||
$('#title').val(blockTitle);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,6 +295,81 @@ class blockModel extends model
|
||||
return (int)$formData->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset dashboard blocks.
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function reset(string $dashboard): bool
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_BLOCK)
|
||||
->where('dashboard')->eq($dashboard)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->andWhere('account')->eq($this->app->user->account)
|
||||
->exec();
|
||||
|
||||
$this->dao->delete()->from(TABLE_CONFIG)
|
||||
->where('module')->eq($dashboard)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->andWhere('owner')->eq($this->app->user->account)
|
||||
->andWhere('`key`')->eq('blockInited')
|
||||
->exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hidden a block.
|
||||
*
|
||||
* @param int $blockID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function hidden(int $blockID): bool
|
||||
{
|
||||
$this->dao->update(TABLE_BLOCK)->set('hidden')->eq(1)
|
||||
->where('id')->eq($blockID)
|
||||
->andWhere('account')->eq($this->app->user->account)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a block.
|
||||
*
|
||||
* @param int $blockID
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function deleteBlock(int $blockID = 0): bool
|
||||
{
|
||||
$this->dao->delete()->from(TABLE_BLOCK)
|
||||
->where('id')->eq($blockID)
|
||||
->andWhere('account')->eq($this->app->user->account)
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->exec();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set block order.
|
||||
*
|
||||
* @param int $blockID
|
||||
* @param int $order
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function setOrder(int $blockID, int $order): bool
|
||||
{
|
||||
$this->dao->update(TABLE_BLOCK)->set('order')->eq($order)->where('id')->eq($blockID)->exec();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a block.
|
||||
*
|
||||
|
||||
@@ -13,8 +13,9 @@ namespace zin;
|
||||
|
||||
set::title($title);
|
||||
jsVar('dashboard', $dashboard);
|
||||
jsVar('of', $lang->block->of);
|
||||
|
||||
$paramsRows = array();
|
||||
$paramsRows = array();
|
||||
$showModules = ($dashboard == 'my' and $modules);
|
||||
$showCodes = (($showModules and $module and $codes) or $dashboard != 'my');
|
||||
|
||||
@@ -28,6 +29,7 @@ foreach($params as $key => $row)
|
||||
set::value(zget($row, 'default', '')),
|
||||
set::control(array
|
||||
(
|
||||
'id' => "params$key",
|
||||
'type' => $row['control'],
|
||||
'items' => isset($row['options']) ? $row['options'] : null
|
||||
))
|
||||
@@ -38,10 +40,11 @@ form
|
||||
(
|
||||
on::change('#module', 'getForm'),
|
||||
on::change('#code', 'getForm'),
|
||||
on::change('#paramstype', 'onParamsTypeChange'),
|
||||
formGroup
|
||||
(
|
||||
set::class($showModules ? '' : 'hidden'),
|
||||
set::value($showModules ? $block : $dashboard),
|
||||
set::value($showModules ? $code : $dashboard),
|
||||
set::label($lang->block->lblModule),
|
||||
set::name('module'),
|
||||
set::control($showModules ? array
|
||||
@@ -76,8 +79,8 @@ form
|
||||
(
|
||||
set::label($lang->block->name),
|
||||
set::name('title'),
|
||||
set::value(zget($codes, $code)),
|
||||
set::class('form-row'),
|
||||
set::value(zget($modules, $module, '') . zget($codes, $code, '')),
|
||||
set::control('input')
|
||||
),
|
||||
$paramsRows,
|
||||
|
||||
@@ -30,9 +30,9 @@ foreach($longBlocks as $index => $block)
|
||||
([
|
||||
['text' => $lang->block->refresh, 'url' => ''],
|
||||
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "blockID=$block->id"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->hidden, 'url' => ''],
|
||||
['text' => $lang->block->hidden, 'url' => $this->createLink("block", "delete", "blockID=$block->id&type=hidden")],
|
||||
['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "create", "dashboard=$dashboard"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->reset, 'url' => ''],
|
||||
['text' => $lang->block->reset, 'url' => $this->createLink("block", "reset", "dashboard=$dashboard")],
|
||||
]),
|
||||
)
|
||||
)
|
||||
@@ -78,9 +78,9 @@ foreach($shortBlocks as $index => $block)
|
||||
([
|
||||
['text' => $lang->block->refresh, 'url' => ''],
|
||||
['text' => $lang->edit, 'url' => $this->createLink("block", "edit", "blockID=$block->id"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->hidden, 'url' => ''],
|
||||
['text' => $lang->block->hidden, 'url' => $this->createLink("block", "delete", "blockID=$block->id&type=hidden")],
|
||||
['text' => $lang->block->createBlock, 'url' => $this->createLink("block", "create", "dashboard=$dashboard"), 'data-toggle' => 'modal'],
|
||||
['text' => $lang->block->reset, 'url' => ''],
|
||||
['text' => $lang->block->reset, 'url' => $this->createLink("block", "reset", "dashboard=$dashboard")],
|
||||
]),
|
||||
)
|
||||
)
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The welcome view 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 https://www.zentao.net
|
||||
*/
|
||||
|
||||
namespace zin;
|
||||
|
||||
panel
|
||||
(
|
||||
set('class', 'welcome-block'),
|
||||
div
|
||||
(
|
||||
setClass('flex'),
|
||||
col
|
||||
(
|
||||
setStyle(['width' => '20%', 'height' => '176px']),
|
||||
set('class', 'border-right p-3'),
|
||||
set('align', 'center'),
|
||||
center
|
||||
(
|
||||
set('class', 'font-bold'),
|
||||
sprintf($lang->block->welcomeList[$welcomeType], $app->user->realname)
|
||||
),
|
||||
center
|
||||
(
|
||||
set('class', 'rounded-full avatar-border-one m-5'),
|
||||
center
|
||||
(
|
||||
set('class', 'rounded-full avatar-border-two'),
|
||||
userAvatar
|
||||
(
|
||||
set('size', 'lg'),
|
||||
set('class', 'welcome-avatar'),
|
||||
set('user', $this->app->user)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
cell
|
||||
(
|
||||
set('width', '45%'),
|
||||
set('class', 'border-right p-3'),
|
||||
div
|
||||
(
|
||||
set('class', 'font-bold'),
|
||||
'待我评审:'
|
||||
),
|
||||
div
|
||||
(
|
||||
setClass('flex items-center justify-around pt-6'),
|
||||
center
|
||||
(
|
||||
col
|
||||
(
|
||||
set('justify', 'center'),
|
||||
set('class', 'text-center'),
|
||||
span
|
||||
(
|
||||
set('class', 'tile-amount text-primary'),
|
||||
81
|
||||
),
|
||||
span('研发需求数')
|
||||
)
|
||||
),
|
||||
center
|
||||
(
|
||||
col
|
||||
(
|
||||
set('justify', 'center'),
|
||||
set('class', 'text-center'),
|
||||
span
|
||||
(
|
||||
set('class', 'tile-amount text-primary'),
|
||||
81
|
||||
),
|
||||
span('研发需求数')
|
||||
)
|
||||
),
|
||||
center
|
||||
(
|
||||
col
|
||||
(
|
||||
set('justify', 'center'),
|
||||
set('class', 'text-center'),
|
||||
span
|
||||
(
|
||||
set('class', 'tile-amount text-primary'),
|
||||
81
|
||||
),
|
||||
span('研发需求数')
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
cell
|
||||
(
|
||||
set::width('35%'),
|
||||
set('class', 'p-3'),
|
||||
div
|
||||
(
|
||||
set('class', 'font-bold'),
|
||||
'待我评审:'
|
||||
),
|
||||
div
|
||||
(
|
||||
setClass('flex items-center justify-around pt-6'),
|
||||
center
|
||||
(
|
||||
col
|
||||
(
|
||||
set('justify', 'center'),
|
||||
set('class', 'text-center'),
|
||||
span
|
||||
(
|
||||
set('class', 'tile-amount text-primary'),
|
||||
81
|
||||
),
|
||||
span('研发需求数')
|
||||
)
|
||||
),
|
||||
center
|
||||
(
|
||||
col
|
||||
(
|
||||
set('justify', 'center'),
|
||||
set('class', 'text-center'),
|
||||
span
|
||||
(
|
||||
set('class', 'tile-amount text-primary'),
|
||||
81
|
||||
),
|
||||
span('研发需求数')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -2,8 +2,8 @@
|
||||
class blockZen extends block
|
||||
{
|
||||
/**
|
||||
* Get module options when adding or editing blocks.
|
||||
* 添加或编辑区块时获取可使用的模块选项
|
||||
* Get module options when adding or editing blocks.
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @access protected
|
||||
@@ -51,8 +51,8 @@ class blockZen extends block
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block options when adding or editing blocks.
|
||||
* 添加或编辑区块时获取可使用的区块选项
|
||||
* Get block options when adding or editing blocks.
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
@@ -112,12 +112,12 @@ class blockZen extends block
|
||||
}
|
||||
|
||||
/**
|
||||
* Get other form items when adding or editing blocks
|
||||
* 添加或编辑区块时获取其他表单项
|
||||
* Get other form items when adding or editing blocks
|
||||
*
|
||||
* @param string $dashboard
|
||||
* @param string $module
|
||||
* @param string $block
|
||||
* @param string $code
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -37,8 +37,9 @@ $config->project->form->edit['acl'] = array('type' => 'string', 'required
|
||||
$config->project->form->edit['whitelist'] = array('type' => 'array', 'required' => false, 'default' => '', 'filter' => 'join');
|
||||
$config->project->form->edit['auth'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->edit['model'] = array('type' => 'string', 'required' => false, 'default' => '');
|
||||
$config->project->form->edit['plans'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->edit['products'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->edit['plans'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->edit['products'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
$config->project->form->edit['product'] = array('type' => 'array', 'required' => false, 'default' => '');
|
||||
|
||||
$config->project->form->start['realBegan'] = array('type' => 'date', 'required' => true, 'filter' => 'trim');
|
||||
|
||||
|
||||
@@ -73,8 +73,7 @@ class project extends control
|
||||
|
||||
if(isset($fields['hasProduct'])) $fields['hasProduct'] = $projectLang->type;
|
||||
|
||||
$involved = $this->cookie->involved ? $this->cookie->involved : 0;
|
||||
$projects = $this->project->getInfoList($status, $orderBy, '', $involved);
|
||||
$projects = $this->project->getList($status, $orderBy, null);
|
||||
$users = $this->loadModel('user')->getPairs('noletter');
|
||||
|
||||
$this->loadModel('product');
|
||||
@@ -316,7 +315,7 @@ class project extends control
|
||||
if($project->model == 'kanban' and $this->config->vision != 'lite')
|
||||
{
|
||||
/* Load pager and get kanban list. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$this->app->loadClass('pager', true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
$kanbanList = $this->loadModel('execution')->getList($projectID, 'all', $browseType, 0, 0, 0, $pager);
|
||||
@@ -370,7 +369,7 @@ class project extends control
|
||||
$browseType = strtolower($browseType);
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$this->app->loadClass('pager', true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
$queryID = ($browseType == 'bysearch') ? (int)$param : 0;
|
||||
@@ -519,9 +518,8 @@ class project extends control
|
||||
$this->loadModel('program');
|
||||
$this->loadModel('execution');
|
||||
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
$programID = $project->parent;
|
||||
$projectID = (int)$projectID;
|
||||
$project = $this->project->getByID($projectID);
|
||||
$this->project->setMenu($projectID);
|
||||
|
||||
if($project->model == 'kanban')
|
||||
@@ -736,7 +734,7 @@ class project extends control
|
||||
}
|
||||
|
||||
/* Load pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$this->app->loadClass('pager', true);
|
||||
$pager = new pager(0, 30, 1);
|
||||
|
||||
/* Check exist extend fields. */
|
||||
@@ -865,8 +863,8 @@ class project extends control
|
||||
$orderBy = $direction == 'next' ? 'date_desc' : 'date_asc';
|
||||
|
||||
/* Set the pager. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$pager = new pager($recTotal, $recPerPage = 50, $pageID = 1);
|
||||
$this->app->loadClass('pager', true);
|
||||
$pager = new pager($recTotal, 50, 1);
|
||||
|
||||
/* Set the user and type. */
|
||||
$account = 'all';
|
||||
@@ -934,7 +932,7 @@ class project extends control
|
||||
if(!empty($project->model) and $project->model == 'kanban' and !(defined('RUN_MODE') and RUN_MODE == 'api')) return print(js::locate($this->createLink('project', 'index', "projectID=$projectID")));
|
||||
|
||||
/* Load pager and get tasks. */
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$this->app->loadClass('pager', true);
|
||||
$pager = new pager($recTotal, $recPerPage, $pageID);
|
||||
|
||||
$allExecution = $this->execution->getStatData($projectID, 'all');
|
||||
|
||||
+13
-25
@@ -47,10 +47,8 @@ class projectModel extends model
|
||||
{
|
||||
if(defined('TUTORIAL')) return true;
|
||||
|
||||
echo(js::alert($this->lang->project->accessDenied));
|
||||
$this->session->set('project', '');
|
||||
|
||||
return print(js::locate(helper::createLink('project', 'index')));
|
||||
return print(js::alert($this->lang->project->accessDenied) . js::locate(helper::createLink('project', 'index')));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,8 +146,8 @@ class projectModel extends model
|
||||
*/
|
||||
public function getMultiLinkedProducts($projectID)
|
||||
{
|
||||
$linkedProducts = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs();
|
||||
$multiLinkedProducts = $this->dao->select('t3.id,t3.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
$linkedProducts = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs();
|
||||
return $this->dao->select('t3.id,t3.name')->from(TABLE_PROJECTPRODUCT)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.project = t2.id')
|
||||
->leftJoin(TABLE_PRODUCT)->alias('t3')->on('t1.product = t3.id')
|
||||
->where('t1.product')->in($linkedProducts)
|
||||
@@ -158,8 +156,6 @@ class projectModel extends model
|
||||
->andWhere('t2.deleted')->eq('0')
|
||||
->andWhere('t3.deleted')->eq('0')
|
||||
->fetchPairs('id', 'name');
|
||||
|
||||
return $multiLinkedProducts;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -235,7 +231,8 @@ class projectModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project info.
|
||||
* 根据状态和和我参与的查询项目列表。
|
||||
* Get project list by status and with my participation.
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $orderBy
|
||||
@@ -244,19 +241,14 @@ class projectModel extends model
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getInfoList($status = 'undone', $orderBy = 'order_desc', $pager = null, $involved = 0)
|
||||
public function getList($status = 'undone', $orderBy = 'order_desc', $pager = null, $involved = 0)
|
||||
{
|
||||
/* Init vars. */
|
||||
$projects = $this->loadModel('program')->getProjectList(0, $status, 0, $orderBy, $pager, 0, $involved);
|
||||
$projects = $this->projectTao->fetchProjectList($status, $orderBy, $involved, $pager);
|
||||
if(empty($projects)) return array();
|
||||
|
||||
$projectIdList = array_keys($projects);
|
||||
$teams = $this->dao->select('t1.root, count(t1.id) as count')->from(TABLE_TEAM)->alias('t1')
|
||||
->leftJoin(TABLE_USER)->alias('t2')->on('t1.account=t2.account')
|
||||
->where('t1.root')->in($projectIdList)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->groupBy('t1.root')
|
||||
->fetchAll('root');
|
||||
$teams = $this->projectTao->fetchMemberCountByIdList($projectIdList);
|
||||
|
||||
$estimates = $this->dao->select("t2.project as project, sum(estimate) as estimate")->from(TABLE_TASK)->alias('t1')
|
||||
->leftJoin(TABLE_PROJECT)->alias('t2')->on('t1.execution = t2.id')
|
||||
@@ -267,7 +259,7 @@ class projectModel extends model
|
||||
->groupBy('t2.project')
|
||||
->fetchAll('project');
|
||||
|
||||
$this->app->loadClass('pager', $static = true);
|
||||
$this->app->loadClass('pager', true);
|
||||
foreach($projects as $projectID => $project)
|
||||
{
|
||||
$orderBy = $project->model == 'waterfall' ? 'id_asc' : 'id_desc';
|
||||
@@ -868,12 +860,11 @@ class projectModel extends model
|
||||
->orderBy('grade desc')
|
||||
->fetch();
|
||||
|
||||
$projects = $this->dao->select('id')->from(TABLE_PROJECT)
|
||||
return $this->dao->select('id')->from(TABLE_PROJECT)
|
||||
->where('type')->eq('project')
|
||||
->andWhere('deleted')->eq(0)
|
||||
->andWhere('path')->like("{$parentProgram->path}%")
|
||||
->fetchPairs('id');
|
||||
return $projects;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1398,7 +1389,7 @@ class projectModel extends model
|
||||
$this->lang->error->unique = $this->lang->error->repeat;
|
||||
|
||||
if(!empty($executionsCount) and $oldProject->multiple) $this->checkDatesValidByProject($projectID ,$project);
|
||||
$this->projectTao->doUpdate($projectID, $project);
|
||||
$this->projectTao->doUpdate($projectID, $project, $oldProject);
|
||||
if(dao::isError()) return false;
|
||||
|
||||
if(!$oldProject->hasProduct and ($oldProject->name != $project->name or $oldProject->parent != $project->parent or $oldProject->acl != $project->acl)) $this->updateShadowProduct($project);
|
||||
@@ -1548,7 +1539,7 @@ class projectModel extends model
|
||||
$parentID = !isset($project->parent) ? $oldProject->parent : $project->parent;
|
||||
|
||||
$this->dao->update(TABLE_PROJECT)->data($project)
|
||||
->autoCheck($skipFields = 'begin,end')
|
||||
->autoCheck('begin,end')
|
||||
->batchCheck($this->config->project->edit->requiredFields, 'notempty')
|
||||
->checkIF($project->begin != '', 'begin', 'date')
|
||||
->checkIF($project->end != '', 'end', 'date')
|
||||
@@ -3065,10 +3056,7 @@ class projectModel extends model
|
||||
{
|
||||
foreach($plans as $planList)
|
||||
{
|
||||
foreach($planList as $planIDList)
|
||||
{
|
||||
foreach($planIDList as $planID) $newPlans[$planID] = $planID;
|
||||
}
|
||||
foreach($planList as $planID) $newPlans[$planID] = $planID;
|
||||
}
|
||||
}
|
||||
if(empty($newPlans)) return;
|
||||
|
||||
+62
-2
@@ -101,13 +101,14 @@ class projectTao extends projectModel
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
* @param object $oldProject
|
||||
* @access protected
|
||||
* @return bool
|
||||
*/
|
||||
protected function doUpdate(int $projectID ,object $project): bool
|
||||
protected function doUpdate(int $projectID ,object $project, object $oldProject): bool
|
||||
{
|
||||
$this->dao->update(TABLE_PROJECT)->data($project)
|
||||
->autoCheck($skipFields = 'begin,end')
|
||||
->autoCheck('begin,end')
|
||||
->batchcheck($requiredFields, 'notempty')
|
||||
->checkIF($project->begin != '', 'begin', 'date')
|
||||
->checkIF($project->end != '', 'end', 'date')
|
||||
@@ -529,4 +530,63 @@ class projectTao extends projectModel
|
||||
$oldExecutionProducts = $this->dao->select('project,product')->from(TABLE_PROJECTPRODUCT)->where('project')->in($executionIDs)->fetchGroup('project', 'product');
|
||||
return !dao::isError();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据状态和和我参与的查询项目列表。
|
||||
* Get project list by status and with my participation.
|
||||
*
|
||||
* @param string $status
|
||||
* @param string $orderBy
|
||||
* @param int $involved
|
||||
* @param object $pager
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchProjectList(string $status, string $orderBy, int $involved, object|null $pager): array
|
||||
{
|
||||
return $this->dao->select('DISTINCT t1.*')->from(TABLE_PROJECT)->alias('t1')
|
||||
->leftJoin(TABLE_TEAM)->alias('t2')->on('t1.id=t2.root')
|
||||
->leftJoin(TABLE_STAKEHOLDER)->alias('t3')->on('t1.id=t3.objectID')
|
||||
->where('t1.deleted')->eq('0')
|
||||
->andWhere('t1.vision')->eq($this->config->vision)
|
||||
->andWhere('t1.type')->eq('project')
|
||||
->beginIF(!in_array($status, array('all', 'undone', 'review', 'unclosed'), true))->andWhere('t1.status')->eq($status)->fi()
|
||||
->beginIF($status == 'undone' or $status == 'unclosed')->andWhere('t1.status')->in('wait,doing')->fi()
|
||||
->beginIF($status == 'review')
|
||||
->andWhere("FIND_IN_SET('{$this->app->user->account}', t1.reviewers)")
|
||||
->andWhere('t1.reviewStatus')->eq('doing')
|
||||
->fi()
|
||||
->beginIF($this->cookie->involved or $involved)
|
||||
->andWhere('t2.type')->eq('project')
|
||||
->andWhere('t1.openedBy', true)->eq($this->app->user->account)
|
||||
->orWhere('t1.PM')->eq($this->app->user->account)
|
||||
->orWhere('t2.account')->eq($this->app->user->account)
|
||||
->orWhere('(t3.user')->eq($this->app->user->account)
|
||||
->andWhere('t3.deleted')->eq(0)
|
||||
->markRight(1)
|
||||
->orWhere("CONCAT(',', t1.whitelist, ',')")->like("%,{$this->app->user->account},%")
|
||||
->markRight(1)
|
||||
->fi()
|
||||
->orderBy($orderBy)
|
||||
->page($pager, 't1.id')
|
||||
->fetchAll('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据项目ID列表查询团队成员数量。
|
||||
* Get project team member count by project id list.
|
||||
*
|
||||
* @param array $projectIdList
|
||||
* @access protected
|
||||
* @return array
|
||||
*/
|
||||
protected function fetchMemberCountByIdList(array $projectIdList): array
|
||||
{
|
||||
return $this->dao->select('t1.root, count(t1.id) as count')->from(TABLE_TEAM)->alias('t1')
|
||||
->leftJoin(TABLE_USER)->alias('t2')->on('t1.account=t2.account')
|
||||
->where('t1.root')->in($projectIdList)
|
||||
->andWhere('t2.deleted')->eq(0)
|
||||
->groupBy('t1.root')
|
||||
->fetchAll('root');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,32 +2,27 @@
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
su('admin');
|
||||
zdTable('project')->gen(90);
|
||||
|
||||
/**
|
||||
|
||||
title=测试 projectModel::getInfoList;
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
查询正在进行的项目数量 >> 44
|
||||
查询wait状态的Id为11的项目名称 >> 项目1
|
||||
查询暂停状态的项目数量 >> 11
|
||||
查询关闭状态的项目数量 >> 11
|
||||
查询所有状态的项目数量 >> 110
|
||||
|
||||
*/
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('project');
|
||||
|
||||
$doingProjects = $tester->project->getInfoList('doing');
|
||||
$waitProjects = $tester->project->getInfoList('wait');
|
||||
$suspendedProjects = $tester->project->getInfoList('suspended');
|
||||
$closedProjects = $tester->project->getInfoList('closed');
|
||||
$allProjects = $tester->project->getInfoList('all');
|
||||
$doingProjects = $tester->project->getList('doing');
|
||||
$waitProjects = $tester->project->getList('wait');
|
||||
$suspendedProjects = $tester->project->getList('suspended');
|
||||
$closedProjects = $tester->project->getList('closed');
|
||||
$allProjects = $tester->project->getList('all');
|
||||
|
||||
r(count($doingProjects)) && p() && e('44'); //查询正在进行的项目数量
|
||||
r($waitProjects) && p('11:name') && e('项目1'); //查询wait状态的Id为11的项目名称
|
||||
r(count($suspendedProjects)) && p() && e('11'); //查询暂停状态的项目数量
|
||||
r(count($closedProjects)) && p() && e('11'); //查询关闭状态的项目数量
|
||||
r(count($allProjects)) && p() && e('110'); //查询所有状态的项目数量
|
||||
r(count($allProjects)) && p() && e('90'); //查询所有状态的项目数量
|
||||
@@ -162,10 +162,10 @@ class Project
|
||||
/**
|
||||
* Activate a project.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
* @access public
|
||||
* @return array $changes
|
||||
* @return array
|
||||
*/
|
||||
public function activate($projectID, $project)
|
||||
{
|
||||
@@ -175,8 +175,8 @@ class Project
|
||||
/**
|
||||
* Do activate a project.
|
||||
*
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
* @param int $projectID
|
||||
* @param object $project
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
@@ -190,7 +190,7 @@ class Project
|
||||
*
|
||||
* @param int $budget
|
||||
* @access public
|
||||
* @return int|string $projectBudget
|
||||
* @return int|string
|
||||
*/
|
||||
public function getBudgetWithUnit($budget)
|
||||
{
|
||||
@@ -202,13 +202,27 @@ class Project
|
||||
*
|
||||
* @param int $budget
|
||||
* @access public
|
||||
* @return int|string $projectBudget
|
||||
* @return int|string
|
||||
*/
|
||||
public function addProjectAdminTest($projectID)
|
||||
{
|
||||
global $tester;
|
||||
$tester->loadModel('project')->addProjectAdmin($projectID);
|
||||
$this->project->addProjectAdmin($projectID);
|
||||
|
||||
return $tester->dao->select('*')->from(TABLE_PROJECTADMIN)->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test fetchProjectList function.
|
||||
*
|
||||
* @param int $status
|
||||
* @param string $orderBy
|
||||
* @param int $involved
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function testFetchProjectList($status, $involved = 0)
|
||||
{
|
||||
$projects = $this->project->fetchProjectList($status, 'id_desc', $involved, null);
|
||||
return $projects;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/project.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('project');
|
||||
$project->id->range('11-19');
|
||||
$project->project->range('11-19');
|
||||
$project->name->prefix("项目")->range('11-19');
|
||||
$project->code->prefix("project")->range('11-19');
|
||||
$project->model->range("scrum");
|
||||
$project->auth->range("[]");
|
||||
$project->path->range("[]");
|
||||
$project->type->range("project");
|
||||
$project->grade->range("1");
|
||||
$project->days->range("1");
|
||||
$project->status->range("wait,doing,suspended,closed");
|
||||
$project->desc->range("[]");
|
||||
$project->budget->range("100000,200000");
|
||||
$project->budgetUnit->range("CNY");
|
||||
$project->percent->range("0-0");
|
||||
$project->openedDate->range("`2023-05-01 10:00:10`");
|
||||
$project->gen(9);
|
||||
|
||||
zdTable('team')->gen(10);
|
||||
zdTable('user')->gen(10);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 projectModel::fetchProjectList();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
|
||||
*/
|
||||
|
||||
initData();
|
||||
$noneIDList = array();
|
||||
$wrongIDList = array('1', '2');
|
||||
$realIDList = array('11', '12');
|
||||
|
||||
global $tester;
|
||||
$projectTester = $tester->loadModel('project');
|
||||
r($projectTester->fetchMemberCountByIdList($noneIDList)) && p() && e('0'); // 查询没有项目ID的情况
|
||||
r($projectTester->fetchMemberCountByIdList($wrongIDList)) && p() && e('0'); // 查询错误ID的情况
|
||||
r($projectTester->fetchMemberCountByIdList($realIDList)) && p('11:count') && e('1'); // 查询正常ID的情况
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/project.class.php';
|
||||
su('admin');
|
||||
|
||||
function initData()
|
||||
{
|
||||
$project = zdTable('project');
|
||||
$project->id->range('11-19');
|
||||
$project->project->range('11-19');
|
||||
$project->name->prefix("项目")->range('11-19');
|
||||
$project->code->prefix("project")->range('11-19');
|
||||
$project->model->range("scrum");
|
||||
$project->auth->range("[]");
|
||||
$project->path->range("[]");
|
||||
$project->type->range("project");
|
||||
$project->grade->range("1");
|
||||
$project->days->range("1");
|
||||
$project->status->range("wait,doing,suspended,closed");
|
||||
$project->desc->range("[]");
|
||||
$project->budget->range("100000,200000");
|
||||
$project->budgetUnit->range("CNY");
|
||||
$project->percent->range("0-0");
|
||||
$project->openedDate->range("`2023-05-01 10:00:10`");
|
||||
$project->gen(9);
|
||||
|
||||
zdTable('team')->gen(10);
|
||||
|
||||
$stakeholder = zdTable('stakeholder');
|
||||
$stakeholder->id->range('1-9');
|
||||
$stakeholder->objectID->range('11-19');
|
||||
$stakeholder->objectType->range('program,project');
|
||||
$stakeholder->user->range("admin");
|
||||
$stakeholder->type->range("inside");
|
||||
$stakeholder->from->range("[]");
|
||||
$stakeholder->createdBy->range("admin");
|
||||
$stakeholder->createdDate->range("`2023-05-01 10:00:10`");
|
||||
$stakeholder->gen(9);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
title=测试 projectModel::fetchProjectList();
|
||||
timeout=0
|
||||
cid=1
|
||||
|
||||
|
||||
*/
|
||||
|
||||
initData();
|
||||
$statusList = array('', 'all', 'undone', 'unclosed', 'error');
|
||||
|
||||
$projectTester = new Project();
|
||||
r($projectTester->testFetchProjectList($statusList[0])) && p() && e('0'); // 查询状态为空的项目
|
||||
r(count($projectTester->testFetchProjectList($statusList[1]))) && p() && e('9'); // 获取所有项目数量
|
||||
r($projectTester->testFetchProjectList($statusList[2])) && p('11:code') && e('project11'); // 查询未完成的第一个项目的code
|
||||
r($projectTester->testFetchProjectList($statusList[3], 1)) && p('12:name') && e('项目12'); // 获取我参与的一个项目的项目名
|
||||
r($projectTester->testFetchProjectList($statusList[4])) && p() && e('0'); // 获取错误类型的项目
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
helper::import(dirname(__FILE__) . 'config/form.php');
|
||||
helper::import(dirname(dirname(dirname(__FILE__))) . '/lib/date/date.class.php');
|
||||
|
||||
$config->todo = new stdclass();
|
||||
$config->todo->batchCreate = 8;
|
||||
@@ -49,3 +50,18 @@ $config->todo->sessionUri['bugList'] = 'qa';
|
||||
$config->todo->sessionUri['taskList'] = 'execution';
|
||||
$config->todo->sessionUri['storyList'] = 'product';
|
||||
$config->todo->sessionUri['testtaskList'] = 'qa';
|
||||
|
||||
$config->todo->dateRange = array();
|
||||
$config->todo->dateRange['all'] = array('begin' => '1970-01-01', 'end' => '2109-01-01');
|
||||
$config->todo->dateRange['assignedtoother'] = array('begin' => '1970-01-01', 'end' => '2109-01-01');
|
||||
$config->todo->dateRange['today'] = array('begin' => date::today(), 'end' => date::today());
|
||||
$config->todo->dateRange['future'] = array('begin' => '2030-01-01', 'end' => '2030-01-01');
|
||||
$config->todo->dateRange['before'] = array('begin' => '1970-01-01', 'end' => date::today());
|
||||
$config->todo->dateRange['cycle'] = array('begin' => '', 'end' => '');
|
||||
$config->todo->dateRange['yesterday'] = array('begin' => date::yesterday(), 'end' => date::yesterday());
|
||||
$config->todo->dateRange['thisweek'] = array('begin' => date::getThisWeek()['begin'], 'end' => date::getThisWeek()['end']);
|
||||
$config->todo->dateRange['lastweek'] = array('begin' => date::getLastWeek()['begin'], 'end' => date::getLastWeek()['end']);
|
||||
$config->todo->dateRange['thismonth'] = array('begin' => date::getThisMonth()['begin'], 'end' => date::getThisMonth()['end']);
|
||||
$config->todo->dateRange['lastmonth'] = array('begin' => date::getLastMonth()['begin'], 'end' => date::getLastMonth()['end']);
|
||||
$config->todo->dateRange['thisseason'] = array('begin' => date::getThisSeason()['begin'], 'end' => date::getThisSeason()['end']);
|
||||
$config->todo->dateRange['thisyear'] = array('begin' => date::getThisYear()['begin'], 'end' => date::getThisYear()['end']);
|
||||
|
||||
+8
-26
@@ -73,15 +73,17 @@ class todo extends control
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch create todo
|
||||
* 批量创建待办。
|
||||
* Batch create todo.
|
||||
*
|
||||
* @param string $date
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function batchCreate($date = 'today')
|
||||
public function batchCreate(string $date = 'today')
|
||||
{
|
||||
if($date == 'today') $date = date(DT_DATE1, time());
|
||||
|
||||
if(!empty($_POST))
|
||||
{
|
||||
$todoIDList = $this->todo->batchCreate();
|
||||
@@ -89,37 +91,17 @@ class todo extends control
|
||||
|
||||
/* Locate the browser. */
|
||||
$date = str_replace('-', '', $this->post->date);
|
||||
if($date == '')
|
||||
{
|
||||
$date = 'future';
|
||||
}
|
||||
else if($date == date('Ymd'))
|
||||
{
|
||||
$date= 'today';
|
||||
}
|
||||
if($date == '') $date = 'future';
|
||||
if($date == date('Ymd')) $date= 'today';
|
||||
|
||||
if($this->viewType == 'json') return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'idList' => $todoIDList));
|
||||
if(isonlybody()) return print(js::reload('parent.parent'));
|
||||
return print(js::locate($this->createLink('my', 'todo', "type=$date"), 'parent'));
|
||||
return print(js::locate($this->createLink('my', 'todo', "type={$date}"), 'parent'));
|
||||
}
|
||||
|
||||
unset($this->lang->todo->typeList['cycle']);
|
||||
|
||||
/* Set Custom*/
|
||||
foreach(explode(',', $this->config->todo->list->customBatchCreateFields) as $field) $customFields[$field] = $this->lang->todo->$field;
|
||||
|
||||
$this->view->customFields = $customFields;
|
||||
$this->view->showFields = $this->config->todo->custom->batchCreateFields;
|
||||
|
||||
$this->view->title = $this->lang->todo->common . $this->lang->colon . $this->lang->todo->batchCreate;
|
||||
$this->view->position[] = $this->lang->todo->common;
|
||||
$this->view->position[] = $this->lang->todo->batchCreate;
|
||||
$this->view->date = (int)$date == 0 ? $date : date('Y-m-d', strtotime($date));
|
||||
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
|
||||
$this->view->time = date::now();
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted|noempty');
|
||||
|
||||
$this->display();
|
||||
$this->todoZen->buildBatchCreateView($date);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.private-row .checkbox-primary {margin-top: 5px;}
|
||||
.every-checkbox .checkbox-primary {width: 50px;}
|
||||
.cycle-config .tab-content>.tab-pane {padding-left: 0; padding-right: 0;}
|
||||
.cycle-config .tab-content>.tab-pane:first-child,
|
||||
.cycle-config .tab-content>.input-group {width: 44.5%;}
|
||||
.switch-time {min-height: 32px;}
|
||||
.form-row .form-group.align-center {align-items: center;}
|
||||
#nameInputBox {width: 80%;}
|
||||
#nameInputBox .form-control {width: 99.8%;}
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* 切换日期选择的禁用状态。
|
||||
* Toggle the disabled state of the date select.
|
||||
*
|
||||
* @param object switcher
|
||||
* @return void
|
||||
*/
|
||||
function toggleDateTodo(switcher)
|
||||
{
|
||||
$('#date').prop('disabled', switcher.checked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data.
|
||||
* @param type $type Type of selected todo.
|
||||
* @param id $id ID of selected todo.
|
||||
* @param objectID $objectID ID of the closed todo type.
|
||||
* @return void
|
||||
*/
|
||||
function loadList(type, id, objectID)
|
||||
{
|
||||
if(id)
|
||||
{
|
||||
divClass = '.name-box' + id;
|
||||
divID = '#nameBox' + id;
|
||||
}
|
||||
else
|
||||
{
|
||||
divClass = '.name-box';
|
||||
divID = '#nameBox';
|
||||
}
|
||||
id = id ? id : '';
|
||||
var param = 'userID=' + userID + '&id=' + id;
|
||||
if(type == "task") param += '&status=wait,doing';
|
||||
if(defaultType && type == defaultType && objectID != 0) param += '&objectID=' + objectID;
|
||||
|
||||
if(moduleList.indexOf(type) !== -1)
|
||||
{
|
||||
link = '/index.php?m=' + type + '&f=' + objectsMethod[type] + '&' + param + '&t=html';
|
||||
$.get(link, function(data, status)
|
||||
{
|
||||
if(data.length != 0)
|
||||
{
|
||||
$(divClass).find('#nameInputBox').html(data).find('select').chosen();
|
||||
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
|
||||
{
|
||||
$(divClass).html("<select id="+ type +" class='form-control'></select>").find('select').chosen();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
$(divClass).html($(divID).html());
|
||||
}
|
||||
|
||||
if(nameBoxLabel) return;
|
||||
var formLabel = type == 'custom' ||(vision && vision == 'rnd') ? nameBoxLabel.custom : nameBoxLabel.objectID;
|
||||
$('#nameBox .form-label').text(formLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择开始时间后,自动给出默认终止时间。
|
||||
* After selecting the start time, the default end time is automatically given.
|
||||
*
|
||||
* @return viod
|
||||
*/
|
||||
function selectNext()
|
||||
{
|
||||
$("#end ")[0].selectedIndex = $("#begin ")[0].selectedIndex + 3;
|
||||
$('#end').trigger('chosen:updated');
|
||||
}
|
||||
|
||||
function setBeginsAndEnds(i, beginOrEnd)
|
||||
{
|
||||
if(!i)
|
||||
{
|
||||
for(j = 0; j < batchCreateNum; j++)
|
||||
{
|
||||
if(j != 0) $("#begins" + j)[0].selectedIndex = $("#ends" + (j - 1))[0].selectedIndex;
|
||||
$("#ends" + j)[0].selectedIndex = $("#begins" + j)[0].selectedIndex + 3;
|
||||
$("#begins" + j, "#ends" + j).trigger('chosen:updated');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(beginOrEnd == 'begin')
|
||||
{
|
||||
$("#ends" + i)[0].selectedIndex = $("#begins" + i)[0].selectedIndex + 3;
|
||||
$("#ends" + i).trigger('chosen:updated');
|
||||
}
|
||||
|
||||
if(batchCreateNum)
|
||||
{
|
||||
for(j = i+1; j < batchCreateNum; j++)
|
||||
{
|
||||
$("#begins" + j)[0].selectedIndex = $("#ends" + (j - 1))[0].selectedIndex;
|
||||
$("#ends" + j)[0].selectedIndex = $("#begins" + j)[0].selectedIndex + 3;
|
||||
$("#begins" + j, "#ends" + j).trigger('chosen:updated');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function switchTimeList(number)
|
||||
{
|
||||
if($('#switchTime' + number).prop('checked'))
|
||||
{
|
||||
$('#begins' + number, '#ends' + number).attr('disabled', 'disabled').trigger('chosen:updated');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#begins' + number, '#ends' + number).removeAttr('disabled').trigger('chosen:updated');
|
||||
}
|
||||
}
|
||||
|
||||
function switchDateFeature(switcher)
|
||||
{
|
||||
if(switcher.checked)
|
||||
{
|
||||
$('#begin, #end').attr('disabled','disabled').trigger('chosen:updated');
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#begin, #end').removeAttr('disabled').trigger('chosen:updated');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 周期待办切换指定复选框时的交互展示。
|
||||
* Interactive display when switching the specified checkbox for cycle.
|
||||
*
|
||||
* @param object switcher
|
||||
* @return void
|
||||
*/
|
||||
function showSpecifiedDate(switcher)
|
||||
{
|
||||
if(switcher.checked)
|
||||
{
|
||||
$('#everyInput').attr('disabled','disabled');
|
||||
$('.specify').removeClass('hidden');
|
||||
$('.every').addClass('hidden')
|
||||
$('#configEvery').prop('checked', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换周期复选框的回调函数,用于页面交互展示。
|
||||
* Switch the cycle checkbox for page interactive display.
|
||||
*
|
||||
* @param object switcher
|
||||
* @return void
|
||||
*/
|
||||
function showEvery(switcher)
|
||||
{
|
||||
if(switcher.checked)
|
||||
{
|
||||
$('#everyInput').removeAttr('disabled');
|
||||
$('.specify').addClass('hidden');
|
||||
$('.every').removeClass('hidden');
|
||||
$('#cycleYear').removeAttr('checked');
|
||||
$('#configSpecify, #configEvery').prop('checked', false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 周期设置为天并为指定时,更改月份时获取天数。
|
||||
* When the cycle is set to days and specified, obtain the number of days when changing the month.
|
||||
*
|
||||
* @param int $specifiedMonth
|
||||
* @return void
|
||||
*/
|
||||
function setDays(specifiedMonth)
|
||||
{
|
||||
/* Get last day in specified month. */
|
||||
var date = new Date();
|
||||
date.setMonth(specifiedMonth);
|
||||
var month = date.getMonth() + 1;
|
||||
date.setMonth(month);
|
||||
date.setDate(0);
|
||||
var specifiedMonthLastDay = date.getDate();
|
||||
|
||||
$('#specifiedDay').empty('');
|
||||
for(var i = 1; i <= specifiedMonthLastDay; i++)
|
||||
{
|
||||
html = "<option value='" + i + "' title='" + i + "' data-keys='" + i + "'>" + i + "</option>";
|
||||
|
||||
$('#specifiedDay').append(html);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* 切换周期类型,用于展示周期类型的交互。
|
||||
* Toggle cycle, used to display the interaction of cycle.
|
||||
*
|
||||
* @param object tab
|
||||
* @return void
|
||||
*/
|
||||
function toggleCycle(switcher)
|
||||
{
|
||||
if(switcher.checked)
|
||||
{
|
||||
$('#date').attr('disabled','disabled');
|
||||
$('.cycle-config').removeClass('hidden');
|
||||
$('#switchDate').closest('.checkbox-primary').addClass('hidden');
|
||||
$('#type').closest('.form-row').addClass('hidden');
|
||||
$('#type').val('custom');
|
||||
loadList('custom'); //Fix bug 3278.
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#date').removeAttr('disabled');
|
||||
$('.cycle-config').addClass('hidden');
|
||||
$('#switchDate').closest('.checkbox-primary').removeClass('hidden');
|
||||
$('#type').closest('.form-row').removeClass('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更改待办日期。
|
||||
* Change todo date.
|
||||
*
|
||||
* @param object tab
|
||||
* @return void
|
||||
*/
|
||||
function changeCreateDate(dateInput)
|
||||
{
|
||||
var selectTime = $(dateInput).val() != today ? start : nowTime;
|
||||
$('#begin').val(selectTime);
|
||||
$('#begin').trigger("chosen:updated");
|
||||
selectNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换标签页,用于更新标签页的样式和更新类型。
|
||||
* Toggle tabs to update the style and type.
|
||||
*
|
||||
* @param object tab
|
||||
* @return void
|
||||
*/
|
||||
function toggleNavTabs(tab)
|
||||
{
|
||||
$(tab).parent().siblings().find('a').prop('class', '');
|
||||
$(tab).addClass('active');
|
||||
if($(tab).data('type'))$('input[id*=type][id*=config]').val($(tab).data('type'));
|
||||
}
|
||||
|
||||
function changeType(typeSelect)
|
||||
{
|
||||
loadList($(typeSelect).find('select').val(), '');
|
||||
}
|
||||
+16
-101
@@ -17,12 +17,13 @@ class todoModel extends model
|
||||
* Create todo data.
|
||||
*
|
||||
* @param object $todo
|
||||
* @param object $formData
|
||||
* @access public
|
||||
* @return int|false
|
||||
*/
|
||||
public function create(object $todo): int|false
|
||||
public function create(object $todo, object $formData): int|false
|
||||
{
|
||||
$processedTodo = $this->todoTao->processCreateData($todo);
|
||||
$processedTodo = $this->todoTao->processCreateData($todo, $formData);
|
||||
if(!$processedTodo) return false;
|
||||
|
||||
$todoID = $this->todoTao->insert($processedTodo);
|
||||
@@ -256,18 +257,9 @@ class todoModel extends model
|
||||
|
||||
$todo = $this->loadModel('file')->replaceImgURL((object)$todo, 'desc');
|
||||
if($setImgSize) $todo->desc = $this->file->setImgSize($todo->desc);
|
||||
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;
|
||||
return $this->todoTao->setTodoNameByType($todo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,93 +272,21 @@ class todoModel extends model
|
||||
* @param object $pager
|
||||
* @param string $orderBy
|
||||
* @access public
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
public function getList($type = 'today', $account = '', $status = 'all', $limit = 0, $pager = null, $orderBy="date, status, begin")
|
||||
public function getList(string $type = 'today', string $account = '', string|array $status = 'all', int $limit = 0, object $pager = null, string $orderBy="date, status, begin"): array
|
||||
{
|
||||
$this->app->loadClass('date');
|
||||
$todos = array();
|
||||
$type = strtolower($type);
|
||||
|
||||
if($type == 'all' or $type == 'assignedtoother')
|
||||
{
|
||||
$begin = '1970-01-01';
|
||||
$end = '2109-01-01';
|
||||
}
|
||||
elseif($type == 'today')
|
||||
{
|
||||
$begin = date::today();
|
||||
$end = $begin;
|
||||
}
|
||||
elseif($type == 'yesterday')
|
||||
{
|
||||
$begin = date::yesterday();
|
||||
$end = $begin;
|
||||
}
|
||||
elseif($type == 'thisweek')
|
||||
{
|
||||
extract(date::getThisWeek());
|
||||
}
|
||||
elseif($type == 'lastweek')
|
||||
{
|
||||
extract(date::getLastWeek());
|
||||
}
|
||||
elseif($type == 'thismonth')
|
||||
{
|
||||
extract(date::getThisMonth());
|
||||
}
|
||||
elseif($type == 'lastmonth')
|
||||
{
|
||||
extract(date::getLastMonth());
|
||||
}
|
||||
elseif($type == 'thisseason')
|
||||
{
|
||||
extract(date::getThisSeason());
|
||||
}
|
||||
elseif($type == 'thisyear')
|
||||
{
|
||||
extract(date::getThisYear());
|
||||
}
|
||||
elseif($type == 'future')
|
||||
{
|
||||
$begin = '2030-01-01';
|
||||
$end = $begin;
|
||||
}
|
||||
elseif($type == 'before')
|
||||
{
|
||||
$begin = '1970-01-01';
|
||||
$end = date::today();
|
||||
}
|
||||
elseif($type == 'cycle')
|
||||
{
|
||||
$begin = $end = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$begin = $end = $type;
|
||||
}
|
||||
$dateRange = $this->config->todo->dateRange[$type] ? $this->config->todo->dateRange[$type] : array('begin' => $type, 'end' => $type);
|
||||
$begin = (string)$dateRange['begin'];
|
||||
$end = (string)$dateRange['end'];
|
||||
|
||||
if(empty($account)) $account = $this->app->user->account;
|
||||
|
||||
$stmt = $this->dao->select('*')->from(TABLE_TODO)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->beginIF($type == 'assignedtoother')->andWhere('account', true)->eq($account)->fi()
|
||||
->beginIF($type != 'assignedtoother')->andWhere('assignedTo', true)->eq($account)->fi()
|
||||
->orWhere('finishedBy')->eq($account)
|
||||
->orWhere('closedBy')->eq($account)
|
||||
->markRight(1)
|
||||
->beginIF($begin)->andWhere('date')->ge($begin)->fi()
|
||||
->beginIF($end)->andWhere('date')->le($end)->fi()
|
||||
->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi()
|
||||
->beginIF($status == 'undone')->andWhere('status')->notin('done,closed')->fi()
|
||||
->beginIF($type == 'cycle')->andWhere('cycle')->eq('1')->fi()
|
||||
->beginIF($type != 'cycle')->andWhere('cycle')->eq('0')->fi()
|
||||
->beginIF($type == 'assignedtoother')->andWhere('assignedTo')->notin(array($account, ''))->fi()
|
||||
->orderBy($orderBy)
|
||||
->beginIF($limit > 0)->limit($limit)->fi()
|
||||
->page($pager)
|
||||
->query();
|
||||
$stmt = $this->todoTao->getListQuery($type, $account, $status, $begin, $end, $pager, $limit, $orderBy);
|
||||
|
||||
/* Set session. */
|
||||
$sql = explode('WHERE', $this->dao->get());
|
||||
@@ -375,15 +295,7 @@ class todoModel extends model
|
||||
|
||||
while($todo = $stmt->fetch())
|
||||
{
|
||||
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 = $this->todoTao->setTodoNameByType($todo);
|
||||
$todo->begin = date::formatTime($todo->begin);
|
||||
$todo->end = date::formatTime($todo->end);
|
||||
|
||||
@@ -397,11 +309,14 @@ class todoModel extends model
|
||||
}
|
||||
|
||||
/**
|
||||
* Get by id list.
|
||||
* 通过包含一个或多个待办ID的列表获取待办列表,这个列表是以todoID为key、以todo对象为value的数组。
|
||||
* 如果待办ID列表为空则返回所有待办。
|
||||
* Get a array with todos which todoID as key, todo object as value by todo id list.
|
||||
* Return all todos if the todo id list is empty.
|
||||
*
|
||||
* @param array $todoIDList
|
||||
* @access public
|
||||
* @return object
|
||||
* @return array
|
||||
*/
|
||||
public function getByList($todoIDList = 0)
|
||||
{
|
||||
|
||||
+70
-1
@@ -340,7 +340,7 @@ class todoTao extends todoModel
|
||||
/**
|
||||
* 获取用户的待办事项数量。
|
||||
* Get todo count on the account.
|
||||
*
|
||||
*
|
||||
* @param string $account
|
||||
* @access protected
|
||||
* @return int
|
||||
@@ -357,4 +357,73 @@ class todoTao extends todoModel
|
||||
->markRight(1)
|
||||
->fetch('count');
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据待办类型设置待办名称。
|
||||
* Set todo name by its type.
|
||||
*
|
||||
* @param object $todo
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function setTodoNameByType(object $todo): object
|
||||
{
|
||||
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($this->config->edition == 'max')
|
||||
{
|
||||
if($todo->type == 'risk' ) $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_RISK)->fetch('name');
|
||||
if($todo->type == 'issue') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_ISSUE)->fetch('title');
|
||||
if($todo->type == 'review') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_REVIEW)->fetch('title');
|
||||
if($todo->type == 'opportunity') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_OPPORTUNITY)->fetch('name');
|
||||
}
|
||||
|
||||
if($this->config->edition == 'biz' || $this->config->edition == 'max')
|
||||
{
|
||||
if($todo->type == 'feedback') $todo->name = $this->dao->findByID($todo->objectID)->from(TABLE_FEEDBACK)->fetch('title');
|
||||
}
|
||||
|
||||
return $todo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造待办列表查询语句。
|
||||
* Build query for todo list.
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $account
|
||||
* @param string|array $status
|
||||
* @param string $begin
|
||||
* @param string $end
|
||||
* @param object $pager
|
||||
* @param int $limit
|
||||
* @param string $orderBy
|
||||
* @access protected
|
||||
* @return object
|
||||
*/
|
||||
protected function getListQuery(string $type, string $account, array|string $status, string $begin, string $end, object $pager, int $limit, string $orderBy): object
|
||||
{
|
||||
return $this->dao->select('*')->from(TABLE_TODO)
|
||||
->where('deleted')->eq('0')
|
||||
->andWhere('vision')->eq($this->config->vision)
|
||||
->beginIF($type == 'assignedtoother')->andWhere('account', true)->eq($account)->fi()
|
||||
->beginIF($type != 'assignedtoother')->andWhere('assignedTo', true)->eq($account)->fi()
|
||||
->orWhere('finishedBy')->eq($account)
|
||||
->orWhere('closedBy')->eq($account)
|
||||
->markRight(1)
|
||||
->beginIF($begin)->andWhere('date')->ge($begin)->fi()
|
||||
->beginIF($end)->andWhere('date')->le($end)->fi()
|
||||
->beginIF($status != 'all' and $status != 'undone')->andWhere('status')->in($status)->fi()
|
||||
->beginIF($status == 'undone')->andWhere('status')->notin('done,closed')->fi()
|
||||
->beginIF($type == 'cycle')->andWhere('cycle')->eq('1')->fi()
|
||||
->beginIF($type != 'cycle')->andWhere('cycle')->eq('0')->fi()
|
||||
->beginIF($type == 'assignedtoother')->andWhere('assignedTo')->notin(array($account, ''))->fi()
|
||||
->orderBy($orderBy)
|
||||
->beginIF($limit > 0)->limit($limit)->fi()
|
||||
->page($pager)
|
||||
->query();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,105 +1,62 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
include dirname(__FILE__, 5) . "/test/lib/init.php";
|
||||
include dirname(__FILE__, 2) . '/todo.class.php';
|
||||
su('admin');
|
||||
|
||||
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->gen(1, '', true);
|
||||
}
|
||||
su('admin');
|
||||
|
||||
/**
|
||||
|
||||
title=测试 todoModel->create();
|
||||
timeout=0
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todoWithoutName, $formData @0
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todoInvalidEnd, $formData @0
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todo, $formData @2
|
||||
|
||||
- 执行todoTest模块的createTest方法,参数是$todoWithCycle, $formData @3
|
||||
|
||||
*/
|
||||
|
||||
$accountList = array('admin', 'dev1', 'test1');
|
||||
|
||||
$b_noname = new stdclass();
|
||||
$b_noname->name = '';
|
||||
$b_noname->date = 'today';
|
||||
$b_noname->type = 'custom';
|
||||
|
||||
$todo1 = new stdclass();
|
||||
$todo1->name = '时间待定的月周期待办';
|
||||
$todo1->type = 'custom';
|
||||
$todo1->date = '+3 days';
|
||||
$todo1->config = array('day' => '', 'specify' => array('month' => 0, 'day' => 1), 'month' => array(1,3,5), 'type' => 'month', 'beforeDays' => 2, 'end' => '2025-01-01');
|
||||
|
||||
$todo2 = new stdclass();
|
||||
$todo2->name = 'bug待办';
|
||||
$todo2->type = 'bug';
|
||||
$todo2->date = 'today';
|
||||
$todo2->bug = '313';
|
||||
$todo2->status = 'doing';
|
||||
$todo2->uid = '313';
|
||||
|
||||
$todo3 = new stdclass();
|
||||
$todo3->name = 'task待办';
|
||||
$todo3->type = 'task';
|
||||
$todo3->date = 'today';
|
||||
$todo3->task = '1';
|
||||
$todo3->status = 'done';
|
||||
$todo3->uid = '1';
|
||||
|
||||
$todo4 = new stdclass();
|
||||
$todo4->name = 'story待办';
|
||||
$todo4->type = 'story';
|
||||
$todo4->date = 'today';
|
||||
$todo4->story = '1';
|
||||
$todo4->status = 'closed';
|
||||
$todo4->uid = '1';
|
||||
|
||||
$todo = new todoTest();
|
||||
|
||||
global $tester;
|
||||
$tester->loadModel('todo');
|
||||
|
||||
initData();
|
||||
zdTable('todo')->config('create')->gen(1);
|
||||
|
||||
$todoWithoutName = new stdclass;
|
||||
$today = date('Y-m-d');
|
||||
|
||||
$formData = new stdClass;
|
||||
$formData->rawdata = new stdclass;
|
||||
$formData->rawdata->uid = '';
|
||||
|
||||
$todo = new stdclass;
|
||||
$todo->name = 'TODO Create Test';
|
||||
$todo->account = 'admin';
|
||||
$todo->date = date('Y-m-d');
|
||||
$todo->type = 'custom';
|
||||
$todo->begin = '0800';
|
||||
$todo->end = '1700';
|
||||
$todo->assignedTo = 'admin';
|
||||
|
||||
$todoWithoutName = clone $todo;
|
||||
$todoWithoutName->name = '';
|
||||
$todoWithoutName->date = date('Y-m-d');
|
||||
$todoWithoutName->type = 'custom';
|
||||
|
||||
$todoInvalidDate = new stdclass;
|
||||
$todoInvalidDate->name = 'todoInvalidDate';
|
||||
$todoInvalidDate->date = 'today';
|
||||
$todoInvalidDate->type = 'custom';
|
||||
$todoInvalidEnd = clone $todo;
|
||||
$todoInvalidEnd->name = 'todoInvalidDate';
|
||||
$todoInvalidEnd->begin = '1000';
|
||||
$todoInvalidEnd->end = '0800';
|
||||
|
||||
$todoValid = new stdclass;
|
||||
$todoValid->name = 'todoValid';
|
||||
$todoValid->date = date('Y-m-d');
|
||||
$todoValid->type = 'custom';
|
||||
$todoWithCycle = clone $todo;
|
||||
$todoWithCycle->type = 'cycle';
|
||||
$todoWithCycle->cycle = 1;
|
||||
$todoWithCycle->config = array('day' => 1, 'specify' => array('month' => 0, 'day' => 1), 'type' => 'day', 'beforeDays' => 1, 'end' => '');
|
||||
$todoWithCycle->objectID = 0;
|
||||
|
||||
$todoValid1 = new stdclass;
|
||||
$todoValid1->name = 'todoValid1';
|
||||
$todoValid1->date = date('Y-m-d');
|
||||
$todoValid1->type = 'custom';
|
||||
|
||||
/**
|
||||
* 1. 如果r函数返回的是一个复杂的结构,比如混合内容的数组或者嵌套的数组,p函数是无法获取返回值中的某些特定值的,需要自己编写助手函数,比如在../todo.class.php中编写。
|
||||
* 2. 如果ztf执行没有生成注释,需要检查php脚本是否执行报错,建议先使用php执行编写的测试用例再用ztf执行。
|
||||
*/
|
||||
r($tester->todo->create($todoValid)) && p() && e('2');
|
||||
r($tester->todo->create($todoWithoutName)) && p() && e('0');
|
||||
r($tester->todo->create($todoInvalidDate)) && p() && e('0');
|
||||
r($tester->todo->create($todoValid1)) && p() && e('3');
|
||||
exit(0);
|
||||
|
||||
r($todo->createTest($accountList[0], $b_noname)) && p() && e('『待办名称』不能为空。');
|
||||
r($todo->createTest($accountList[1], $todo1)) && p('name,type,status') && e('时间待定的月周期待办,custom,wait');
|
||||
r($todo->createTest($accountList[2], $todo2)) && p('name,type,status') && e('测试单转Bug13,bug,doing');
|
||||
r($todo->createTest($accountList[0], $todo3)) && p('name,type,status') && e('开发任务11,task,done');
|
||||
r($todo->createTest($accountList[0], $todo4)) && p('name,type,status') && e('用户需求1,story,closed');
|
||||
$todoTest = new todoTest();
|
||||
r($todoTest->createTest($todoWithoutName, $formData)) && p() && e('0');
|
||||
r($todoTest->createTest($todoInvalidEnd, $formData)) && p() && e('0');
|
||||
r($todoTest->createTest($todo, $formData)) && p() && e('2');
|
||||
r($todoTest->createTest($todoWithCycle, $formData)) && p() && e('3');
|
||||
|
||||
@@ -10,18 +10,16 @@ title=测试 todoModel->getByList();
|
||||
cid=1
|
||||
pid=1
|
||||
|
||||
获取todo 1 2 3 4的名称 >> 自定义1的待办,BUG2的待办,任务3的待办,需求4的待办
|
||||
获取todo 5 6 7 8的名称 >> 测试单5的待办,自定义6的待办,BUG7的待办,任务8的待办
|
||||
获取todo 9 10 11 12的名称 >> 需求9的待办,测试单10的待办,自定义11的待办,BUG12的待办
|
||||
|
||||
*/
|
||||
|
||||
$todoIDList1 = array('1', '2', '3', '4');
|
||||
$todoIDList2 = array('5', '6', '7', '8');
|
||||
$todoIDList3 = array('9', '10', '11', '12');
|
||||
$todoIDList1 = array('1');
|
||||
$todoIDList2 = array('1', '2', '3', '4');
|
||||
$todoIDList3 = array('9', '10', '11', '12'); /* Test not existed items. */
|
||||
$todoIDList4 = array(); /* Test empty todoIDList. */
|
||||
|
||||
$todo = new todoTest();
|
||||
|
||||
r($todo->getByListTest($todoIDList1)) && p() && e('自定义1的待办,BUG2的待办,任务3的待办,需求4的待办'); // 获取todo 1 2 3 4的名称
|
||||
r($todo->getByListTest($todoIDList2)) && p() && e('测试单5的待办,自定义6的待办,BUG7的待办,任务8的待办'); // 获取todo 5 6 7 8的名称
|
||||
r($todo->getByListTest($todoIDList3)) && p() && e('需求9的待办,测试单10的待办,自定义11的待办,BUG12的待办'); // 获取todo 9 10 11 12的名称
|
||||
r($todo->getByListTest($todoIDList1)) && p() && e('1');
|
||||
r($todo->getByListTest($todoIDList2)) && p() && e('1234');
|
||||
r($todo->getByListTest($todoIDList3)) && p() && e('');
|
||||
r($todo->getByListTest($todoIDList4)) && p() && e('12345');
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
title: Create todos for todoModel::create UTC.
|
||||
desc: Create todos for todoModel::create UTC.
|
||||
author: xushenjie
|
||||
version: 1.0.0
|
||||
|
||||
fields:
|
||||
- field: id
|
||||
range: 1
|
||||
- field: account
|
||||
range: 'admin'
|
||||
- field: name
|
||||
range: '待办'
|
||||
- field: date
|
||||
range: '`2023-04-23`'
|
||||
- field: type
|
||||
range: 'custom'
|
||||
- field: begin
|
||||
range: '0800'
|
||||
- field: end
|
||||
range: '1700'
|
||||
- field: assignedTo
|
||||
range: 'admin'
|
||||
@@ -27,5 +27,11 @@ fields:
|
||||
prefix: '这是待办描述'
|
||||
- field: status
|
||||
range: 'wait,doing,done,closed,closed'
|
||||
- field: finishedDate
|
||||
range: 1-9
|
||||
prefix: '2023-04-2'
|
||||
- field: closedDate
|
||||
range: 1-9
|
||||
prefix: '2023-04-2'
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
title: zt_getbylist
|
||||
author: jukui
|
||||
version: "1.0"
|
||||
fields:
|
||||
- field: id
|
||||
range: 1-5
|
||||
- field: account
|
||||
range: 'admin'
|
||||
- field: date
|
||||
range: 1-9
|
||||
prefix: '2023-04-2'
|
||||
- field: begin
|
||||
range: 1000-1100
|
||||
- field: end
|
||||
range: 1200-1300
|
||||
- field: type
|
||||
range: 'custom'
|
||||
- field: cycle
|
||||
range: 0
|
||||
- field: pri
|
||||
range: 3
|
||||
- field: name
|
||||
range: 1-5
|
||||
prefix: '自定义的待办'
|
||||
- field: desc
|
||||
range: 1-5
|
||||
prefix: '这是待办描述'
|
||||
- field: status
|
||||
range: 'wait,doing,done,closed,closed'
|
||||
- field: finishedDate
|
||||
range: 1-9
|
||||
prefix: '2023-04-2'
|
||||
- field: closedDate
|
||||
range: 1-9
|
||||
prefix: '2023-04-2'
|
||||
|
||||
|
||||
@@ -12,37 +12,16 @@ class todoTest
|
||||
/**
|
||||
* Test create a todo.
|
||||
*
|
||||
* @param string $account
|
||||
* @param array $param
|
||||
* @param object $todoData
|
||||
* @param object $formData
|
||||
* @access public
|
||||
* @return object
|
||||
* @return int
|
||||
*/
|
||||
public function createTest($account, $param = array())
|
||||
public function createTest($todoData, $formData)
|
||||
{
|
||||
$config = array('day' => '', 'specify' => array('month' => 0, 'day' => 1), 'type' => 'day', 'beforeDays' => 0, 'end' => '');
|
||||
if(isset($param->date)) $param->date = $param->date == 'today' ? date('Y-m-d',time()) : date('Y-m-d',strtotime('+3 days'));
|
||||
$objectID = $this->objectModel->create($todoData, $formData);
|
||||
|
||||
$createFields['config'] = $config;
|
||||
$createFields['type'] = 'custom';
|
||||
$createFields['name'] = '';
|
||||
$createFields['pri'] = 3;
|
||||
$createFields['desc'] = '';
|
||||
$createFields['status'] = 'wait';
|
||||
$createFields['begin'] = '0830';
|
||||
$createFields['end'] = '0900';
|
||||
|
||||
foreach($createFields as $field => $defaultValue) $_POST[$field] = $defaultValue;
|
||||
|
||||
foreach($param as $key => $value) $_POST[$key] = $value;
|
||||
|
||||
$objectID = $this->objectModel->create(date('Y').date('m'), $account);
|
||||
|
||||
unset($_POST);
|
||||
|
||||
if(dao::isError()) return array_values(dao::getError())[0][0];
|
||||
|
||||
$object = $objectID ? $this->objectModel->getByID($objectID) : 0;
|
||||
return $object;
|
||||
return $objectID ?: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,23 +217,22 @@ class todoTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get todo by id list.
|
||||
* Test todoModel::getByList.
|
||||
*
|
||||
* @parami array $todoIDList
|
||||
* @param array $todoIDList
|
||||
* @access public
|
||||
* @return void
|
||||
* @return string
|
||||
*/
|
||||
public function getByListTest($todoIDList = 0)
|
||||
{
|
||||
$objects = $this->objectModel->getByList($todoIDList);
|
||||
|
||||
$name = '';
|
||||
foreach($objects as $todo) $name .= ',' . $todo->name;
|
||||
$name = trim($name, ',');
|
||||
|
||||
if(dao::isError()) return dao::getError();
|
||||
|
||||
return $name;
|
||||
$result = '';
|
||||
foreach($objects as $id => $todo)
|
||||
{
|
||||
$result .= (string) $todo->id;
|
||||
}
|
||||
if(empty($result)) return "pass";
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* The ui file of todo 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 Zemei Wang<wangzemei@easycorp.ltd>
|
||||
* @package todo
|
||||
* @link http://www.zentao.net
|
||||
*/
|
||||
namespace zin;
|
||||
|
||||
jsVar('noTodo', $lang->todo->noTodo);
|
||||
jsVar('moduleList', $config->todo->moduleList);
|
||||
jsVar('objectsMethod', $config->todo->getUserObjectsMethod);
|
||||
jsVar('nameBoxLabel', array('custom' => $lang->todo->name, 'idvalue' => isset($lang->todo->idvalue) ? $lang->todo->idvalue : null));
|
||||
jsVar('vision', $config->vision);
|
||||
jsVar('noOptions', $lang->todo->noOptions);
|
||||
jsVar('chosenType', $lang->todo->typeList);
|
||||
jsVar('today', date('Y-m-d'));
|
||||
jsVar('nowTime', $time);
|
||||
jsVar('start', key($times));
|
||||
jsVar('userID', $app->user->id);
|
||||
jsVar('defaultType', '');
|
||||
|
||||
/**
|
||||
* 构建周期设置的天的标签内容,待办为周期类型进行展示。
|
||||
* Build tab-pane content of day.
|
||||
*
|
||||
* @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型。
|
||||
*/
|
||||
function buildDayPane(): mixed
|
||||
{
|
||||
global $lang, $app;
|
||||
|
||||
return fragment
|
||||
(
|
||||
inputGroup
|
||||
(
|
||||
set::class('every'),
|
||||
span
|
||||
(
|
||||
set::class('input-group-addon'),
|
||||
$lang->todo->every
|
||||
),
|
||||
|
||||
input
|
||||
(
|
||||
set::id('everyInput'),
|
||||
set::name('config[day]')
|
||||
),
|
||||
span
|
||||
(
|
||||
set::class('input-group-addon'),
|
||||
$lang->todo->cycleDay
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('pl-3 flex items-center input-group-addon every-checkbox'),
|
||||
checkbox
|
||||
(
|
||||
set::id('configSpecify'),
|
||||
set::name('config[specifiedDate]'),
|
||||
set::text($lang->todo->specify),
|
||||
set::value(1),
|
||||
on::change('showSpecifiedDate(this)')
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
inputGroup
|
||||
(
|
||||
set::class('specify hidden'),
|
||||
span
|
||||
(
|
||||
set::class('input-group-addon'),
|
||||
$lang->todo->specify
|
||||
),
|
||||
select
|
||||
(
|
||||
set::id('config[specify][month]'),
|
||||
set::name('config[specify][month]'),
|
||||
set::items($lang->datepicker->monthNames),
|
||||
set::value(0),
|
||||
set::multiple(false),
|
||||
on::change('setDays(this.value)')
|
||||
),
|
||||
select
|
||||
(
|
||||
set::id('specifiedDay'),
|
||||
set::name('config[specify][day]'),
|
||||
set::items($lang->todo->specifiedDay),
|
||||
set::multiple(false),
|
||||
set::value(1)
|
||||
),
|
||||
span
|
||||
(
|
||||
set::class('input-group-addon', strpos($app->getClientLang(), 'zh') !== false ? '' : 'hidden'),
|
||||
$lang->todo->day
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('w-36 pl-3 flex items-center gap-3 input-group-addon'),
|
||||
checkbox
|
||||
(
|
||||
set::id('cycleYear'),
|
||||
set::name('config[cycleYear]'),
|
||||
set::value(1),
|
||||
set::text($lang->todo->everyYear)
|
||||
),
|
||||
checkbox
|
||||
(
|
||||
set::id('configEvery'),
|
||||
set::name('configEvery'),
|
||||
set::value(1),
|
||||
set::text($lang->todo->every),
|
||||
on::change('showEvery(this)')
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建月的标签页,用于周期设置。
|
||||
* Build tab-pane content of month.
|
||||
*
|
||||
* @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型。
|
||||
*/
|
||||
|
||||
function buildMonthDays(): mixed
|
||||
{
|
||||
$days = array();
|
||||
for($i = 1; $i <= 31; $i ++) $days[$i] = $i;
|
||||
|
||||
return checkList
|
||||
(
|
||||
set::class('flex-wrap gap-4'),
|
||||
set::name('config[month]'),
|
||||
set::inline(true),
|
||||
set::items($days),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建周期设置的标签导航,待办为周期类型进行展示。
|
||||
* Build navTabs header for cycle.
|
||||
*
|
||||
* @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型。
|
||||
*/
|
||||
|
||||
function buildNavTabsBar(): mixed
|
||||
{
|
||||
global $lang;
|
||||
|
||||
$navTabs = [
|
||||
[
|
||||
'type' => 'day',
|
||||
'text' => $lang->todo->cycleDay,
|
||||
'class' => ' active'
|
||||
],
|
||||
[
|
||||
'type' => 'week',
|
||||
'text' => $lang->todo->cycleWeek,
|
||||
'class' => ''
|
||||
],
|
||||
[
|
||||
'type' => 'month',
|
||||
'text' => $lang->todo->cycleMonth,
|
||||
'class' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$nav = ul(set::class('nav nav-tabs'));
|
||||
foreach($navTabs as $tab)
|
||||
{
|
||||
$nav->add(
|
||||
li
|
||||
(
|
||||
set::class('nav-item'. $tab['class']),
|
||||
a
|
||||
(
|
||||
set::href('#' . $tab['type']),
|
||||
set::class($tab['class']),
|
||||
set('data-toggle', 'tab'),
|
||||
$tab['text'],
|
||||
on::click('toggleNavTabs(this)')
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建周期设置的标签页,当待办为周期时进行展示。
|
||||
* Build navTabs for cycle.
|
||||
*
|
||||
* @return mixed Any type supported by zin widget function 任何 zin 部件函数参数支持的类型。
|
||||
*/
|
||||
function buildNavTabs(): mixed
|
||||
{
|
||||
global $lang;
|
||||
|
||||
return div
|
||||
(
|
||||
set::class('w-full'),
|
||||
buildNavTabsBar(),
|
||||
div
|
||||
(
|
||||
set::class('tab-content'),
|
||||
div
|
||||
(
|
||||
set::class('tab-pane active'),
|
||||
set::id('day'),
|
||||
buildDayPane(),
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('tab-pane'),
|
||||
set::id('week'),
|
||||
checkList
|
||||
(
|
||||
set::primary(true),
|
||||
set::id('config[week]'),
|
||||
set::name('config[week]'),
|
||||
set::inline(true),
|
||||
set::items($lang->todo->dayNames),
|
||||
),
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('tab-pane h-28'),
|
||||
set::id('month'),
|
||||
buildMonthDays(),
|
||||
),
|
||||
inputGroup
|
||||
(
|
||||
div
|
||||
(
|
||||
set::class('input-group-addon'),
|
||||
'提前',
|
||||
),
|
||||
input
|
||||
(
|
||||
set::id('name'),
|
||||
set::name('config[beforeDays]'),
|
||||
set::value(0),
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('input-group-addon'),
|
||||
'天生成待办',
|
||||
),
|
||||
),
|
||||
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
formPanel
|
||||
(
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::label($lang->todo->date),
|
||||
set::strong(true),
|
||||
set::class('align-center'),
|
||||
inputGroup
|
||||
(
|
||||
input
|
||||
(
|
||||
set::name('date'),
|
||||
set::value(date('Y-m-d')),
|
||||
set::type('date'),
|
||||
set::width('1/3'),
|
||||
on::change('changeCreateDate(this)')
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('flex items-center gap-3 pl-3 input-group-addon'),
|
||||
checkbox
|
||||
(
|
||||
set::id('switchDate'),
|
||||
set::name('switchDate'),
|
||||
set::text($lang->todo->periods['future']),
|
||||
set::width('100px'),
|
||||
on::change('toggleDateTodo(this)')
|
||||
),
|
||||
checkbox
|
||||
(
|
||||
set::id('cycle'),
|
||||
set::name('cycle'),
|
||||
set::value(1),
|
||||
set::text($lang->todo->cycle),
|
||||
on::change('toggleCycle(this)')
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
set::class('cycle-config hidden'),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->todo->cycleConfig),
|
||||
set::strong(true),
|
||||
buildNavTabs()
|
||||
)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
set::class('cycle-config hidden'),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::label($lang->todo->deadline),
|
||||
set::strong(true),
|
||||
input
|
||||
(
|
||||
set::type('date'),
|
||||
set::name('config[end]')
|
||||
)
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name('type'),
|
||||
set::strong(true),
|
||||
set::label($lang->todo->type),
|
||||
set::items($lang->todo->typeList),
|
||||
on::change('changeType(this)'),
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::name('assignedTo'),
|
||||
set::strong(true),
|
||||
set::label($lang->todo->assignTo),
|
||||
set::items($users),
|
||||
set::value($app->user->account)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
formGroup
|
||||
(
|
||||
set::id('nameBox'),
|
||||
set::class('name-box'),
|
||||
set::label($lang->todo->name),
|
||||
set::strong(true),
|
||||
set::required(true),
|
||||
inputGroup
|
||||
(
|
||||
set::class('title-group'),
|
||||
div
|
||||
(
|
||||
set::id('nameInputBox'),
|
||||
input
|
||||
(
|
||||
set::id('name'),
|
||||
set::name('name')
|
||||
)
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('input-group-addon fix-border br-0'),
|
||||
$lang->todo->pri
|
||||
),
|
||||
select
|
||||
(
|
||||
set::class('w-20'),
|
||||
set::id('pri'),
|
||||
set::name('pri'),
|
||||
set::items($lang->todo->priList),
|
||||
set::value(3)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
formGroup
|
||||
(
|
||||
set::name('desc'),
|
||||
set::strong(true),
|
||||
set::type('textarea'),
|
||||
set::label($lang->todo->desc)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::id('status'),
|
||||
set::name('status'),
|
||||
set::items($lang->todo->statusList),
|
||||
set::label($lang->todo->status),
|
||||
set::strong(true)
|
||||
),
|
||||
formRow
|
||||
(
|
||||
set::class('items-center'),
|
||||
formGroup
|
||||
(
|
||||
set::width('1/2'),
|
||||
set::label($lang->todo->beginAndEnd),
|
||||
set::strong(true),
|
||||
inputGroup
|
||||
(
|
||||
select
|
||||
(
|
||||
set::id('begin'),
|
||||
set::name('begin'),
|
||||
set::items($times),
|
||||
set::value(date('Y-m-d') != $date ? key($times) : $time),
|
||||
on::change('selectNext()')
|
||||
),
|
||||
select
|
||||
(
|
||||
set::id('end'),
|
||||
set::name('end'),
|
||||
set::items($times)
|
||||
)
|
||||
),
|
||||
div
|
||||
(
|
||||
set::class('ml-3 flex items-center switch-time'),
|
||||
checkbox
|
||||
(
|
||||
set::id('switchTime'),
|
||||
set::name('switchTime'),
|
||||
set::text($lang->todo->lblDisableDate),
|
||||
on::change('switchDateFeature(this)')
|
||||
)
|
||||
)
|
||||
|
||||
)
|
||||
),
|
||||
formGroup
|
||||
(
|
||||
set::label($lang->todo->private),
|
||||
set::strong(true),
|
||||
set::class('private-row'),
|
||||
checkbox
|
||||
(
|
||||
set::id('private'),
|
||||
set::name('private'),
|
||||
set::value(1)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
render();
|
||||
@@ -22,6 +22,33 @@ class todoZen extends todo
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成批量创建待办视图数据。
|
||||
* Build batch create form data.
|
||||
*
|
||||
* @param string $date
|
||||
* @access protected
|
||||
* @return void
|
||||
*/
|
||||
protected function buildBatchCreateView(string $date)
|
||||
{
|
||||
/* Set Custom. */
|
||||
foreach(explode(',', $this->config->todo->list->customBatchCreateFields) as $field) $customFields[$field] = $this->lang->todo->$field;
|
||||
|
||||
$this->view->customFields = $customFields;
|
||||
$this->view->showFields = $this->config->todo->custom->batchCreateFields;
|
||||
|
||||
$this->view->title = $this->lang->todo->common . $this->lang->colon . $this->lang->todo->batchCreate;
|
||||
$this->view->position[] = $this->lang->todo->common;
|
||||
$this->view->position[] = $this->lang->todo->batchCreate;
|
||||
$this->view->date = (int)$date == 0 ? $date : date('Y-m-d', strtotime($date));
|
||||
$this->view->times = date::buildTimeList($this->config->todo->times->begin, $this->config->todo->times->end, $this->config->todo->times->delta);
|
||||
$this->view->time = date::now();
|
||||
$this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted|noempty');
|
||||
|
||||
$this->display();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成编辑待办视图数据。
|
||||
* Build create form data.
|
||||
|
||||
@@ -3,4 +3,4 @@ sonar.sourceEncoding=UTF-8
|
||||
sonar.qualitygate.wait=true
|
||||
sonar.coverage.exclusions=**/*.*
|
||||
sonar.inclusions=**/**.php
|
||||
sonar.exclusions=**/*.bak,**/*.sql,**/*.js,**/*.css,**/*.yaml,**/*.zip,**/*.out,**/lang/*,**/test/**
|
||||
sonar.exclusions=**/*.bak,**/*.sql,**/*.js,**/*.css,**/*.yaml,**/*.zip,**/*.out,**/lang/*,**/test/**,doc/*
|
||||
|
||||
@@ -81,5 +81,10 @@ fields:
|
||||
range: 5-10000:5
|
||||
- field: openedVersion
|
||||
range: "16.5"
|
||||
- field: openedDate
|
||||
range: "(-3M)-(+M):1D"
|
||||
type: timestamp
|
||||
format: "YY/MM/DD"
|
||||
postfix: "\t"
|
||||
- field: deleted
|
||||
range: 0
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ fields:
|
||||
- field: account1
|
||||
range: admin,user{98},test{100},pm{100},po{100}
|
||||
- field: account2
|
||||
range: [],3-100,1-100,1-100,1-100
|
||||
range: "[],3-100,1-100,1-100,1-100"
|
||||
prefix: ""
|
||||
postfix: ""
|
||||
loop: 0
|
||||
|
||||
+6
-6
@@ -26,7 +26,7 @@ fields:
|
||||
- field: account1
|
||||
range: admin,user{99},test{100},dev{100},pm{100},po{100},td{100},pd{100},qd{100},top{100},outside{100},others{100},a,bb,ccc,qwuiadsd?!2as@#%$aasd~aj1!@#1
|
||||
- field: account2
|
||||
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}
|
||||
range: "[],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}"
|
||||
- field: password
|
||||
note: "密码"
|
||||
range: 123Qwe!@#{346}
|
||||
@@ -53,7 +53,7 @@ fields:
|
||||
- field: commiter1
|
||||
range: admin,user{99},test{100},dev{100},pm{100},po{100},td{100},pd{100},qd{100},top{100},outside{100},others{100},a,bb,ccc,qwuiadsd?!2as@#%$aasd~aj1!@#1
|
||||
- field: commiter2
|
||||
range: [],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}
|
||||
range: "[],1-99,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,1-100,[]{4}"
|
||||
- field: avatar
|
||||
note: ""
|
||||
range: ""
|
||||
@@ -78,7 +78,7 @@ fields:
|
||||
- field: email2
|
||||
range: 1000-9999:2
|
||||
- field: email3
|
||||
range: [@qq.com,@163.com,@gmail.com]
|
||||
range: "[@qq.com,@163.com,@gmail.com]"
|
||||
- field: skype
|
||||
note: "Skype"
|
||||
range: Skype
|
||||
@@ -125,9 +125,8 @@ fields:
|
||||
note: "入职日期"
|
||||
range: "(M)-(w)"
|
||||
type: timestamp
|
||||
prefix: "DateTime"
|
||||
postfix: ""
|
||||
format: "YY/MM/DD"
|
||||
format: "YY/MM/DD hh:mm:ss"
|
||||
- field: visits
|
||||
note: "访问次数"
|
||||
range: 0-10000:R
|
||||
@@ -154,7 +153,7 @@ fields:
|
||||
range: 1-10000
|
||||
- field: locked
|
||||
note: "锁定时间"
|
||||
range: 0
|
||||
range: "`2023-01-02 10:00:00`"
|
||||
- field: company
|
||||
note: "公司"
|
||||
range: 1
|
||||
@@ -170,6 +169,7 @@ fields:
|
||||
range: 1-10000:R
|
||||
- field: scoreLevel
|
||||
note: "积分等级"
|
||||
range: 0
|
||||
- field: deleted
|
||||
note: "是否删除"
|
||||
range: 0
|
||||
|
||||
+5
-3
@@ -115,7 +115,7 @@ function p($keys = '', $delimiter = ',')
|
||||
{
|
||||
$values = getValues($_result, $part, $delimiter);
|
||||
if(!is_array($values)) continue;
|
||||
|
||||
|
||||
foreach($values as $value) echo $value . "\n";
|
||||
}
|
||||
|
||||
@@ -272,7 +272,7 @@ function genModuleAndMethod($rParams)
|
||||
{
|
||||
$param = trim($param, "'");
|
||||
if($param[0] != '$') $param = trim(strchr($param, '$'), ')');
|
||||
|
||||
|
||||
$objArrowCount = substr_count($param, '->');
|
||||
$rParamsStructureList = explode('->', $param);
|
||||
|
||||
@@ -474,7 +474,9 @@ function zdImport($table, $yaml, $count = 10)
|
||||
function su($account)
|
||||
{
|
||||
$userModel = new userModel();
|
||||
$user = $userModel->identify($account, '123Qwe!@#');
|
||||
$user = $userModel->getByID($account);
|
||||
if($user) return $userModel->login($user);
|
||||
|
||||
$user = $userModel->identify($account, $user->password);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -100,6 +100,13 @@ class h extends wg
|
||||
return new h(prop('tagName', $tagName), $args);
|
||||
}
|
||||
|
||||
public static function a()
|
||||
{
|
||||
$a = static::create('a', func_get_args());
|
||||
if($a->prop('target') === '_blank' && !$a->hasProp('rel')) $a->prop('rel', 'noopener noreferrer');
|
||||
return $a;
|
||||
}
|
||||
|
||||
public static function button()
|
||||
{
|
||||
return static::create('button', prop('type', 'button'), func_get_args());
|
||||
|
||||
Reference in New Issue
Block a user