This commit is contained in:
holan20180123
2020-08-19 08:29:36 +08:00
45 changed files with 2162 additions and 113 deletions
+10 -5
View File
@@ -193,11 +193,16 @@ define('TABLE_RELATION', '`' . $config->db->prefix . 'relation`');
define('TABLE_REPOHISTORY', '`' . $config->db->prefix . 'repohistory`');
define('TABLE_REPOFILES', '`' . $config->db->prefix . 'repofiles`');
define('TABLE_REPOBRANCH', '`' . $config->db->prefix . 'repobranch`');
if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`');
if(!defined('TABLE_STAGE')) define('TABLE_STAGE', '`' . $config->db->prefix . 'stage`');
if(!defined('TABLE_DESIGN')) define('TABLE_DESIGN', '`' . $config->db->prefix . 'design`');
if(!defined('TABLE_DESIGNSPEC')) define('TABLE_DESIGNSPEC', '`' . $config->db->prefix . 'designspec`');
if(!defined('TABLE_RISK')) define('TABLE_RISK', '`' . $config->db->prefix . 'risk`');
if(!defined('TABLE_LANG')) define('TABLE_LANG', '`' . $config->db->prefix . 'lang`');
if(!defined('TABLE_STAGE')) define('TABLE_STAGE', '`' . $config->db->prefix . 'stage`');
if(!defined('TABLE_DESIGN')) define('TABLE_DESIGN', '`' . $config->db->prefix . 'design`');
if(!defined('TABLE_DESIGNSPEC')) define('TABLE_DESIGNSPEC', '`' . $config->db->prefix . 'designspec`');
if(!defined('TABLE_ISSUE')) define('TABLE_ISSUE', '`' . $config->db->prefix . 'issue`');
if(!defined('TABLE_RISK')) define('TABLE_RISK', '`' . $config->db->prefix . 'risk`');
if(!defined('TABLE_PROJECTSPEC')) define('TABLE_PROJECTSPEC', '`' . $config->db->prefix . 'projectspec`');
if(!defined('TABLE_WORKESTIMATION')) define('TABLE_WORKESTIMATION', '`' . $config->db->prefix . 'workestimation`');
if(!defined('TABLE_DURATIONESTIMATION')) define('TABLE_DURATIONESTIMATION', '`' . $config->db->prefix . 'durationestimation`');
if(!defined('TABLE_BUDGET')) define('TABLE_BUDGET', '`' . $config->db->prefix . 'budget`');
$config->objectTables['product'] = TABLE_PRODUCT;
$config->objectTables['story'] = TABLE_STORY;
+104 -12
View File
@@ -95,6 +95,34 @@ CREATE TABLE `zt_designspec` (
UNIQUE KEY `design` (`design`,`version`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_issue`;
CREATE TABLE `zt_issue` (
`id` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT,
`program` varchar(255) NOT NULL,
`product` varchar(255) NOT NULL,
`commit` varchar(30) NOT NULL,
`project` mediumint(9) NOT NULL DEFAULT '0',
`name` varchar(255) NOT NULL,
`parent` mediumint(8) unsigned NOT NULL,
`status` varchar(30) NOT NULL,
`subStatus` varchar(30) NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
`commitBy` varchar(30) NOT NULL,
`commitDate` datetime NOT NULL,
`assignedTo` varchar(30) NOT NULL,
`assignedBy` varchar(30) NOT NULL,
`assignedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
`story` char(30) NOT NULL,
`desc` text NOT NULL,
`version` smallint(6) NOT NULL,
`type` char(30) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `zt_risk` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`program` varchar(255) NOT NULL,
@@ -115,22 +143,86 @@ CREATE TABLE `zt_risk` (
`addedDate` date NOT NULL,
`resolution` text NOT NULL,
`resolvedBy` varchar(30) NOT NULL,
`activateBy` varchar(30) NOT NULL,
`activateDate` date NOT NULL,
`closeBy` varchar(30) NOT NULL,
`closedDate` date NOT NULL,
`assignedTo` varchar(30) NOT NULL,
`assignedBy` varchar(30) NOT NULL,
`cancelBy` varchar(30) NOT NULL,
`cancelDate` datetime NOT NULL,
`cancelReason` char(30) NOT NULL,
`hangupBy` varchar(30) NOT NULL,
`hangupdDate` datetime NOT NULL,
`trackedBy` varchar(30) NOT NULL,
`trackedDate` datetime NOT NULL,
`assignedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_projectspec`;
CREATE TABLE `zt_projectspec` (
`project` mediumint(8) NOT NULL,
`version` smallint(6) NOT NULL,
`name` varchar(255) NOT NULL,
`milestone` enum('0','1') NOT NULL DEFAULT '0',
`begin` date NOT NULL,
`end` date NOT NULL,
UNIQUE KEY `project` (`project`,`version`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_budget`;
CREATE TABLE `zt_budget` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`program` mediumint(8) NOT NULL,
`stage` char(30) NOT NULL,
`subject` mediumint(8) NOT NULL,
`amount` char(30) NOT NULL,
`name` varchar(255) NOT NULL,
`desc` text NOT NULL,
`createdBy` char(30) NOT NULL,
`createdDate` date NOT NULL,
`lastEditedBy` char(30) NOT NULL,
`lastEditedDate` date NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_durationestimation`;
CREATE TABLE `zt_durationestimation` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`program` mediumint(8) unsigned NOT NULL,
`stage` mediumint(9) NOT NULL,
`workload` varchar(255) NOT NULL,
`worktimeRate` varchar(255) NOT NULL,
`people` varchar(255) NOT NULL,
`startDate` date NOT NULL,
`endDate` date NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
`cancelBy` varchar(30) NOT NULL,
`cancelDate` datetime NOT NULL,
`cancelReason` char(30) NOT NULL,
`assignedTo` varchar(30) NOT NULL,
`assignedDate` datetime NOT NULL,
`hangupBy` varchar(30) NOT NULL,
`hangupdDate` datetime NOT NULL,
`activateBy` varchar(30) NOT NULL,
`activateDate` datetime NOT NULL,
`isChange` enum('0','1') NOT NULL DEFAULT '0',
`trackedBy` varchar(30) NOT NULL,
`trackedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- DROP TABLE IF EXISTS `zt_workestimation`;
CREATE TABLE `zt_workestimation` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`program` mediumint(8) unsigned NOT NULL,
`scale` mediumint(8) unsigned NOT NULL,
`productivity` smallint(3) unsigned NOT NULL,
`duration` mediumint(8) unsigned NOT NULL,
`unitLaborCost` mediumint(8) unsigned NOT NULL,
`totalLaborCost` mediumint(8) unsigned NOT NULL,
`createdBy` varchar(30) NOT NULL,
`createdDate` datetime NOT NULL,
`editedBy` varchar(30) NOT NULL,
`editedDate` datetime NOT NULL,
`assignedTo` varchar(30) NOT NULL,
`assignedDate` datetime NOT NULL,
`deleted` enum('0','1') NOT NULL DEFAULT '0',
`dayHour` float(5,2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+9
View File
@@ -0,0 +1,9 @@
<?php
$config->budget = new stdclass();
$config->budget->editor = new stdclass();
$config->budget->create = new stdclass();
$config->budget->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
$config->budget->editor->edit = array('id' => 'desc', 'tools' => 'simpleTools');
$config->budget->create->requiredFields = 'stage,subject,name';
+166
View File
@@ -0,0 +1,166 @@
<?php
class budget extends control
{
public function __construct($module = '', $method = '')
{
parent::__construct($module, $method);
$this->view->program = $this->loadModel('project')->getByID($this->session->program);
}
public function browse($orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$this->app->loadClass('pager', $static = true);
$pager = pager::init($recTotal, $recPerPage, $pageID);
$this->view->title = $this->lang->budget->common . $this->lang->budget->list;
$this->view->position[] = $this->lang->budget->common . $this->lang->budget->list;
$this->view->budgets = $this->budget->getList($orderBy, $pager);
$this->view->orderBy = $orderBy;
$this->view->pager = $pager;
$this->view->modules = $this->loadModel('tree')->getOptionMenu(0, $viewType = 'subject', $startModuleID = 0);
$this->view->stages = $this->loadModel('programplan')->getPlanPairsForBudget($this->session->program);
$this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
$this->display();
}
public function summary()
{
$getSubjectStructure = $this->budget->getSubjectStructure();
$isChildren = false;
if(is_array($getSubjectStructure))
{
foreach($getSubjectStructure as $subjects)
{
if(isset($subjects['hasChild']))
{
$isChildren = true;
break;
}
}
}
$this->view->title = $this->lang->budget->common . $this->lang->budget->summary;
$this->view->position[] = $this->lang->budget->common . $this->lang->budget->summary;
$this->view->subjectStructure = $getSubjectStructure;
$this->view->isChildren = $isChildren;
$this->view->subjects = $this->budget->getSubjects();
$this->view->stages = $this->budget->getStages();
$this->view->stagePairs = $this->loadModel('programplan')->getPlanPairsForBudget($this->session->program);
$this->view->summary = $this->budget->getSummary();
$this->view->modules = $this->loadModel('tree')->getOptionMenu(0, $viewType = 'subject', $startModuleID = 0);
$this->display();
}
public function create()
{
if($_POST)
{
$budgetID = $this->budget->create();
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = dao::getError();
$this->send($response);
}
$this->loadModel('action')->create('budget', $budgetID, 'created');
$response['result'] = 'success';
$response['message'] = $this->lang->saveSuccess;
$response['locate'] = inlink('browse');
$this->send($response);
}
$this->view->title = $this->lang->budget->create . $this->lang->budget->common;
$this->view->position[] = $this->lang->budget->create . $this->lang->budget->common;
$this->view->subjects = array(0 => '') + $this->budget->getSubjectOption();
$this->view->stages = $this->loadModel('programplan')->getPlanPairsForBudget($this->session->program);
$this->display();
}
public function edit($budgetID)
{
if($_POST)
{
$changes = $this->budget->update($budgetID);
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = dao::getError();
$this->send($response);
}
if($changes)
{
$actionID = $this->loadModel('action')->create('budget', $budgetID, 'edited');
$this->action->logHistory($actionID, $changes);
}
$response['result'] = 'success';
$response['message'] = $this->lang->saveSuccess;
$response['locate'] = inlink('browse');
$this->send($response);
}
$this->view->title = $this->lang->budget->edit . $this->lang->budget->common;
$this->view->position[] = $this->lang->budget->edit . $this->lang->budget->common;
$this->view->subjects = array('' => '') + $this->budget->getSubjectOption();
$this->view->stages = $this->loadModel('programplan')->getPlanPairsForBudget($this->session->program);
$this->view->budget = $this->budget->getByID($budgetID);
$this->display();
}
public function view($budgetID)
{
$this->view->stages = $this->budget->getStages();
$this->view->subjects = $this->budget->getSubjectOption();
$this->view->stages = $this->loadModel('programplan')->getPlanPairsForBudget($this->session->program);
$this->view->budget = $this->budget->getByID($budgetID);
$this->view->actions = $this->loadModel('action')->getList('budget', $budgetID);
$this->view->users = $this->loadModel('user')->getPairs('noclosed|noletter');
$this->display();
}
public function delete($budgetID = 0, $confirm = 'no')
{
if($confirm == 'no')
{
echo js::confirm($this->lang->budget->confirmDelete, $this->createLink('budget', 'delete', "id=$budgetID&confirm=yes"));
exit;
}
else
{
$this->budget->delete(TABLE_BUDGET, $budgetID);
die(js::locate(inlink('browse'), 'parent'));
}
}
public function batchCreate()
{
if($_POST)
{
$this->budget->batchCreate();
if(dao::isError())
{
$response['result'] = 'fail';
$response['message'] = dao::getError();
$this->send($response);
}
$response['result'] = 'success';
$response['message'] = $this->lang->saveSuccess;
$response['locate'] = inlink('browse');
$this->send($response);
}
$this->view->title = $this->lang->budget->batchCreate . $this->lang->budget->common;
$this->view->position[] = $this->lang->budget->batchCreate . $this->lang->budget->common;
$this->view->subjects = array('' => '') + $this->budget->getSubjectOption();
$this->view->stages = $this->loadModel('programplan')->getPlanPairsForBudget($this->session->program);
$this->display();
}
}
+1
View File
@@ -0,0 +1 @@
#pageNav{display: none}
+28
View File
@@ -0,0 +1,28 @@
<?php
$lang->budget->create = '新建';
$lang->budget->edit = '编辑';
$lang->budget->total = '总预算';
$lang->budget->summary = '汇总';
$lang->budget->browse = '列表';
$lang->budget->list = '列表';
$lang->budget->view = '详情';
$lang->budget->delete = '删除';
$lang->budget->batchCreate = '批量新建';
$lang->budget->common = '费用估算';
$lang->budget->id = '编号';
$lang->budget->stage = '阶段';
$lang->budget->subject = '科目';
$lang->budget->name = '费用名称';
$lang->budget->amount = '预计金额';
$lang->budget->desc = '说明';
$lang->budget->yuan = '元';
$lang->budget->dollar = 'Dollars';
$lang->budget->createdBy = '由谁创建';
$lang->budget->createdDate = '创建时间';
$lang->budget->lastEditedBy = '由谁编辑';
$lang->budget->lastEditedDate = '编辑时间';
$lang->budget->basicInfo = '基本信息';
$lang->budget->noData = '暂无记录,';
$lang->budget->summaryReport = '汇总表';
$lang->budget->confirmDelete = '您确定要删除吗?';
+182
View File
@@ -0,0 +1,182 @@
<?php
class budgetModel extends model
{
public function getSubjectOption()
{
$subjects = $this->loadModel('tree')->getOptionMenu(0, $viewType = 'subject', $startModuleID = 0);
$subjectList = $this->dao->select('*')->from(TABLE_MODULE)->where('id')->in(array_keys($subjects))->fetchAll();
foreach($subjectList as $subject)
{
if(isset($subjects[$subject->parent])) unset($subjects[$subject->parent]);
if($subject->grade > 2) unset($subjects[$subject->id]);
}
return $subjects;
}
public function getByID($budgetID)
{
$budget = $this->dao->select('*')->from(TABLE_BUDGET)->where('id')->eq($budgetID)->fetch();
$budget = $this->loadModel('file')->replaceImgURL($budget, 'desc');
return $budget;
}
public function getList($orderBy = 'id_desc', $pager = null)
{
return $this->dao->select('*')->from(TABLE_BUDGET)
->where('program')->eq($this->session->program)
->andWhere('deleted')->eq(0)
->orderBy($orderBy)
->page($pager)
->fetchAll();
}
public function getStages()
{
return $this->dao->select('stage')->from(TABLE_BUDGET)
->where('program')->eq($this->session->program)
->andWhere('deleted')->eq(0)
->orderBy('stage_asc')
->fetchPairs();
}
public function getSubjects()
{
return $this->dao->select('subject')->from(TABLE_BUDGET)
->where('program')->eq($this->session->program)
->andWhere('deleted')->eq(0)
->orderBy('subject_asc')
->fetchPairs();
}
public function getSubjectStructure()
{
$subjects = $this->getSubjects();
$structure = array();
foreach($subjects as $subjectID)
{
$subject = $this->loadModel('tree')->getById($subjectID);
if($subject->grade == 1)
{
$structure[$subject->id][] = $subject->id;
continue;
}
$structure[$subject->parent][] = $subject->id;
$structure[$subject->parent]['hasChild'] = true;
}
return $structure;
}
public function getSummary()
{
$budgets = $this->dao->select('*')->from(TABLE_BUDGET)
->where('program')->eq($this->session->program)
->andWhere('deleted')->eq(0)
->fetchAll();
$summary = array();
foreach($budgets as $budget)
{
$summary[$budget->subject] = isset($summary[$budget->subject]) ? $summary[$budget->subject] : array();
$summary[$budget->subject][$budget->stage] = isset($summary[$budget->subject][$budget->stage]) ? $summary[$budget->subject][$budget->stage] : 0;
$summary[$budget->subject][$budget->stage] += $budget->amount;
}
$total = 0;
foreach($summary as $subject => $stageSummary)
{
$summary[$subject]['summary'] = 0;
foreach($stageSummary as $amount)
{
$summary[$subject]['summary'] += $amount;
$total += $amount;
}
}
$summary['total'] = $total;
return $summary;
}
public function create()
{
$budget = fixer::input('post')
->setDefault('createdBy', $this->app->user->account)
->setDefault('createdDate', helper::today())
->setDefault('program', $this->session->program)
->cleanFloat('amount')
->remove('uid')
->get();
$this->dao->insert(TABLE_BUDGET)->data($budget)
->autoCheck()
->batchCheck($this->config->budget->create->requiredFields, 'notempty')
->exec();
$budgetID = $this->dao->lastInsertID();
return $budgetID;
}
public function batchCreate()
{
$today = helper::today();
$budgets = fixer::input('post')->get();
foreach($budgets->name as $i => $name)
{
if(!$name) continue;
$data = new stdclass();
$data->name = $name;
$data->program = $this->session->program;
$data->stage = $budgets->stage[$i];
$data->subject = $budgets->subject[$i];
$data->amount = (float)$budgets->amount[$i];
$data->desc = nl2br($budgets->desc[$i]);
$data->createdBy = $this->app->user->account;
$data->createdDate = $today;
foreach(explode(',', $this->config->budget->create->requiredFields) as $field)
{
$field = trim($field);
if($field and empty($data->$field))
{
dao::$errors['message'][] = sprintf($this->lang->error->notempty, $this->lang->budget->$field);
return false;
}
}
$this->dao->insert(TABLE_BUDGET)->data($data)
->autoCheck()
->exec();
$budgetID = $this->dao->lastInsertID();
$this->loadModel('action')->create('budget', $budgetID, 'Opened');
}
return !dao::isError();
}
public function update($budgetID)
{
$oldBudget = $this->getByID($budgetID);
$budget = fixer::input('post')
->setDefault('lastEditedBy', $this->app->user->account)
->setDefault('lastEditedDate', helper::today())
->cleanFloat('amount')
->remove('uid')
->get();
$this->dao->update(TABLE_BUDGET)->data($budget)
->where('id')->eq($budgetID)
->autoCheck()
->batchCheck($this->config->budget->create->requiredFields, 'notempty')
->exec();
if(!dao::isError()) return common::createChanges($oldBudget, $budget);
}
}
+44
View File
@@ -0,0 +1,44 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<div id="mainContent" class="main-content fade">
<div class="center-block">
<div class="main-header">
<h2><?php echo $lang->budget->batchCreate;?></h2>
</div>
<form class="main-form form-ajax" method='post' enctype='multipart/form-data'>
<table class="table table-form">
<thead>
<tr>
<th class='w-40px'><?php echo $lang->idAB;?></th>
<th class='w-200px required'><?php echo $lang->budget->stage;?> </th>
<th class='w-200px required'><?php echo $lang->budget->subject;?> </th>
<th class='required'><?php echo $lang->budget->name;?> </th>
<th class='w-150px'><?php echo $lang->budget->amount;?> </th>
<th class='w-180px'><?php echo $lang->budget->desc;?> </th>
</tr>
</thead>
<tbody>
<?php for($i = 1; $i <= 10; $i++):?>
<tr>
<td><?php echo $i;?></td>
<td><?php echo html::select("stage[$i]", $stages, '', 'class="form-control chosen"');?></td>
<td><?php echo html::select("subject[$i]", $subjects, '', 'class="form-control chosen"');?></td>
<td><?php echo html::input("name[$i]", '', 'class="form-control"');?></td>
<td>
<div class='input-group'>
<?php echo html::input("amount[$i]", '', 'class="form-control"');?>
<span class='input-group-addon'><?php echo $lang->budget->{$program->budgetUnit};?></span>
</div>
</td>
<td><?php echo html::textarea("desc[$i]", '', 'class="form-control" rows=1');?></td>
</tr>
<?php endfor;?>
<tr>
<td colspan='5' class='text-center form-actions'><?php echo html::submitButton() . html::backButton();?></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+65
View File
@@ -0,0 +1,65 @@
<?php include '../../common/view/header.html.php';?>
<style>
.browse-active{color: #0c64eb;font-weight: 700;}
</style>
<div id="mainMenu" class="clearfix">
<div class="pull-left">
<?php common::printLink('budget', 'summary', '', "<i class='icon-common-report icon-bar-chart muted'></i> " . $lang->budget->summary, '', "class='btn btn-link'");?>
<?php common::printLink('budget', 'browse', '', "<i class='icon icon-list-alt muted'></i> " . $lang->budget->list, '', "class='btn btn-link browse-active'");?>
</div>
<div class="btn-toolbar pull-right">
<?php common::printLink('budget', 'batchcreate', '', "<i class='icon icon-plus'></i>" . $lang->budget->batchCreate, '', "class='btn btn-secondary'");?>
<?php common::printLink('budget', 'create', '', "<i class='icon icon-plus'></i>" . $lang->budget->create, '', "class='btn btn-primary'");?>
</div>
</div>
<div id="mainContent" class="main-row fade">
<div class="main-col">
<?php if(empty($budgets)):?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->budget->noData;?></span>
<?php if(common::hasPriv('budget', 'create')):?>
<?php echo html::a($this->createLink('budget', 'create', ''), "<i class='icon icon-plus'></i> " . $lang->budget->create, '', "class='btn btn-info'");?>
<?php endif;?>
</p>
</div>
<?php else:?>
<form class='main-table' method='post' id='dataForm'>
<table class='table has-sort-head' id='dataList'>
<?php $vars = "orderBy=%s&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}";?>
<thead>
<tr>
<th><?php echo common::printOrderLink('id', $orderBy, $vars, $lang->budget->id);?></th>
<th><?php echo common::printOrderLink('name', $orderBy, $vars, $lang->budget->name);?></th>
<th><?php echo common::printOrderLink('stage', $orderBy, $vars, $lang->budget->stage);?></th>
<th><?php echo common::printOrderLink('subject', $orderBy, $vars, $lang->budget->subject);?></th>
<th><?php echo common::printOrderLink('amount', $orderBy, $vars, $lang->budget->amount);?></th>
<th><?php echo common::printOrderLink('createdBy', $orderBy, $vars, $lang->budget->createdBy);?></th>
<th><?php echo common::printOrderLink('createdDate', $orderBy, $vars, $lang->budget->createdDate);?></th>
<th><?php echo $lang->actions;?></th>
</tr>
</thead>
<tbody>
<?php foreach($budgets as $budget):?>
<tr>
<td class='c-id'><?php printf('%03d', $budget->id);?></td>
<td><?php echo html::a($this->createLink('budget', 'view', "id=$budget->id"), $budget->name);?></td>
<td><?php echo zget($stages, $budget->stage);?></td>
<td><?php echo zget($modules, $budget->subject);?></td>
<td><?php echo $budget->amount;?></td>
<td><?php echo zget($users, $budget->createdBy);?></td>
<td><?php echo $budget->createdDate;?></td>
<td class='c-actions'>
<?php common::printIcon('budget', 'edit', "id=$budget->id", $budget, 'list');?>
<?php common::printIcon('budget', 'delete', "id=$budget->id", $budget, 'list', '', 'hiddenwin');?>
</td>
</tr>
<?php endforeach;?>
</tbody>
</table>
<div class="table-footer"><?php $pager->show('right', 'pagerjs');?></div>
</form>
<?php endif;?>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+46
View File
@@ -0,0 +1,46 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<div id="mainContent" class="main-content fade">
<div class="center-block">
<div class="main-header">
<h2><?php echo $lang->budget->create . $lang->budget->common;?></h2>
</div>
<form class="main-form form-ajax" method='post' enctype='multipart/form-data'>
<table class="table table-form">
<tbody>
<tr>
<th class='w-120px'><?php echo $lang->budget->stage;?> </th>
<td><?php echo html::select('stage', $stages, '', 'class="form-control chosen"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->budget->subject;?> </th>
<td><?php echo html::select('subject', $subjects, '', 'class="form-control chosen"');?></td>
</tr>
<tr>
<th><?php echo $lang->budget->amount;?> </th>
<td>
<div class='input-group'>
<?php echo html::input('amount', '', 'class="form-control"');?>
<span class='input-group-addon'><?php echo $lang->budget->{$program->budgetUnit};?></span>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->budget->name;?> </th>
<td colspan='2'><?php echo html::input('name', '', 'class="form-control"');?></td>
</tr>
<tr>
<th><?php echo $lang->budget->desc;?> </th>
<td colspan='2'><?php echo html::textarea('desc', '', 'class="form-control"');?></td>
</tr>
<tr>
<td colspan='4' class='text-center form-actions'><?php echo html::submitButton() . html::backButton();?></td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+46
View File
@@ -0,0 +1,46 @@
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<div id="mainContent" class="main-content fade">
<div class="center-block">
<div class="main-header">
<h2><?php echo $lang->budget->edit . $lang->budget->common;?></h2>
</div>
</div>
<form class="main-form form-ajax" method='post' enctype='multipart/form-data'>
<table class="table table-form">
<tbody>
<tr>
<th class='w-120px'><?php echo $lang->budget->stage;?> </th>
<td><?php echo html::select('stage', $stages, $budget->stage, 'class="form-control chosen"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->budget->subject;?> </th>
<td><?php echo html::select('subject', $subjects, $budget->subject, 'class="form-control chosen"');?></td>
</tr>
<tr>
<th><?php echo $lang->budget->amount;?> </th>
<td>
<div class='input-group'>
<?php echo html::input('amount', $budget->amount, 'class="form-control"');?>
<span class='input-group-addon'><?php echo $lang->budget->{$program->budgetUnit};?></span>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->budget->name;?> </th>
<td colspan='2'><?php echo html::input('name', $budget->name, 'class="form-control"');?></td>
</tr>
<tr>
<th><?php echo $lang->budget->desc;?> </th>
<td colspan='2'><?php echo html::textarea('desc', $budget->desc, 'class="form-control"');?></td>
</tr>
<tr>
<td colspan='4' class='text-center form-actions'><?php echo html::submitButton() . html::backButton();?></td>
</tr>
</tbody>
</table>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+90
View File
@@ -0,0 +1,90 @@
<?php include '../../common/view/header.html.php';?>
<style>
.summary-active{color: #0c64eb;font-weight: 700;}
.summary td{font-weight: 700;}
.table-title{background: #efefef}
.text-center th{vertical-align: middle;}
</style>
<div id="mainMenu" class="clearfix">
<div class="pull-left">
<?php common::printLink('budget', 'summary', '', "<i class='icon-common-report icon-bar-chart muted'></i> " . $lang->budget->summary, '', "class='btn btn-link summary-active'");?>
<?php common::printLink('budget', 'browse', '', "<i class='icon icon-list-alt muted'></i> " . $lang->budget->list, '', "class='btn btn-link'");?>
</div>
<div class="btn-toolbar pull-right">
<?php common::printLink('budget', 'batchcreate', '', "<i class='icon icon-plus'></i>" . $lang->budget->batchCreate, '', "class='btn btn-secondary'");?>
<?php common::printLink('budget', 'create', '', "<i class='icon icon-plus'></i>" . $lang->budget->create, '', "class='btn btn-primary'");?>
</div>
</div>
<div id='mainContent' class='main-content'>
<div class="center-block">
<?php if($summary['total'] != 0):?>
<table class='table table-bordered'>
<tr class='text-center table-title'>
<th rowspan="<?php echo $isChildren ? 2 : 1;?>"><?php echo $lang->budget->subject . '/' . $lang->budget->stage?></th>
<?php $hasChild = false;?>
<?php foreach($subjectStructure as $subject => $structure):?>
<?php if(isset($structure['hasChild'])) $hasChild = true;?>
<th colspan="<?php echo (count($structure) - 1)?>"><?php echo zget($modules, $subject);?></th>
<?php endforeach;?>
<th rowspan="<?php echo $isChildren ? 2 : 1;?>"><?php echo $lang->budget->summary; ?></th>
</tr>
<?php if($hasChild):?>
<tr class='text-center table-title'>
<?php foreach($subjectStructure as $parentID => $structure):?>
<?php
foreach($structure as $subject)
{
if($subject == 'hasChild') continue;
if($subject == $parentID)
{
echo "<th></th>";
}
else
{
echo "<th>" . zget($modules, $subject) . "</th>";
}
}
?>
<?php endforeach;?>
</tr>
<?php endif;?>
<?php foreach($stages as $stage):?>
<tr>
<td><?php echo zget($stagePairs, $stage);?></td>
<?php foreach($subjects as $subject):?>
<td><?php echo isset($summary[$subject][$stage]) ? $summary[$subject][$stage] : 0;?></td>
<?php endforeach;?>
<td>
<?php $rowsum = 0;?>
<?php foreach($subjects as $subject):?>
<?php $rowsum += isset($summary[$subject][$stage]) ? $summary[$subject][$stage] : 0;?>
<?php endforeach;?>
<?php echo $rowsum;?>
</td>
</tr>
<?php endforeach;?>
<tr class='summary'>
<td><?php echo $lang->budget->summary;?></td>
<?php foreach($subjects as $subject):?>
<td><?php echo isset($summary[$subject]['summary']) ? $summary[$subject]['summary'] : 0;?></td>
<?php endforeach;?>
<td>
<?php $rowsum = 0;?>
<?php foreach($subjects as $subject):?>
<?php $rowsum += isset($summary[$subject]['summary']) ? $summary[$subject]['summary'] : 0;?>
<?php endforeach;?>
<?php echo $rowsum;?>
</td>
</tr>
</table>
<div class='alert alert-info mg-0'><?php echo $lang->budget->total . ':' . $summary['total'] . $lang->budget->{$program->budgetUnit};?></div>
<?php else:?>
<div class="table-empty-tip">
<p>
<span class="text-muted"><?php echo $lang->noData;?></span>
</p>
</div>
<?php endif;?>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+77
View File
@@ -0,0 +1,77 @@
<?php
/**
* The view file of bug module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package bug
* @version $Id: view.html.php 4728 2013-05-03 06:14:34Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php $browseLink = inlink('browse');?>
<div id="mainMenu" class="clearfix">
<div class="btn-toolbar pull-left">
<?php common::printBack($browseLink, 'btn btn-secondary');?>
<div class='divider'></div>
<div class="page-title">
<span class="label label-id"><?php echo $budget->id?></span>
<span class="text" title="<?php echo $budget->name;?>"><?php echo $budget->name;?></span>
</div>
</div>
</div>
<div id="mainContent" class="main-row">
<div class="col-8 main-col">
<div class="cell">
<div class="detail">
<div class="detail-title"><?php echo $lang->budget->desc;?></div>
<div class="detail-content article-content">
<?php echo $budget->desc; ?>
</div>
</div>
</div>
<div class='cell'><?php include '../../common/view/action.html.php';?></div>
</div>
<div class="side-col col-4">
<div class="cell">
<div class='detail'>
<div class='detail-title'><?php echo $lang->budget->basicInfo;?></div>
<table class="table table-data">
<tbody>
<tr>
<th><?php echo $lang->budget->stage;?></th>
<td><?php echo zget($stages, $budget->stage);?></td>
</tr>
<tr>
<th><?php echo $lang->budget->subject;?></th>
<td><?php echo zget($subjects, $budget->subject);?></td>
</tr>
<tr>
<th><?php echo $lang->budget->amount;?></th>
<td><?php echo $budget->amount;?></td>
</tr>
<tr>
<th><?php echo $lang->budget->createdBy;?></th>
<td><?php echo zget($users, $budget->createdBy);?></td>
</tr>
<tr>
<th><?php echo $lang->budget->createdDate;?></th>
<td><?php echo $budget->createdDate;?></td>
</tr>
<tr>
<th><?php echo $lang->budget->lastEditedBy;?></th>
<td><?php echo zget($users, $budget->lastEditedBy);?></td>
</tr>
<tr>
<th><?php echo $lang->budget->lastEditedDate;?></th>
<td><?php echo $budget->lastEditedDate;?></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+1 -1
View File
@@ -1121,7 +1121,7 @@ $lang->cmmi = new stdclass();
$lang->cmmi->subMenu = new stdclass();
$lang->cmmi->subMenu->list = new stdclass();
$lang->cmmi->subMenu->list->workestimation = array('link' => '估算|workestimation|index|program=%s', 'subModule' => 'durationestimation,budget');
$lang->cmmi->subMenu->list->program = '项目|||';
$lang->cmmi->subMenu->list->program = '项目|program|edit|';
$lang->cmmiproduct = new stdclass();
$lang->workestimation = new stdclass();
+4
View File
@@ -0,0 +1,4 @@
<?php
$config->durationestimation = new stdclass;
$config->durationestimation->index = new stdclass;
$config->durationestimation->index->requiredFields = 'scale,productivity,scale,duration,unitLaborCost,totalLaborCost';
+117
View File
@@ -0,0 +1,117 @@
<?php
/**
* The control file of durationestimation of ChanzhiEPS.
*
* @copyright Copyright 2009-2010 QingDao Nature Easy Soft Network Technology Co,LTD (www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv11.html)
* @author Xiying Guan <guanxiying@xirangit.com>
* @package durationestimation
* @version $Id$
* @link http://www.chanzhi.org
*/
class durationestimation extends control
{
public function index($programID)
{
$workestimation = $this->loadModel('workestimation')->getBudget($programID);
if(!$workestimation)
{
echo js::alert($this->lang->durationestimation->setWorkestimation);
die(js::locate($this->createLink('workestimation', 'index', "currentProgram=$programID")));
}
$this->loadModel('programplan');
$program = $this->loadModel('project')->getById($programID);
$stages = $this->loadModel('stage')->getStages();
$title = $this->lang->durationestimation->common . $this->lang->colon . $program->name;
$this->view->estimationList = $this->durationestimation->getListByProgram($programID);
if(empty($this->view->estimationList)) $this->locate(inlink('create', "currentProgram=$programID"));
$this->view->workestimation = $workestimation;
$this->view->title = $title;
$this->view->program = $program;
$this->view->stages = $stages;
$this->display();
}
public function create($programID = 0)
{
$workestimation = $this->loadModel('workestimation')->getBudget($programID);
if(!$workestimation)
{
echo js::alert($this->lang->durationestimation->setWorkestimation);
die(js::locate($this->createLink('workestimation', 'index', "currentProgram=$programID")));
}
$this->loadModel('programplan');
if(!empty($_POST))
{
$total = 0;
foreach($this->post->workload as $value) $total += $value;
if($total != 100) $this->send(array('result' => 'fail', 'message' => $this->lang->durationestimation->workloadError));
$this->durationestimation->save($programID);
if(dao::isError()) $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inlink('index', "currentProgram={$programID}")));
}
$this->view->estimationList = $this->durationestimation->getListByProgram($programID);
$this->view->workestimation = $workestimation;
$program = $this->loadModel('project')->getById($programID);
$title = $this->lang->durationestimation->common . $this->lang->colon . $program->name;
$this->view->title = $title;
$this->view->program = $program;
$this->view->stages = $this->loadModel('stage')->getStages();
$this->display();
}
/**
* ajaxGetDuration
*
* @param int $program
* @param int $workload
* @param int $worktimeRate
* @param int $people
* @access public
* @return void
*/
public function ajaxGetDuration($program, $stage, $workload, $worktimeRate, $people, $startDate)
{
$startDate = str_replace('_', '-', $startDate);
if($startDate == '0000-00-00') $this->send(array('result' => 'success', 'endDate' => '0000-00-00'));
$estimation = $this->loadModel('workestimation')->getBudget($program);
$duration = $estimation->duration * $workload / 100;
$divisor = ($people == 0 || $estimation->dayHour == 0) ? 0 : $worktimeRate / 100 * $people / $estimation->dayHour;
$duration = !$divisor ? 0 : $duration / $divisor;
if(!$divisor) $this->send(array('result' => 'fail'));
$holidays = array();
$workDays = array();
$i = 0;
$this->loadModel('project');
$startedTime = strtotime($startDate);
$days = 0;
for($i = 0; $days < $duration; $i ++)
{
$day = date('N', strtotime("+ $i days", $startedTime));
if($this->config->project->weekend == 2)
{
if($day > 5) continue;
}
if($this->config->project->weekend == 1)
{
if($day > 6) continue;
}
$lastDay = date('Y-m-d', strtotime("+ $i days", $startedTime));
$days ++;
}
$this->send(array('result' => 'success', 'endDate' => $lastDay));
}
}
+55
View File
@@ -0,0 +1,55 @@
$().ready(function()
{
$(':input[name*=people]').change(function()
{
var peopleNumber = 0;
$(':input[name*=people]').each(function()
{
var people = $(this).val();
if(people) peopleNumber += parseInt(people);
});
$('#totalStaff').html(peopleNumber);
});
$(':input[name*=workload]').change(function()
{
rate = parseFloat($(this).val());
workload = estimation.scale * rate / 100;
$(this).parents('td').next().find(':input').val(workload);
totalWorkload = 0;
$(':input[name*=workload]').each(function()
{
rate = parseFloat($(this).val());
workload = estimation.scale * rate / 100;
totalWorkload += workload;
});
$('#totalWorkload').html(totalWorkload.toFixed(2));
});
$(':input').change(function()
{
var that = $(this);
programID = program.id;
stage = $(this).parents('tr').find('[name*=stage]').val();
workload = $(this).parents('tr').find('[name*=workload]').val();
worktimeRate = $(this).parents('tr').find('[name*=worktimeRate]').val();
people = $(this).parents('tr').find('[name*=people]').val();
startDate = $(this).parents('tr').find('[name*=startDate]').val();
if(startDate) startDate = startDate.replace(/-/g, '_');
if(isNaN(workload) || isNaN(worktimeRate) || isNaN(people) || startDate == '') return false;
url = createLink('durationestimation', 'ajaxGetDuration', 'program=' + programID + '&stage=' + stage + '&workload=' + workload + '&worktimeRate=' + worktimeRate + '&people=' + people + '&startDate=' + startDate),
$.getJSON(
url,
function(response)
{
if(response.result == 'success')
{
that.parents('tr').find('[name*=endDate]').val(response.endDate);
}
}
);
});
$(':input').change();
})
+23
View File
@@ -0,0 +1,23 @@
<?php
$lang->durationestimation->index = '工期估算首页';
$lang->durationestimation->create = '工期估算设置';
$lang->durationestimation->common = '项目工期估算';
$lang->durationestimation->stage = '阶段';
$lang->durationestimation->workloadRate = '工作量占比';
$lang->durationestimation->workload = '工作量';
$lang->durationestimation->worktimeRate = '全时率';
$lang->durationestimation->people = '投入人数';
$lang->durationestimation->startDate = '开始日期';
$lang->durationestimation->endDate = '结束日期';
$lang->durationestimation->setting = '设置';
$lang->durationestimation->setWorkestimation = "请先录入工作量估算信息";
$lang->durationestimation->summary = "项目规模: <strong class='text-danger'> %s {$lang->hourCommon}</strong>, 估算工作量: <strong id='totalWorkload' class='text-danger'>0</strong>, 总投入人数: <strong id='totalStaff' class='text-danger'>0</strong>";
$lang->durationestimation->workloadError = "工作量占比之和必须是100%";
$lang->durationestimation->placeholder = new stdclass();
$lang->durationestimation->placeholder->scale = '';
$lang->durationestimation->placeholder->productivity = '';
$lang->durationestimation->placeholder->duration = '';
$lang->durationestimation->placeholder->unitLaborCost = '';
$lang->durationestimation->placeholder->totalLaborCost = '';
+37
View File
@@ -0,0 +1,37 @@
<?php
/**
* The model file of durationestimation module of ChanzhiEPS.
*
* @copyright Copyright 2009-2010 QingDao Nature Easy Soft Network Technology Co,LTD (www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv11.html)
* @author Xiying Guan <guanxiying@xirangit.com>
* @package durationestimation
* @version $Id$
* @link http://www.chanzhi.org
*/
class durationestimationModel extends model
{
public function getListByProgram($program)
{
return $this->dao->select('*')->from(TABLE_DURATIONESTIMATION)->where('program')->eq($program)->fetchAll('stage');
}
public function save($program)
{
$this->dao->delete()->from(TABLE_DURATIONESTIMATION)->where('program')->eq($program);
foreach($this->post->stage as $i => $stage)
{
$estimation = new stdclass;
$estimation->program = $program;
$estimation->stage = $stage;
$estimation->workload = $this->post->workload[$i];
$estimation->worktimeRate = $this->post->worktimeRate[$i];
$estimation->people = $this->post->people[$i];
$estimation->startDate = $this->post->startDate[$i];
$estimation->endDate = $this->post->endDate[$i];
$this->dao->insert(TABLE_DURATIONESTIMATION)->data($estimation)->exec();
}
return !dao::isError();
}
}
@@ -0,0 +1,66 @@
<?php include '../../common/view/header.html.php';?>
<?php js::set('program', $program);?>
<?php js::set('estimation', $workestimation);?>
<div id='mainContent' class='main-content'>
<form class='main-form form-ajax' method='post' id='stageForm' enctype='multipart/form-data'>
<table class='table table-bordered table-form'>
<thead>
<tr class='text-center'>
<th><?php echo $lang->durationestimation->stage;?></th>
<th><?php echo $lang->durationestimation->workloadRate;?></th>
<th><?php echo $lang->durationestimation->workload;?></th>
<th><?php echo $lang->durationestimation->worktimeRate;?></th>
<th><?php echo $lang->durationestimation->people;?></th>
<th><?php echo $lang->durationestimation->startDate;?></th>
<th><?php echo $lang->durationestimation->endDate;?></th>
</tr>
</thead>
<tbody>
<?php $i = 0;?>
<?php if(!empty($stages)):?>
<?php foreach($stages as $stage):?>
<?php $estimation = zget($estimationList, $stage->id, array());?>
<tr>
<td>
<?php echo $stage->name;?>
<?php echo html::hidden('stage[]', $stage->id);?>
</td>
<td>
<div class='input-group'>
<input type='text' name='workload[]' id='workload<?php echo $i;?>' value='<?php echo zget($estimation, 'workload', $stage->percent); ?>' class='form-control' />
<span class='input-group-addon'>%</span>
</div>
</td>
<td>
<div class='input-group'>
<input type='text' value='' class='form-control' />
<span class='input-group-addon'><?php echo $lang->hourCommon;?></span>
</div>
</td>
<td>
<div class='input-group'>
<input type='text' name='worktimeRate[]' id='<?php echo $i;?>' value='<?php echo zget($estimation, 'worktimeRate', '100');?>' class='form-control' />
<span class='input-group-addon'>%</span>
</div>
</td>
<td><input type='text' name='people[]' id='people<?php echo $i;?>' value='<?php echo zget($estimation, 'people', 0);?>' class='form-control' /></td>
<td><input type='text' name='startDate[]' id='startDate<?php echo $i;?>' value='<?php echo zget($estimation, 'startDate', '');?>' class='form-control form-date' /></td>
<td><input type='text' name='endDate[]' id='endDate<?php echo $i;?>' value='<?php echo zget($estimation, 'endDate', '');?>' class='form-control form-date' /></td>
</tr>
<?php $i ++;?>
<?php endforeach;?>
<?php endif;?>
<tr>
<td colspan='7'><?php printf($lang->durationestimation->summary, zget($workestimation, 'scale', ''));?></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan='7' class='text-center form-actions'><?php echo html::submitButton() . ' ' . html::backButton(); ?></td>
</tr>
</tfoot>
</table>
<?php js::set('i', $i);?>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
@@ -0,0 +1,48 @@
<?php include '../../common/view/header.html.php';?>
<?php js::set('program', $program);?>
<?php js::set('estimation', $workestimation);?>
<div id='mainContent' class='main-content'>
<form class='main-form form-ajax' method='post' id='planForm' enctype='multipart/form-data'>
<table class='table table-list table-bordered'>
<thead>
<tr class='text-center'>
<th><?php echo $lang->durationestimation->stage;?></th>
<th><?php echo $lang->durationestimation->workload;?></th>
<th><?php echo $lang->durationestimation->worktimeRate;?></th>
<th><?php echo $lang->durationestimation->people;?></th>
<th><?php echo $lang->durationestimation->startDate;?></th>
<th><?php echo $lang->durationestimation->endDate;?></th>
</tr>
</thead>
<tbody>
<?php $i = 0;?>
<?php foreach($stages as $plan):?>
<?php $estimation = zget($estimationList, $plan->id, 0);?>
<tr class='text-center'>
<td>
<?php echo $plan->name;?>
<?php echo html::hidden('stage[]', $plan->id);?>
</td>
<td> <?php echo zget($estimation, 'workload', ''); ?>% </td>
<td> <?php echo zget($estimation, 'worktimeRate', '');?>% </td>
<td><?php echo zget($estimation, 'people', '');?></td>
<td><?php echo zget($estimation, 'startDate', '');?></td>
<td><?php echo zget($estimation, 'endDate', '');?></td>
</tr>
<?php $i ++;?>
<?php endforeach;?>
</tbody>
<tfoot>
<tr>
<td colspan='6' class='form-actions text-center'>
<?php echo html::a(inlink('create', "program={$program->id}"), $lang->durationestimation->setting, '', "class='btn btn-primary'");?>
</td>
</tr>
</tfoot>
</table>
</table>
<?php js::set('i', $i);?>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+6
View File
@@ -0,0 +1,6 @@
<?php
$config->issue->create = new stdclass();
$config->issue->create->requiredFields = 'title,type,severity';
$config->issue->editor = new stdclass();
$config->issue->editor->create = array('id' => 'desc', 'tools' => 'simpleTools');
+56
View File
@@ -0,0 +1,56 @@
<?php
/**
* The control file of issue module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package issue
* @version $Id: control.php 5145 2013-07-15 06:47:26Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
class issue extends control
{
/**
* Get issue list data.
*
* @param string $browseType
* @param string orderBy
* @param int recTotal
* @param int recPerPage
* @param int pageID
* @access public
* @return void
*/
public function browse($browseType = 'all', $orderBy = 'id_desc', $recTotal = 0, $recPerPage = 20, $pageID = 1)
{
$this->view->title = $this->lang->issue->common . $this->lang->colon . $this->lang->issue->browse;
$this->view->position[] = $this->lang->issue->browse;
$this->display();
}
/**
* Create a issue.
*
* @access public
* @return void
*/
public function create()
{
if($_POST)
{
$result = $this->issue->create();
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
$this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => inLink('browse', 'browseType=all')));
}
$this->view->title = $this->lang->issue->common . $this->lang->colon . $this->lang->issue->create;
$this->view->position[] = $this->lang->issue->common;
$this->view->position[] = $this->lang->issue->create;
$this->view->users = $this->loadModel('user')->getPairs('noclosed|nodeleted');
$this->display();
}
}
+75
View File
@@ -0,0 +1,75 @@
<?php
$lang->issue->common = '项目问题';
$lang->issue->browse = '问题列表';
$lang->issue->resolvedBy = '解决者';
$lang->issue->program = '所属项目';
$lang->issue->title = '标题';
$lang->issue->desc = '描述';
$lang->issue->pri = '优先级';
$lang->issue->severity = '严重程度';
$lang->issue->type = '类别';
$lang->issue->effectedArea = '受影响的活动';
$lang->issue->activity = '活动列表';
$lang->issue->deadline = '计划解决日期';
$lang->issue->resolution = '解决方式';
$lang->issue->resolutionComment = '解决方案';
$lang->issue->resolvedDate = '实际解决日期';
$lang->issue->status = '结果';
$lang->issue->createdBy = '由谁创建';
$lang->issue->createdDate = '创建日期';
$lang->issue->owner = '提出人';
$lang->issue->editedBy = '由谁编辑';
$lang->issue->editedDate = '编辑日期';
$lang->issue->activateBy = '由谁激活';
$lang->issue->activateDate = '激活日期';
$lang->issue->closeBy = '由谁关闭';
$lang->issue->closedDate = '关闭日期';
$lang->issue->assignedTo = '指派给';
$lang->issue->assignedBy = '由谁指派';
$lang->issue->assignedDate = '指派时间';
$lang->issue->resolved = '解决';
$lang->issue->create = '新建';
$lang->issue->batchCreate = '批量新建';
$lang->issue->labelList['open'] = '开放';
$lang->issue->labelList['assignTo'] = '指派给我';
$lang->issue->labelList['closed'] = '已关闭';
$lang->issue->labelList['suspended'] = '已挂起';
$lang->issue->labelList['cancelled'] = '已取消';
$lang->issue->priList[''] = '';
$lang->issue->priList['1'] = 1;
$lang->issue->priList['2'] = 2;
$lang->issue->priList['3'] = 3;
$lang->issue->priList['4'] = 4;
$lang->issue->serverityList[''] = '';
$lang->issue->serverityList['1'] = '严重';
$lang->issue->serverityList['2'] = '较严重';
$lang->issue->serverityList['3'] = '较小';
$lang->issue->serverityList['4'] = '建议';
$lang->issue->typeList[''] = '';
$lang->issue->typeList['design'] = '设计问题';
$lang->issue->typeList['code'] = '程序缺陷';
$lang->issue->typeList['performance'] = '性能问题';
$lang->issue->typeList['version'] = '版本控制';
$lang->issue->typeList['storyadd'] = '需求新增';
$lang->issue->typeList['storychanged'] = '需求修改';
$lang->issue->typeList['storyremoved'] = '需求删除';
$lang->issue->typeList['data'] = '数据问题';
$lang->issue->resolutionList['resolved'] = '已解决';
$lang->issue->resolutionList['tostory'] = '转需求';
$lang->issue->resolutionList['tobug'] = '转BUG';
$lang->issue->resolutionList['torisk'] = '转风险';
$lang->issue->resolutionList['totask'] = '转任务';
$lang->issue->statusList['unconfirmed'] = '待确认';
$lang->issue->statusList['confirmed'] = '已确认';
$lang->issue->statusList['unresolved'] = '正解决';
$lang->issue->statusList['resolved'] = '已解决';
$lang->issue->statusList['canceled'] = '取消';
$lang->issue->statusList['closed'] = '已关闭';
+48
View File
@@ -0,0 +1,48 @@
<?php
/**
* The model file of issue module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package issue
* @version $Id: model.php 5145 2013-07-15 06:47:26Z chencongzhi520@gmail.com $
* @link http://www.zentao.net
*/
?>
<?php
class issueModel extends model
{
public function create()
{
$now = helper::now();
$data = fixer::input('post')
->add('createdBy', $this->app->user->account)
->add('createdDate', $now)
->addIF($this->post->assignedTo, 'assignedBy', $this->app->user->account)
->addIF($this->post->assignedTo, 'assignedDate', $now)
->stripTags($this->config->issue->editor->create['id'], $this->config->allowedTags)
->get();
if(strpos($this->config->issue->create->requiredFields, 'type') !== false and !$this->post->type)
{
dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->issue->type);
return false;
}
if(strpos($this->config->issue->create->requiredFields, 'title') !== false and !$this->post->title)
{
dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->issue->title);
return false;
}
if(strpos($this->config->issue->create->requiredFields, 'severity') !== false and !$this->post->severity)
{
dao::$errors[] = sprintf($this->lang->error->notempty, $this->lang->issue->severity);
return false;
}
$this->dao->insert(TABLE_ISSUE)->data($data)->exec();
return true;
}
}
+24
View File
@@ -0,0 +1,24 @@
<?php
/**
* The batch close view of story module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Congzhi Chen <congzhi@cnezsoft.com>
* @package story
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div>
<div class="btn-toolbar pull-left">
<?php echo html::a($this->createLink('issue', 'browse', 'browseType=all'), '<span class="text">' . $lang->issue->browse . '</span>', '', 'class="btn btn-link btn-active-text"');?>
</div>
<div class="btn-toolbar pull-right">
<?php common::printLink('issue', 'create', '', "<i class='icon icon-plus'></i>" . $lang->issue->create, '', "class='btn btn-primary'");?>
<?php common::printLink('issue', 'batchCreate', '', "<i class='icon icon-plus'></i>" . $lang->issue->batchCreate, '', "class='btn btn-primary'");?>
</div>
</div>
<?php include '../../common/view/footer.html.php';?>
+71
View File
@@ -0,0 +1,71 @@
<?php
/**
* The batch close view of story module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Congzhi Chen <congzhi@cnezsoft.com>
* @package story
* @version $Id$
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<?php include '../../common/view/kindeditor.html.php';?>
<div class="main-content" id="mainCentent">
<div class="center-block">
<div class="main-header">
<h2><?php echo $lang->issue->create;?></h2>
</div>
</div>
<form method="post" class="main-form form-ajax" enctype="multipart/form-data" id="issueForm">
<table class="table table-form">
<tbody>
<tr>
<th><?php echo $lang->issue->type;?></th>
<td class="required"><?php echo html::select('type', $lang->issue->typeList, '', 'class="form-control chosen"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->issue->title;?></th>
<td class="required"><?php echo html::input('title', '', 'class="form-control"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->issue->severity;?></th>
<td class="required"><?php echo html::select('severity', $lang->issue->serverityList, '', 'class="form-control chosen"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->issue->pri;?></th>
<td><?php echo html::select('pri', $lang->issue->priList, '', 'class="form-control chosen"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->issue->deadline;?></th>
<td><?php echo html::input('deadline', '', 'class="form-control form-date"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->issue->assignedTo;?></th>
<td><?php echo html::select('assignedTo', $users, '', 'class="form-control chosen"');?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->issue->desc;?></th>
<td colspan="3"><?php echo html::textarea('desc', '', 'row="6"');?></td>
</tr>
<tr>
<td colspan='3' class='text-center form-actions'><?php echo html::submitButton() . html::backButton();?></td>
</tr>
</tbody>
</table>
</form>
</div>
<?php include '../../common/view/footer.html.php';?>
+79 -38
View File
@@ -28,72 +28,99 @@ class productModel extends model
* @return void
*/
public function setMenu($products, $productID, $branch = 0, $module = 0, $moduleType = '', $extra = '')
{
/* Has access privilege?. */
if($products and !isset($products[$productID]) and !$this->checkPriv($productID)) $this->accessDenied();
{
$product = $this->getByID($productID);
if($product)
{
$project = $this->loadModel('project')->getByID($product->program);
if(isset($project->id)) $this->loadModel('project')->setMenu($products, $project->id);
$this->lang->modulePageNav = $this->getModuleNav($products, $project, $product, $extra, $branch, $module, $moduleType);
}
$pageActions = '';
if($this->app->moduleName == 'release')
{
$pageActions = html::a(helper::createLink('release', 'create', "productID=$productID&branch=$branch"), "<i class='icon icon-plus'></i> {$this->lang->release->create}", '', "class='btn btn-primary'");
foreach($this->lang->release->moduleMenus as $key => $menu)
{
$replace = array();
$replace['productID'] = $productID;
$replace['branch'] = $branch;
common::setMenuVars($this->lang->release->moduleMenus, $key, $replace);
}
$this->lang->moduleMenus['release'] = $this->lang->release->moduleMenus;
}
if($this->app->moduleName == 'programplan' and isset($product->program))
{
$pageActions .= html::a(helper::createLink('programplan', 'create', "program=$product->program&productID=$productID"), "<i class='icon icon-plus'></i> {$this->lang->programplan->create}", '', "class='btn btn-primary'");
}
$this->lang->modulePageActions = $pageActions;
foreach($this->lang->product->menu as $key => $menu)
{
$replace = array();
$replace['productID'] = $productID;
$replace['branch'] = $branch;
common::setMenuVars($this->lang->product->menu, $key, $replace);
}
}
/**
* Get product module menu.
*
* @param array $products
* @param int $productID
* @param string $currentModule
* @param string $currentMethod
* @param string $extra
*
* @access public
* @return string
*/
public function getModuleNav($products, $project, $product, $extra, $branch, $module, $moduleType)
{
$currentModule = $this->app->getModuleName();
$currentMethod = $this->app->getMethodName();
/* init currentModule and currentMethod for report and story. */
if($currentModule == 'story')
{
if($currentMethod != 'create' and $currentMethod != 'batchcreate') $currentModule = 'product';
if($currentMethod == 'view' || $currentMethod == 'change' || $currentMethod == 'review') $currentMethod = 'browse';
{
if($currentMethod != 'track' and $currentMethod != 'create' and $currentMethod != 'batchcreate') $currentModule = 'product';
if($currentMethod == 'view') $currentMethod = 'browse';
}
if($currentMethod == 'report') $currentMethod = 'browse';
$selectHtml = $this->select($products, $productID, $currentModule, $currentMethod, $extra, $branch, $module, $moduleType);
$label = $this->lang->product->index;
if($this->config->global->flow != 'full') $label = $this->lang->product->all;
if($currentModule == 'product' && $currentMethod == 'all') $label = $this->lang->product->all;
if($currentModule == 'product' && $currentMethod == 'create') $label = $this->lang->product->create;
$selectHtml = $this->select($products, $product->id, $currentModule, $currentMethod, $extra, $branch, $module, $moduleType);
$pageNav = '';
$isMobile = $this->app->viewType == 'mhtml';
if($isMobile)
{
{
$pageNav = html::a(helper::createLink('product', 'index'), $this->lang->product->index) . $this->lang->colon;
$pageNav .= $selectHtml;
}
else
{
$pageNav = '<div class="btn-group angle-btn' . ($currentMethod == 'index' ? ' active' : '') . '"><div class="btn-group"><button data-toggle="dropdown" type="button" class="btn">' . $label . ' <span class="caret"></span></button>';
$pageNav .= '<ul class="dropdown-menu">';
if($this->config->global->flow == 'full' && common::hasPriv('product', 'index')) $pageNav .= '<li>' . html::a(helper::createLink('product', 'index', 'locate=no'), '<i class="icon icon-home"></i> ' . $this->lang->product->index) . '</li>';
if(common::hasPriv('product', 'all')) $pageNav .= '<li>' . html::a(helper::createLink('product', 'all'), '<i class="icon icon-cards-view"></i> ' . $this->lang->product->all) . '</li>';
if(common::isTutorialMode())
{
$wizardParams = helper::safe64Encode('');
$link = helper::createLink('tutorial', 'wizard', "module=product&method=create&params=$wizardParams");
$pageNav .= '<li>' . html::a($link, "<i class='icon icon-plus'></i> {$this->lang->product->create}", '', "class='create-product-btn'") . '</li>';
}
else
{
if(common::hasPriv('product', 'create')) $pageNav .= '<li>' . html::a(helper::createLink('product', 'create'), '<i class="icon icon-plus"></i> ' . $this->lang->product->create) . '</li>';
}
$pageNav .= '</ul></div></div>';
$pageNav .= $selectHtml;
{
if(isset($project->category) and $project->category == 'multiple') $pageNav = $selectHtml;
}
$pageActions = '';
if($this->config->global->flow != 'full')
{
{
if($currentMethod == 'build' && common::hasPriv('build', 'create'))
{
{
$this->app->loadLang('build');
$pageActions .= html::a(helper::createLink('build', 'create', "productID=$productID"), "<i class='icon icon-plus'></i> {$this->lang->build->create}", '', "class='btn btn-primary'");
}
}
$this->lang->modulePageNav = $pageNav;
$this->lang->modulePageActions = $pageActions;
foreach($this->lang->product->menu as $key => $menu)
{
$replace = $productID;
common::setMenuVars($this->lang->product->menu, $key, $replace);
}
return $pageNav;
}
/**
@@ -330,6 +357,20 @@ class productModel extends model
->fetchPairs();
}
/**
* Get product id by project.
*
* @param int $projectID
* @access public
* @return array
*/
public function getProductIDByProject($projectID)
{
$products = $this->dao->select('product')->from(TABLE_PROJECTPRODUCT)->where('project')->eq($projectID)->fetchPairs();
return empty($products) ? 0 : current($products);
}
/**
* Get grouped products.
*
+1 -1
View File
@@ -11,7 +11,7 @@ class program extends control
public function index($status = 'doing', $orderBy = 'order_desc', $recTotal = 0, $recPerPage = 10, $pageID = 1)
{
if(common::hasPriv('program', 'create')) $this->lang->pageActions = html::a($this->createLink('program', 'create'), "<i class='icon icon-sm icon-plus'></i> " . $this->lang->program->create, '', "class='btn btn-primary'");
if(common::hasPriv('program', 'createGuide')) $this->lang->pageActions = html::a($this->createLink('program', 'createGuide'), "<i class='icon icon-sm icon-plus'></i> " . $this->lang->program->create, '', "class='btn btn-primary' data-toggle=modal");
$programType = $this->cookie->programType ? $this->cookie->programType : 'bylist';
+2 -1
View File
@@ -164,7 +164,8 @@ class programModel extends model
$dropMenuLink = helper::createLink('program', 'ajaxGetDropMenu', "objectID=$programID&module=$currentModule&method=$currentMethod&extra=$extra");
$output = "<div class='btn-group' id='swapper'><button data-toggle='dropdown' type='button' class='btn btn-limit' id='currentItem' title='{$currentProgramName}'>{$currentProgramName} <i class='icon icon-swap'></i></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>'; $output .= "</div></div>";
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
$output .= "</div></div>";
//if($isMobile) $output = "<a id='currentItem' href=\"javascript:showSearchMenu('project', '$projectID', '$currentModule', '$currentMethod', '$extra')\">{$currentProjectName} <span class='icon-caret-down'></span></a><div id='currentItemDropMenu' class='hidden affix enter-from-bottom layer'></div>";
return $output;
+1 -1
View File
@@ -49,7 +49,7 @@ foreach($programs as $program)
?>
</div>
<div class="col-footer">
<?php echo html::a(helper::createLink('program', 'create'), '<i class="icon icon-plus"></i>' . $lang->program->create, '', 'class="not-list-item text-primary"'); ?>
<?php echo html::a(helper::createLink('program', 'createGuide'), '<i class="icon icon-plus"></i>' . $lang->program->create, '', 'class="not-list-item text-primary" data-toggle=modal'); ?>
<div class='pull-right'>
<?php echo html::a(helper::createLink('program', 'index', 'status=all'), '<i class="icon icon-cards-view muted"></i> ' . $lang->project->all, '', 'class="not-list-item"'); ?>
<span class='text-muted muted'> &nbsp; | &nbsp; </span>
+1 -1
View File
@@ -40,7 +40,7 @@
<div id='mainContent' class='main-row'>
<?php if(empty($projectList)):?>
<div class="table-empty-tip">
<p><span class="text-muted"><?php echo $lang->program->noProgram;?></span> <?php common::printLink('program', 'create', '', "<i class='icon icon-plus'></i> " . $lang->program->create, '', "class='btn btn-info'");?></p>
<p><span class="text-muted"><?php echo $lang->program->noProgram;?></span> <?php common::printLink('program', 'createguide', '', "<i class='icon icon-plus'></i> " . $lang->program->create, '', "class='btn btn-info'");?></p>
</div>
<?php else:?>
<div class='main-col'>
+93 -52
View File
@@ -62,8 +62,42 @@ class projectModel extends model
*/
public function setMenu($projects, $projectID, $buildID = 0, $extra = '')
{
/* Check the privilege. */
$project = $this->getById($projectID);
if(!$projectID and $this->session->project) $projectID = $this->session->project;
/* Get project and program */
$project = $this->getById($projectID);
$isProgram = false;
$program = array();
if(!empty($project))
{
$isProgram = $project->template;
$program = $isProgram ? $project : $this->getByID($project->program);
}
if(empty($program)) $program = $this->getByID($this->session->program);
$projects = $this->getPairs();
if(empty($projects))
{
if($program->template == 'cmmi')
{
if(($this->app->moduleName == 'programplan' && $this->app->methodName != 'create') || $this->app->moduleName == 'project') die(js::locate(helper::createLink('programplan', 'create', "progarmID=$program->id")));
}
else
{
if($this->app->moduleName == 'project' && $this->app->methodName != 'create') die(js::locate(helper::createLink('project', 'create')));
}
}
if($isProgram)
{
$projectID = $this->session->project;
if(!$projectID or !in_array($projectID, array_keys($projects))) $projectID = key($projects);
}
$this->session->set('project', $projectID);
$products = $this->loadModel('product')->getPairs($program->id);
/* Unset story, bug, build and testtask if type is ops. */
if($project and $project->type == 'ops')
@@ -75,83 +109,70 @@ class projectModel extends model
unset($this->lang->project->subMenu->qa->testtask);
}
if($projects and !isset($projects[$projectID]) and !$this->checkPriv($projectID)) $this->accessDenied();
/* Hide story and qa menu when project is story or design type. */
if($project and ($project->attribute == 'story' || $project->attribute == 'design'))
{
unset($this->lang->project->menu->story);
unset($this->lang->project->menu->qa);
}
$moduleName = $this->app->getModuleName();
$methodName = $this->app->getMethodName();
if($this->cookie->projectMode == 'noclosed' and ($project->status == 'done' or $project->status == 'closed'))
{
setcookie('projectMode', 'all', 0, $this->config->webRoot, '', false, false);
setcookie('projectMode', 'all');
$this->cookie->projectMode = 'all';
}
$selectHtml = $this->select($projects, $projectID, $buildID, $moduleName, $methodName, $extra);
$label = $this->lang->project->index;
if($moduleName == 'project' && $methodName == 'all') $label = $this->lang->project->allProjects;
if($moduleName == 'project' && $methodName == 'create') $label = $this->lang->project->create;
$projectIndex = '';
$isMobile = $this->app->viewType == 'mhtml';
if($isMobile)
{
$projectIndex = html::a(helper::createLink('project', 'index'), $this->lang->project->index) . $this->lang->colon;
$projectIndex .= $selectHtml;
}
else
{
$projectIndex = '<div class="btn-group angle-btn' . ($methodName == 'index' ? ' active' : '') . '"><div class="btn-group"><button data-toggle="dropdown" type="button" class="btn">' . $label . ' <span class="caret"></span></button>';
$projectIndex .= '<ul class="dropdown-menu">';
if(common::hasPriv('project', 'index')) $projectIndex .= '<li>' . html::a(helper::createLink('project', 'index', 'locate=no'), '<i class="icon icon-home"></i> ' . $this->lang->project->index) . '</li>';
if(common::hasPriv('project', 'all')) $projectIndex .= '<li>' . html::a(helper::createLink('project', 'all', 'status=all'), '<i class="icon icon-cards-view"></i> ' . $this->lang->project->allProjects) . '</li>';
if(common::isTutorialMode())
{
$wizardParams = helper::safe64Encode('');
$link = helper::createLink('tutorial', 'wizard', "module=project&method=create&params=$wizardParams");
$projectIndex .= '<li>' . html::a($link, "<i class='icon icon-plus'></i> {$this->lang->project->create}", '', "class='create-project-btn'") . '</li>';
}
else
{
if(common::hasPriv('project', 'create')) $projectIndex .= '<li>' . html::a(helper::createLink('project', 'create'), '<i class="icon icon-plus"></i> ' . $this->lang->project->create, '') . '</li>';
}
$projectIndex .= '</ul></div></div>';
$projectIndex .= $selectHtml;
}
$this->lang->modulePageNav = $projectIndex;
if($moduleName != 'project') $this->lang->$moduleName->dividerMenu = $this->lang->project->dividerMenu;
if(!isset($this->lang->modulePageNav)) $this->lang->modulePageNav = $this->getModuleNav($projectID, $extra);
foreach($this->lang->project->menu as $key => $menu)
{
common::setMenuVars($this->lang->project->menu, $key, $projectID);
/* Replace for dropdown submenu. */
if(isset($this->lang->project->subMenu->$key))
{
{
$projectSubMenu = $this->lang->project->subMenu->$key;
$subMenu = common::createSubMenu($this->lang->project->subMenu->$key, $projectID);
if(!empty($subMenu))
{
{
foreach($subMenu as $menuKey => $menu)
{
$itemMenu = zget($projectSubMenu, $menuKey, '');
{
$itemMenu = zget($projectSubMenu, $menuKey, '');
$isActive['method'] = ($moduleName == strtolower($menu->link['module']) and $methodName == strtolower($menu->link['method']));
$isActive['alias'] = ($moduleName == strtolower($menu->link['module']) and (is_array($itemMenu) and isset($itemMenu['alias']) and strpos($itemMenu['alias'], $methodName) !== false));
$isActive['subModule'] = (is_array($itemMenu) and isset($itemMenu['subModule']) and strpos($itemMenu['subModule'], $moduleName) !== false);
if($isActive['method'] or $isActive['alias'] or $isActive['subModule'])
{
{
$this->lang->project->menu->{$key}['link'] = $menu->text . "|" . join('|', $menu->link);
break;
}
}
}
}
$this->lang->project->menu->{$key}['subMenu'] = $subMenu;
}
}
}
}
return true;
}
/**
* Set module page nav.
*
* @param int $activeID
* @param string $extra
* @access public
* @return string
*/
public function getModuleNav($projectID, $extra = '')
{
$moduleName = $this->app->getModuleName();
$methodName = $this->app->getMethodName();
$selectHtml = $this->select(null, $projectID, null, $moduleName, $methodName, $extra);
return $selectHtml; //暂时先隐藏掉迭代主页、单个创建迭代和所有迭代列表页面,统一使用计划阶段来管理
}
/**
@@ -175,8 +196,28 @@ class projectModel extends model
setCookie("lastProject", $projectID, $this->config->cookieLife, $this->config->webRoot, '', false, true);
$currentProject = $this->getById($projectID);
if(isset($currentProject->type) and $currentProject->type == 'program') return;
if(isset($currentProject->program))
$program = $this->getByID($currentProject->program);
if(isset($program->category) and $program->category == 'multiple')
{
$productID = $this->loadModel('product')->getProductIDByProject($currentProject->id);
$productName = $this->dao->findByID($productID)->from(TABLE_PRODUCT)->fetch('name');
if($currentProject->parent)
{
$parentInfo = $this->getById($currentProject->parent);
$currentProject->name = $parentInfo->name . '/' . $currentProject->name;
}
$currentProject->name = $productName . '/' . $currentProject->name;
}
$dropMenuLink = helper::createLink('project', 'ajaxGetDropMenu', "objectID=$projectID&module=$currentModule&method=$currentMethod&extra=$extra");
$output = "<div class='btn-group angle-btn'><div class='btn-group'><button data-toggle='dropdown' type='button' class='btn btn-limit' id='currentItem' title='{$currentProject->name}'>{$currentProject->name} <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
$currentProjectName = '';
if(isset($currentProject->name)) $currentProjectName = $currentProject->name;
$output = "<div class='btn-group angle-btn'><div class='btn-group'><button data-toggle='dropdown' type='button' class='btn btn-limit' id='currentItem' title='{$currentProjectName}'>{$currentProjectName} <span class='caret'></span></button><div id='dropMenu' class='dropdown-menu search-list' data-ride='searchList' data-url='$dropMenuLink'>";
$output .= '<div class="input-control search-box has-icon-left has-icon-right search-example"><input type="search" class="form-control search-input" /><label class="input-control-icon-left search-icon"><i class="icon icon-search"></i></label><a class="input-control-icon-right search-clear-btn"><i class="icon icon-close icon-sm"></i></a></div>';
$output .= "</div></div></div>";
if($isMobile) $output = "<a id='currentItem' href=\"javascript:showSearchMenu('project', '$projectID', '$currentModule', '$currentMethod', '$extra')\">{$currentProject->name} <span class='icon-caret-down'></span></a><div id='currentItemDropMenu' class='hidden affix enter-from-bottom layer'></div>";
+1 -1
View File
@@ -68,7 +68,7 @@ class riskModel extends model
->add('editedBy', $this->app->user->account)
->add('editedDate', helper::today())
->stripTags($this->config->risk->editor->track['id'], $this->config->allowedTags)
->remove('comment,uid')
->remove('ischange,comment,uid')
->removeIF($this->post->isChange == 0, 'name,category,strategy,impact,probability,riskindex,pri,prevention,resolution' )
->get();
+15
View File
@@ -0,0 +1,15 @@
<?php
class subject extends control
{
public function browse($currentModuleID = 0)
{
$this->view->title = $this->lang->subject->manage;
$this->view->position[] = $this->lang->subject->manage;
$this->view->modules = $this->loadModel('tree')->getTreeMenu(0, 'subject', 0, array('treeModel', 'createManageLink'));
$this->view->sons = $this->tree->getSons(0, $currentModuleID, 'subject');
$this->view->currentModuleID = $currentModuleID;
$this->view->tree = $this->tree->getProductStructure(0, 'subject');
$this->view->parentModules = $this->tree->getParents($currentModuleID);
$this->display();
}
}
+9
View File
@@ -0,0 +1,9 @@
.row-module {max-width: 500px; min-width: 400px;}
.row-module + .row-module {margin-top: 5px;}
.col-module {min-width: 200px;}
.col-shorts .form-control {border-radius: 0 2px 2px 0; border-left-width: 0;}
.col-shorts .form-control:focus {margin-left: -1px; border-left-width: 1px;}
.col-shorts {width: 110px;}
.col-actions {width: 80px; padding-left: 5px;}
#modulesTree li {padding-left: 20px;}
+29
View File
@@ -0,0 +1,29 @@
function addItem(obj)
{
var $inputRow = $(obj).closest('.row-module');
var $newRow = $('#insertItemBox').children('.row-module').clone().insertAfter($inputRow).addClass('highlight');
$newRow.find("input[type!='hidden']").val('');
setTimeout(function()
{
$newRow.removeClass('highlight');
}, 1600);
}
function insertItem(obj)
{
var $inputgroup = $(obj).closest('.row-table');
var insertHtml = $('#insertItemBox').children('.row-table').clone();
$inputgroup.after(insertHtml).next('.row-table').find('input').val('');
}
function deleteItem(obj)
{
var $inputRow = $(obj).closest('.row-module');
if ($inputRow.siblings('.row-module.row-module-new').find('.btn-delete').length > 0)
{
$inputRow.addClass('highlight').fadeOut(500, function()
{
$inputRow.remove();
});
}
}
+6
View File
@@ -0,0 +1,6 @@
<?php
$lang->subject->common = '科目';
$lang->subject->manage = '科目维护';
$lang->subject->manageChild = '维护子科目';
$lang->subject->name = '科目名称';
$lang->subject->browse = '浏览科目';
+212
View File
@@ -0,0 +1,212 @@
<?php
/**
* The browse view file of tree module of ZenTaoPMS.
*
* @copyright Copyright 2009-2015 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv12.html)
* @author Chunsheng Wang <chunsheng@cnezsoft.com>
* @package tree
* @version $Id: browse.html.php 4796 2013-06-06 02:21:59Z zhujinyonging@gmail.com $
* @link http://www.zentao.net
*/
?>
<?php include '../../common/view/header.html.php';?>
<div id="mainContent" class="main-row">
<div class="side-col col-4">
<div class="panel">
<div class="panel-heading">
<div class="panel-title"><?php echo $lang->subject->common;?></div>
</div>
<div class="panel-body">
<ul id='modulesTree' data-name='tree-subject'></ul>
</div>
</div>
</div>
<div class="main-col col-8">
<div class="panel">
<div class="panel-heading">
<div class="panel-title">
<?php echo $lang->subject->manageChild;?>
</div>
</div>
<div class="panel-body">
<form id='childrenForm' method='post' target='hiddenwin' action='<?php echo $this->createLink('tree', 'manageChild', "root=0&viewType=subject");?>'>
<table class='table table-form table-auto'>
<tr>
<td class="text-middle text-right with-padding">
<?php
foreach($parentModules as $module)
{
echo "<span>" . html::a($this->createLink('subject', 'browse', "moduleID=$module->id"), $module->name) . " <i class='icon icon-angle-right muted'></i></span>";
}
?>
</td>
<td>
<div id='sonModule'>
<?php $maxOrder = 0;?>
<?php foreach($sons as $sonModule):?>
<?php if($sonModule->order > $maxOrder) $maxOrder = $sonModule->order;?>
<div class="table-row row-module">
<div class="table-col col-module"><?php echo html::input("modules[id$sonModule->id]", $sonModule->name, 'class="form-control"');?></div>
<div class="table-col col-shorts"><?php echo html::input("shorts[id$sonModule->id]", $sonModule->short, "class='form-control' placeholder='{$lang->tree->short}'") . html::hidden("order[id$sonModule->id]", $sonModule->order);?></div>
<div class="table-col col-actions"> </div>
</div>
<?php endforeach;?>
<?php for($i = 0; $i < 5; $i ++):?>
<div class="table-row row-module row-module-new">
<div class="table-col col-module"><?php echo html::input("modules[]", '', "class='form-control' placeholder='{$lang->subject->name}'");?></div>
<div class="table-col col-shorts"><?php echo html::input("shorts[]", '', "class='form-control' placeholder='{$lang->tree->short}'");?></div>
<div class="table-col col-actions">
<button type="button" class="btn btn-link btn-icon btn-add" onclick="addItem(this)"><i class="icon icon-plus"></i></button>
<button type="button" class="btn btn-link btn-icon btn-delete" onclick="deleteItem(this)"><i class="icon icon-close"></i></button>
</div>
</div>
<?php endfor;?>
</div>
<div id="insertItemBox" class="template">
<div class="table-row row-module row-module-new">
<div class="table-col col-module"><?php echo html::input("modules[]", '', "class='form-control' placeholder='{$lang->subject->name}'");?></div>
<div class="table-col col-shorts"><?php echo html::input("shorts[]", '', "class='form-control' placeholder='{$lang->tree->short}'");?></div>
<div class="table-col col-actions">
<button type="button" class="btn btn-link btn-icon btn-add" onclick="addItem(this)"><i class="icon icon-plus"></i></button>
<button type="button" class="btn btn-link btn-icon btn-delete" onclick="deleteItem(this)"><i class="icon icon-close"></i></button>
</div>
</div>
</div>
</td>
</tr>
<tr>
<td></td>
<td colspan="2" class="form-actions">
<?php echo html::submitButton();?>
<?php echo html::backButton();?>
<?php echo html::hidden('parentModuleID', $currentModuleID);?>
<?php echo html::hidden('maxOrder', $maxOrder);?>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</div>
</div>
<script>
$(function()
{
var data = $.parseJSON('<?php echo helper::jsonEncode4Parse($tree);?>');
var options =
{
initialState: 'preserve',
data: data,
sortable:
{
lazy: true,
nested: true,
canMoveHere: function($ele, $target)
{
if($ele && $target && $ele.parent().closest('li').attr('data-id') !== $target.parent().closest('li').attr('data-id')) return false;
}
},
itemCreator: function($li, item)
{
var link = (item.id !== undefined && item.type != 'line') ? ('<a href="' + createLink('subject', 'browse', 'moduleID={0}'.format(item.id, item.branch)) + '">' + item.name + '</a>') : ('<span class="tree-toggle">' + item.name + '</span>');
var $toggle = $('<span class="module-name" data-id="' + item.id + '">' + link + '</span>');
if(item.type === 'bug') $toggle.append('&nbsp; <span class="text-muted">[B]</span>');
if(item.type === 'case') $toggle.append('&nbsp; <span class="text-muted">[C]</span>');
$li.append($toggle);
if(item.nodeType || item.type) $li.addClass('tree-item-' + (item.nodeType || item.type));
$li.toggleClass('active', <?php echo $currentModuleID ?> === item.id);
return true;
},
actions:
{
sort:
{
title: '<?php echo $lang->tree->dragAndSort ?>',
template: '<a class="sort-handler"><i class="icon-move"></i></a>'
},
//edit:
//{
// linkTemplate: '<?php echo helper::createLink('tree', 'edit', "moduleID={0}&type=subject"); ?>',
// title: '<?php echo $lang->tree->edit ?>',
// template: '<a><i class="icon-edit"></i></a>'
//},
"delete":
{
linkTemplate: '<?php echo helper::createLink('tree', 'delete', "rootID=0&moduleID={0}"); ?>',
title: '<?php echo $lang->tree->delete ?>',
template: '<a><i class="icon-trash"></i></a>'
},
subModules:
{
linkTemplate: '<?php echo helper::createLink('subject', 'browse', "moduleID={0}"); ?>',
title: '<?php echo $title;?>',
template: '<a><?php echo '<i class="icon-treemap-alt"></i>';?></a>',
}
},
action: function(event)
{
var action = event.action, $target = $(event.target), item = event.item;
if(action.type === 'edit')
{
new $.zui.ModalTrigger({
type: 'ajax',
url: action.linkTemplate.format(item.id),
keyboard: true
}).show();
}
else if(action.type === 'delete')
{
hiddenwin.location.href = action.linkTemplate.format(item.id);
}
else if(action.type === 'sort')
{
var orders = {};
$('#modulesTree').find('li:not(.tree-action-item)').each(function()
{
var $li = $(this);
if($li.hasClass('tree-item-branch')) return;
var item = $li.data();
orders['orders[' + item.id + ']'] = $li.attr('data-order') || item.order;
});
$.post('<?php echo $this->createLink('tree', 'updateOrder', "rootID=0&viewType=subject");?>', orders).error(function()
{
bootbox.alert(lang.timeout);
});
}
else if(action.type === 'subModules')
{
window.location.href = action.linkTemplate.format(item.id, item.branch);
}
}
};
if(<?php echo common::hasPriv('tree', 'updateorder') ? 'false' : 'true' ?>) options.actions["sort"] = false;
if(<?php echo common::hasPriv('tree', 'edit') ? 'false' : 'true' ?>) options.actions["edit"] = false;
if(<?php echo common::hasPriv('tree', 'delete') ? 'false' : 'true' ?>) options.actions["delete"] = false;
var $tree = $('#modulesTree').tree(options);
var tree = $tree.data('zui.tree');
if(<?php echo $currentModuleID ?>)
{
var $currentLi = $tree.find('.module-name[data-id=' + <?php echo $currentModuleID ?> + ']').closest('li');
if($currentLi.length) tree.show($currentLi);
}
$tree.on('mouseenter', 'li:not(.tree-action-item)', function(e)
{
$('#modulesTree').find('li.hover').removeClass('hover');
$(this).addClass('hover');
e.stopPropagation();
});
$('#subNavbar > ul > li > a[href*=tree][href*=browse]').not('[href*=subject]').parent().removeClass('active');
if(window.config.viewType == 'line') $('#modulemenu > .nav > li > a[href*=product][href*=all]').parent('li[data-id=all]').addClass('active');
});
</script>
<?php include '../../common/view/footer.html.php';?>
+4
View File
@@ -0,0 +1,4 @@
<?php
$config->workestimation = new stdclass;
$config->workestimation->index = new stdclass;
$config->workestimation->index->requiredFields = 'scale,productivity,scale,duration,unitLaborCost,totalLaborCost';
+43
View File
@@ -0,0 +1,43 @@
<?php
/**
* The control file of workestimation of ChanzhiEPS.
*
* @copyright Copyright 2009-2010 QingDao Nature Easy Soft Network Technology Co,LTD (www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv11.html)
* @author Xiying Guan <guanxiying@xirangit.com>
* @package workestimation
* @version $Id$
* @link http://www.chanzhi.org
*/
class workestimation extends control
{
public function index($program)
{
if($_POST)
{
$result = $this->workestimation->save($program);
if($result) $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $this->server->http_referer));
$this->send(array('result' => 'fail', 'message' => dao::getError()));
}
$this->view->title = $this->lang->workestimation->common;
$this->view->programScale = $this->workestimation->getProgramScale($program);
$this->view->hourPoint = $this->config->custom->hourPoint;
$budget = $this->workestimation->getBudget($program);
if(!isset($this->config->project)) $this->config->project = new stdclass();
if(empty($budget))
{
$this->app->loadConfig('estimate');
$budget = new stdclass();
$budget->scale = $this->view->programScale;
$budget->productivity = zget($this->config->custom, 'efficiency', '');
$budget->unitLaborCost = zget($this->config->custom, 'cost', '');
$budget->dayHour = zget($this->config->project, 'defaultWorkhours', '');
}
$this->view->budget = $budget;
$this->display();
}
}
+2
View File
@@ -0,0 +1,2 @@
$('#scale+span').css('padding', '5px 27px');
$('#duration+span').css('padding', '5px 33px')
+19
View File
@@ -0,0 +1,19 @@
<?php
$lang->workestimation->common = '工作量估算';
$lang->workestimation->index = '总览';
$lang->workestimation->scale = '规模';
$lang->workestimation->productivity = '生产率';
$lang->workestimation->duration = '估算总工时';
$lang->workestimation->unitLaborCost = '单位人工成本';
$lang->workestimation->totalLaborCost = '估算人工成本';
$lang->workestimation->dayHour = '每日工时';
$lang->workestimation->hour = '工时';
$lang->workestimation->programScaleTip = "当前项目实际规模:<strong>%s{$lang->hourCommon}</strong> <a href='###' id='useScale' class='btn btn-xs'>使用</span>";
$lang->workestimation->placeholder = new stdclass();
$lang->workestimation->placeholder->scale = '';
$lang->workestimation->placeholder->productivity = '';
$lang->workestimation->placeholder->duration = '';
$lang->workestimation->placeholder->unitLaborCost = '';
$lang->workestimation->placeholder->totalLaborCost = '';
+49
View File
@@ -0,0 +1,49 @@
<?php
/**
* The model file of workestimation module of ChanzhiEPS.
*
* @copyright Copyright 2009-2010 QingDao Nature Easy Soft Network Technology Co,LTD (www.cnezsoft.com)
* @license ZPL (http://zpl.pub/page/zplv11.html)
* @author Xiying Guan <guanxiying@xirangit.com>
* @package workestimation
* @version $Id$
* @link http://www.chanzhi.org
*/
class workestimationModel extends model
{
public function getBudget($program)
{
return $this->dao->select('*')->from(TABLE_WORKESTIMATION)->where('program')->eq($program)->fetch();
}
public function getProgramScale($program)
{
$products = $this->loadModel('product')->getPairs($program);
$productIdList = array_keys($products);
return $this->dao->select('cast(sum(estimate) as decimal(10,2)) as scale')->from(TABLE_STORY)->where('product')->in($productIdList)->andWhere('type')->eq('requirement')->fetch('scale');
}
public function save($program)
{
$budget = $this->getBudget($program);
$postBudget = fixer::input('post')->get();
$postBudget->program = $program;
if(empty($budget))
{
$this->dao->insert(TABLE_WORKESTIMATION)
->batchcheck($this->config->workestimation->index->requiredFields, 'notempty')
->data($postBudget)
->exec();
}
else
{
$postBudget->id = $budget->id;
$this->dao->replace(TABLE_WORKESTIMATION)
->batchcheck($this->config->workestimation->index->requiredFields, 'notempty')
->data($postBudget)
->exec();
}
return !dao::isError();
}
}
+97
View File
@@ -0,0 +1,97 @@
<?php include '../../common/view/header.html.php';?>
<style>.unify-padding{width:94px;}</style>
<div id='mainContent' class='main-content'>
<div class='center-block'>
<div class='main-header'>
<h2><?php echo $lang->workestimation->common;?></h2>
</div>
<form class='load-indicator main-form form-ajax' id='dataform' method='post' enctype='multipart/form-data'>
<table class='table table-form'>
<tbody>
<tr>
<th class='w-100px'><?php echo $lang->workestimation->scale;?></th>
<td class='w-300px'>
<div class='input-group'>
<?php echo html::input('scale', zget($budget, 'scale', ''), "class='form-control' required");?>
<span class='input-group-addon unify-padding'><?php echo $lang->hourCommon;?></span>
</div>
</td>
<td><?php if(isset($budget->duration) and $budget->duration) printf($lang->workestimation->programScaleTip, $programScale);?></td>
<td></td>
<td></td>
</tr>
<tr>
<th><?php echo $lang->workestimation->productivity;?></th>
<td>
<div class='input-group'>
<?php echo html::input('productivity', zget($budget, 'productivity', ''), "class='form-control'");?>
<span class='input-group-addon unify-padding'>
<?php echo $hourPoint == 3 ? $lang->custom->unitList['manhour'] . $lang->custom->unitList['loc'] : $lang->custom->unitList['efficiency'] . $lang->hourCommon;?>
</span>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->workestimation->duration;?></th>
<td>
<div class='input-group'>
<?php echo html::input('duration', zget($budget, 'duration', ''), "class='form-control'");?>
<span class='input-group-addon unify-padding'><?php echo $lang->workestimation->hour;?></span>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->workestimation->unitLaborCost;?></th>
<td>
<div class='input-group'>
<?php echo html::input('unitLaborCost', zget($budget, 'unitLaborCost', ''), "class='form-control'");?>
<span class='input-group-addon unify-padding'><?php echo $lang->custom->unitList['cost'];?></span>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->workestimation->totalLaborCost;?></th>
<td>
<div class='input-group'>
<?php echo html::input('totalLaborCost', zget($budget, 'totalLaborCost', ''), "class='form-control'");?>
</div>
</td>
</tr>
<tr>
<th><?php echo $lang->workestimation->dayHour;?></th>
<td><?php echo html::input('dayHour', zget($budget, 'dayHour', ''), "class='form-control'");?></td>
</tr>
<tr>
<td></td>
<td colspan='2' class='text-left form-actions'>
<?php echo html::submitButton();?>
<?php echo html::backButton();?>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
<script>
$(function()
{
$('#useScale').click(function()
{
$('#scale').val('<?php echo $programScale;?>').keyup();
});
$(':input').keyup(function()
{
duration = parseFloat($('#scale').val()) * parseFloat($('#productivity').val());
if(!isNaN(duration)) $('#duration').val(duration);
if(isNaN(duration)) $('#duration').val('');
totalLaborCost = parseFloat($('#unitLaborCost').val()) * parseFloat($('#duration').val());
if(!isNaN(totalLaborCost)) $('#totalLaborCost').val(totalLaborCost);
if(isNaN(totalLaborCost)) $('#totalLaborCost').val('');
});
$('#scale').change();
});
</script>
<?php include '../../common/view/footer.html.php';?>