This commit is contained in:
liyang
2023-05-04 16:47:38 +08:00
8 changed files with 176 additions and 126 deletions
+1 -1
View File
@@ -1816,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')->getList('all', 'id_desc', 1, $pager);
$this->view->projects = $this->loadModel('project')->getList('all', 'id_desc', true, $pager);
}
/**
+13 -5
View File
@@ -73,7 +73,7 @@ class project extends control
if(isset($fields['hasProduct'])) $fields['hasProduct'] = $projectLang->type;
$projects = $this->project->getList($status, $orderBy, null);
$projects = $this->project->getList($status, $orderBy);
$users = $this->loadModel('user')->getPairs('noletter');
$this->loadModel('product');
@@ -1930,8 +1930,8 @@ class project extends control
}
/**
* 管理项目下的关联产品
* Manage products.
* 管理项目的关联产品
* Manage products under project.
*
* @param string $projectID
* @param string $from project|program|programproject
@@ -1941,6 +1941,7 @@ class project extends control
*/
public function manageProducts(string $projectID, $from = 'project'): mixed
{
/* Access the nonProduct project alter tips. */
$projectID = (int)$projectID;
$project = $this->project->getById($projectID);
if(!$project->hasProduct) return print(js::error($this->lang->project->cannotManageProducts) . js::locate('back'));
@@ -1957,6 +1958,7 @@ class project extends control
return $this->send(array('result' => 'fail', 'message' => dao::getError()));
}
/* Update linked products. */
$this->projectZen->mergeProducts($projectID, $project, $executionIDs, $postData);
$locateLink = inLink('manageProducts', "projectID=$projectID");
@@ -1964,9 +1966,10 @@ class project extends control
return $this->send(array('result' => 'success', 'message' => $this->lang->saveSuccess, 'locate' => $locateLink));
}
/* Set menu. */
if($this->app->tab == 'program')
{
$this->program->setMenu($project->parent);
$this->loadModel('program')->setMenu($project->parent);
}
else if($this->app->tab == 'project')
{
@@ -1974,7 +1977,12 @@ class project extends control
}
$this->projectZen->dealLinkProduct($projectID, $project);
$this->projectZen->buildMangedProductForm($projectID, $project, $executions);
$this->view->title = $this->lang->project->manageProducts . $this->lang->colon . $project->name;
$this->view->project = $project;
$this->view->executions = $executions;
$this->view->branches = $this->project->getBranchesByProject($projectID);
$this->display();
}
/**
+2 -2
View File
@@ -236,12 +236,12 @@ class projectModel extends model
*
* @param string $status
* @param string $orderBy
* @param bool $involved
* @param int $pager
* @param int $involved
* @access public
* @return array
*/
public function getList($status = 'undone', $orderBy = 'order_desc', $pager = null, $involved = 0)
public function getList(string $status = 'undone', string $orderBy = 'order_desc', bool $involved = false, object|null $pager = null): array
{
/* Init vars. */
$projects = $this->projectTao->fetchProjectList($status, $orderBy, $involved, $pager);
+7 -7
View File
@@ -517,18 +517,18 @@ class projectTao extends projectModel
}
/**
* 将旧的产品替换成新的
* replace oldProduct
* 查找项目执行下关联的产品
* Get linked products with execution under the project.
*
* @param array $executionIDs
*
* @access protected
* @return bool
* @return array
*/
protected function replaceOldProduct(array $executionIDs): bool
protected function getExecutionProductGroup(array $executionIDs): array
{
$oldExecutionProducts = $this->dao->select('project,product')->from(TABLE_PROJECTPRODUCT)->where('project')->in($executionIDs)->fetchGroup('project', 'product');
return !dao::isError();
return $oldExecutionProducts;
}
/**
@@ -537,12 +537,12 @@ class projectTao extends projectModel
*
* @param string $status
* @param string $orderBy
* @param int $involved
* @param bool $involved
* @param object $pager
* @access protected
* @return array
*/
protected function fetchProjectList(string $status, string $orderBy, int $involved, object|null $pager): array
protected function fetchProjectList(string $status, string $orderBy, bool $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')
+46 -15
View File
@@ -1,28 +1,59 @@
#!/usr/bin/env php
<?php
include dirname(__FILE__, 5) . "/test/lib/init.php";
include dirname(__FILE__, 2) . '/project.class.php';
su('admin');
zdTable('project')->gen(90);
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::getInfoList;
title=测试 projectModel::fetchProjectList();
timeout=0
cid=1
*/
global $tester;
$tester->loadModel('project');
initData();
$statusList = array('', 'all', 'undone', 'unclosed', 'error');
$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('90'); //查询所有状态的项目数量
$projectTester = new Project();
r($projectTester->testGetList($statusList[0])) && p() && e('0'); // 查询状态为空的项目
r(count($projectTester->testGetList($statusList[1]))) && p() && e('9'); // 获取所有项目数量
r($projectTester->testGetList($statusList[2])) && p('11:code') && e('project11'); // 查询未完成的第一个项目的code
r($projectTester->testGetList($statusList[3], true)) && p('12:name') && e('项目12'); // 获取我参与的一个项目的项目名
r($projectTester->testGetList($statusList[4])) && p() && e('0'); // 获取错误类型的项目
+16 -3
View File
@@ -215,12 +215,25 @@ class Project
* Test fetchProjectList function.
*
* @param int $status
* @param string $orderBy
* @param int $involved
* @param bool $involved
* @access public
* @return array
*/
public function testFetchProjectList($status, $involved = 0)
public function testFetchProjectList($status, $involved = false)
{
$projects = $this->project->fetchProjectList($status, 'id_desc', $involved, null);
return $projects;
}
/**
* Test getList function.
*
* @param int $status
* @param bool $involved
* @access public
* @return array
*/
public function testGetList($status, $involved = false)
{
$projects = $this->project->fetchProjectList($status, 'id_desc', $involved, null);
return $projects;
+1 -1
View File
@@ -55,5 +55,5 @@ $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[3], true)) && p('12:name') && e('项目12'); // 获取我参与的一个项目的项目名
r($projectTester->testFetchProjectList($statusList[4])) && p() && e('0'); // 获取错误类型的项目
+90 -92
View File
@@ -652,8 +652,8 @@ class projectZen extends project
}
/**
* 处理并合并项目下的新旧产品
* mergeProducts
* 关联产品时,合并项目下的新旧产品
* Merge old and new products under the project When link products.
*
* @param int $projectID
* @param object $project
@@ -672,21 +672,20 @@ class projectZen extends project
$this->project->updateProducts($projectID);
if(dao::isError()) return $this->send(array('result' => 'fail', 'message' => dao::getError()));
//判断是否为项目型项目并更新关联产品
if(empty($project->multiple))
{
$executionID = $this->execution->getNoMultipleID($projectID);
if($executionID) $this->execution->updateProducts($executionID);
}
//将项目下关联的新旧产品合并
/* Merge old and new linked products under the project. */
$newProducts = $this->product->getProducts($projectID);
$oldProductIDs = array_keys($oldProducts);
$newProductIDs = array_keys($newProducts);
$diffProducts = array_merge(array_diff($oldProductIDs, $newProductIDs), array_diff($newProductIDs, $oldProductIDs));
if($diffProducts) $this->loadModel('action')->create('project', $projectID, 'Managed', '', !empty($postData->rawdata->products) ? implode(',', $postData->rawdata->products) : '');
//判断是否为产品型项目并更新关联产品
/* Multiple and Division project update linked products. */
if(empty($project->multiple))
{
$executionID = $this->execution->getNoMultipleID($projectID);
if($executionID) $this->execution->updateProducts($executionID);
}
if(empty($project->division))
{
foreach($executionIDs as $executionID)
@@ -696,48 +695,47 @@ class projectZen extends project
}
}
//处理非瀑布及产品型项目
$this->dealExecutionProduct($project, $oldProducts, $newProductIDs, $executionIDs);
/* Record multiple and waterfall project unlinked products. */
if($project->multiple and $project->model != 'waterfall' and $project->model != 'waterfallplus')
{
$this->dealUnlinkedProduct($project, $oldProducts, $newProductIDs, $executionIDs);
}
}
/**
* 处理项目执行下关联产品
* deal execution product
* 记录多迭代及瀑布类项目移除的产品
* Record multiple and waterfall project unlinked products
*
* @param object $project
* @param object $oldProducts
* @param array $oldProducts
* @param array $newProductIDs
* @param int|array $executionIDs
*
* @access protected
* @return void
*/
protected function dealExecutionProduct(object $project, object $oldProducts, array $newProductIDs, array $executionIDs): void
protected function dealUnlinkedProduct(object $project, array $oldProducts, array $newProductIDs, array $executionIDs): void
{
//处理非瀑布及产品型项目
if($project->multiple and $project->model != 'waterfall' and $project->model != 'waterfallplus')
$oldExecutionProducts = $this->projectTao->getExecutionProductGroup($executionIDs);
$unlinkedProducts = array_diff(array_keys($oldProducts), $newProductIDs);
if(!empty($unlinkedProducts))
{
$oldExecutionProducts = $this->projectTao->replaceOldProduct($executionIDs);
$unlinkedProducts = array_diff(array_keys($oldProducts), $newProductIDs);
if(!empty($unlinkedProducts))
$unlinkedProductPairs = array();
foreach($unlinkedProducts as $unlinkedProduct) $unlinkedProductPairs[$unlinkedProduct] = $oldProducts[$unlinkedProduct]->name;
$unlinkExecutions = array();
foreach($oldExecutionProducts as $executionID => $executionProducts)
{
$unlinkedProductPairs = array();
foreach($unlinkedProducts as $unlinkedProduct) $unlinkedProductPairs[$unlinkedProduct] = $oldProducts[$unlinkedProduct]->name;
$unlinkExecutions = array();
foreach($oldExecutionProducts as $executionID => $executionProducts)
{
$unlinkExecutionProducts = array_intersect_key($unlinkedProductPairs, $executionProducts);
if($unlinkExecutionProducts) $unlinkExecutions[$executionID] = $unlinkExecutionProducts;
}
foreach($unlinkExecutions as $executionID => $unlinkExecutionProducts) $this->loadModel('action')->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkExecutionProducts));
$unlinkExecutionProducts = array_intersect_key($unlinkedProductPairs, $executionProducts);
if($unlinkExecutionProducts) $unlinkExecutions[$executionID] = $unlinkExecutionProducts;
}
foreach($unlinkExecutions as $executionID => $unlinkExecutionProducts) $this->loadModel('action')->create('execution', $executionID, 'unlinkproduct', '', implode(',', $unlinkExecutionProducts));
}
}
/**
* 处理项目关联需求的产品
* 项目关联用户故事则无法移除产品
* dealLinkProduct
*
* @param int $projectID
@@ -759,7 +757,6 @@ class projectZen extends project
$linkedProducts = $this->product->getProducts($projectID, 'all', '', true, $linkedProductIdList);
$projectStories = $this->project->getStoriesByProject($projectID);
$projectBranches = $this->project->getBranchGroupByProject($projectID, array_keys($linkedProducts));
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed', $linkedBranchIdList);
/* If the story of the product which linked the project,don't allow to remove the product. */
$unmodifiableProducts = array();
@@ -782,86 +779,87 @@ class projectZen extends project
}
}
$this->dealOtherLinkProduct($project, $branchGroups, $linkedBranches);
/* Initializes the product from other linked products. */
if($this->config->systemMode == 'ALM') $this->InitOtherLinkProduct($project, $allProducts, $linkedBranchIdList, $linkedBranches, $linkedProducts);
$this->view->allBranches = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal');
$this->view->allProducts = $allProducts;
$this->view->unmodifiableProducts = $unmodifiableProducts;
$this->view->unmodifiableBranches = $unmodifiableBranches;
$this->view->unmodifiableMainBranches = $unmodifiableMainBranches;
$this->view->linkedBranches = $linkedBranches;
$this->view->branchGroups = $branchGroups;
}
/**
* dealOtherLinkProduct
* 初始化项目集下其他关联产品中当前产品
* Initializes the current product under the projectprogram.
*
* @param object $project
* @param object $branchGroups
* @param array $allProducts
* @param array $linkedBranchIdList
* @param array $linkedBranches
* @param array $linkedProducts
*
* @access protected
* @return void
*/
protected function dealOtherLinkProduct(object $project, object $branchGroups, array $linkedBranches): void
protected function InitOtherLinkProduct(object $project, array $allProducts, array $linkedBranchIdList, array $linkedBranches, array $linkedProducts): void
{
$linkedProducts = $this->product->getProducts($projectID, 'all', '', true, $linkedProductIdList);
$branchGroups = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal|noclosed', $linkedBranchIdList);
$topProgramID = $project->parent ? $this->program->getTopByPath($project->path) : 0;
$productsGroupByProgram = $this->loadModel('product')->getProductsGroupByProgram();
if($this->config->systemMode == 'ALM')
$currentProducts = array();
foreach($productsGroupByProgram as $programID => $programProducts)
{
$topProgramID = $project->parent ? $this->program->getTopByPath($project->path) : 0;
$productsGroupByProgram = $this->product->getProductsGroupByProgram();
$currentProducts = array();
$otherProducts = array();
foreach($productsGroupByProgram as $programID => $programProducts)
if($programID != $topProgramID)
{
if($programID != $topProgramID)
{
foreach($programProducts as $productID => $productName)
{
if(!empty($branchGroups[$productID]))
{
foreach($branchGroups[$productID] as $branchID => $branchName)
{
if(isset($linkedProducts[$productID]) and isset($linkedBranches[$productID][$branchID])) continue;
$otherProducts = $this->InitBranchProduct($programProducts, $branchGroups, $linkedBranches, $linkedProducts);
}
else
{
$currentProducts += $programProducts;
}
}
$this->view->currentProducts = $currentProducts;
$this->view->otherProducts = $otherProducts;
$otherProducts["{$productID}_{$branchID}"] = $productName . '_' . $branchName;
}
}
else
{
if(isset($linkedProducts[$productID])) continue;
$otherProducts[$productID] = $productName;
}
}
}
else
$this->view->branchGroups = $branchGroups;
$this->view->linkedBranches = $linkedBranches;
$this->view->linkedProducts = $linkedProducts;
$this->view->allProducts = $allProducts;
$this->view->allBranches = $this->loadModel('branch')->getByProducts(array_keys($allProducts), 'ignoreNormal');
}
/**
* 初始化项目集下其他关联产品中多分支产品
* Initializes the multi-branch product under the projectprogram.
*
* @param object $programProducts
* @param array $branchGroups
* @param array $linkedBranches
* @param array $linkedProducts
*
* @access protected
* @return array
*/
protected function InitBranchProduct(object $programProducts, array $branchGroups, array $linkedBranches, array $linkedProducts): array
{
$otherProducts = array();
foreach($programProducts as $productID => $productName)
{
if(!empty($branchGroups[$productID]))
{
foreach($branchGroups[$productID] as $branchID => $branchName)
{
$currentProducts += $programProducts;
if(isset($linkedProducts[$productID]) and isset($linkedBranches[$productID][$branchID])) continue;
$otherProducts["{$productID}_{$branchID}"] = $productName . '_' . $branchName;
}
}
$this->view->currentProducts = $currentProducts;
$this->view->otherProducts = $otherProducts;
else
{
if(isset($linkedProducts[$productID])) continue;
$otherProducts[$productID] = $productName;
}
}
$this->view->linkedProducts = $linkedProducts;
}
/**
* buildMangedProductForm
*
* @param int $projectID
* @param object $project
*
* @access protected
* @return void
*/
protected function buildMangedProductForm(int $projectID, $project, $executions): void
{
$this->view->title = $this->lang->project->manageProducts . $this->lang->colon . $project->name;
$this->view->project = $project;
$this->view->executions = $executions;
$this->view->branches = $this->project->getBranchesByProject($projectID);
$this->display();
return $otherProducts;
}
}