From 65ecca81840e06fec344a2af33c295a3a58e7e76 Mon Sep 17 00:00:00 2001 From: daitingting Date: Fri, 7 Feb 2025 07:21:20 +0000 Subject: [PATCH] * [task#137010,done,3h] Add product release block. --- module/doc/config.php | 2 +- module/release/control.php | 35 +++++++++-- module/release/css/browse.ui.css | 1 + module/release/js/browse.ui.js | 39 ++++++++++++ module/release/ui/browse.html.php | 98 ++++++++++++++++++++++++++++--- 5 files changed, 161 insertions(+), 14 deletions(-) diff --git a/module/doc/config.php b/module/doc/config.php index fa6106455a..c07a600aa0 100644 --- a/module/doc/config.php +++ b/module/doc/config.php @@ -141,7 +141,7 @@ $config->doc->zentaoList['bug']['subMenu'][] = array('key' => 'productBug', 'nam $config->doc->zentaoList['bug']['subMenu'][] = array('key' => 'planBug', 'name' => $lang->doc->zentaoList['planBug'] . $lang->doc->list, 'icon' => 'productplan', 'module' => 'productplan', 'method' => 'bug', 'params' => 'productID=0&planID=0&blockID=0', 'priv' => 'productplanView'); $config->doc->zentaoList['more']['subMenu'][] = array('key' => 'productPlan', 'name' => $lang->doc->zentaoList['productPlan'] . $lang->doc->list, 'icon' => 'productplan', 'module' => 'productplan', 'method' => 'browse', 'params' => 'productID=0&branch=&browseType=undone&queryID=0&orderBy=begin_desc&recTotal=0&recPerPage=20&pageID=1&from=doc', 'priv' => 'productplanBrowse'); -//$config->doc->zentaoList['more']['subMenu'][] = array('key' => 'productRelease', 'name' => $lang->doc->zentaoList['productRelease'] . $lang->doc->list, 'icon' => 'send', 'module' => 'product', 'method' => 'browse', 'params' => '', 'priv' => 'releaseBrowse'); +$config->doc->zentaoList['more']['subMenu'][] = array('key' => 'productRelease', 'name' => $lang->doc->zentaoList['productRelease'] . $lang->doc->list, 'icon' => 'send', 'module' => 'release', 'method' => 'browse', 'params' => 'productID=0&branch=all&type=all&orderBy=¶m=0&recTotal=0&recPerPage=20&pageID=1&from=doc', 'priv' => 'releaseBrowse'); $config->doc->zentaoList['more']['subMenu'][] = array('key' => 'ER', 'name' => $lang->doc->zentaoList['ER'] . $lang->doc->list, 'icon' => 'lightbulb-alt', 'module' => 'product', 'method' => 'browse', 'params' => 'productID=0&branch=all&browseType=¶m=0&storyType=epic&orderBy=&recTotal=0&recPerPage=20&pageID=1&projectID=0&from=doc', 'priv' => 'epicBrowse'); $config->doc->zentaoList['more']['subMenu'][] = array('key' => 'UR', 'name' => $lang->doc->zentaoList['UR'] . $lang->doc->list, 'icon' => 'customer', 'module' => 'product', 'method' => 'browse', 'params' => 'productID=0&branch=all&browseType=¶m=0&storyType=requirement&orderBy=&recTotal=0&recPerPage=20&pageID=1&projectID=0&from=doc', 'priv' => 'requirementBrowse'); diff --git a/module/release/control.php b/module/release/control.php index 24bd7b7050..d906935ce8 100755 --- a/module/release/control.php +++ b/module/release/control.php @@ -26,9 +26,9 @@ class release extends control $this->loadModel('product')->setMenu($productID, $branch); $product = $this->product->getById($productID); - $products = $this->product->getPairs('all', 0, '', 'all'); if(empty($product)) $this->locate($this->createLink('product', 'create')); + $products = $this->product->getPairs('all', 0, '', 'all'); $this->product->checkAccess($productID, $products); $this->view->product = $product; @@ -48,20 +48,35 @@ class release extends control * @param int $recTotal * @param int $recPerPage * @param int $pageID + * @param string $from + * @param int $blockID * @access public * @return void */ - public function browse(int $productID, string $branch = 'all', string $type = 'all', string $orderBy = 't1.date_desc', string $param = '', int $recTotal = 0, int $recPerPage = 20, int $pageID = 1) + public function browse(int $productID, string $branch = 'all', string $type = 'all', string $orderBy = 't1.date_desc', string $param = '', int $recTotal = 0, int $recPerPage = 20, int $pageID = 1, string $from = 'product', int $blockID = 0) { + if($from === 'doc') + { + $this->app->loadLang('doc'); + + $products = $this->loadModel('product')->getPairs('all', 0, '', 'all'); + if(empty($products)) return $this->send(array('result' => 'fail', 'message' => $this->lang->doc->tips->noProduct)); + + if(!$productID) $productID = key($products); + + $this->view->products = $products; + } + + $this->commonAction($productID, $branch); + $this->app->loadClass('pager', true); $pager = new pager($recTotal, $recPerPage, $pageID); - $this->commonAction($productID, $branch); $uri = $this->app->getURI(true); $this->session->set('releaseList', $uri, 'product'); $this->session->set('buildList', $uri); - $showBranch = $this->view->product->type != 'normal'; + $showBranch = $this->view->product->type != 'normal'; if(!$showBranch) { unset($this->config->release->dtable->fieldList['branch']); @@ -73,7 +88,7 @@ class release extends control if(strpos($sort, 'branchName_') !== false) $sort = str_replace('branchName_', 'branch_', $sort); $queryID = $type == 'bySearch' ? (int)$param : 0; - $actionURL = $this->createLink('release', 'browse', "productID={$productID}&branch={$branch}&type=bySearch&orderBy={$sort}¶m=myQueryID"); + $actionURL = $this->createLink('release', 'browse', "productID={$productID}&branch={$branch}&type=bySearch&orderBy={$sort}¶m=myQueryID&recTotal=$recTotal&recPerPage=$recPerPage&pageID=$pageID&from=$from&blockID=$blockID"); $this->releaseZen->buildSearchForm($queryID, $actionURL, $this->view->product, $branch); $releaseQuery = $type == 'bySearch' ? $this->releaseZen->getSearchQuery($queryID) : ''; @@ -94,6 +109,16 @@ class release extends control $this->view->branchPairs = $this->loadModel('branch')->getPairs($productID); $this->view->appList = $this->loadModel('system')->getPairs(); $this->view->childReleases = $this->release->getListByCondition(explode(',', $children), 0, true); + $this->view->from = $from; + $this->view->blockID = $blockID; + $this->view->idList = ''; + + if($from === 'doc') + { + $content = $this->loadModel('doc')->getDocBlockContent($blockID); + $this->view->idList = zget($content, 'idList', ''); + } + $this->display(); } diff --git a/module/release/css/browse.ui.css b/module/release/css/browse.ui.css index 5dfd6ed9bc..bb4db1fc33 100644 --- a/module/release/css/browse.ui.css +++ b/module/release/css/browse.ui.css @@ -1 +1,2 @@ .red{color: red;} +.mb-4-important{margin-bottom: 12px!important} diff --git a/module/release/js/browse.ui.js b/module/release/js/browse.ui.js index c9dd59d788..ef677878c8 100644 --- a/module/release/js/browse.ui.js +++ b/module/release/js/browse.ui.js @@ -46,3 +46,42 @@ window.getCellSpan = function(cell) return {rowSpan: cell.row.data.rowspan}; } } + +window.insertListToDoc = function() +{ + const dtable = zui.DTable.query($('#releases')); + const checkedList = dtable.$.getChecks(); + if(!checkedList.length) return; + + let {cols, data} = dtable.options; + data = data.filter((item) => checkedList.includes(item.id + '')); + const docID = getDocApp()?.docID; + + const blockType = 'productRelease'; + const url = $.createLink('doc', 'buildZentaoList', `docID=${docID}&type=${blockType}&blockID=${blockID}`); + const formData = new FormData(); + formData.append('cols', JSON.stringify(cols)); + formData.append('data', JSON.stringify(data)); + formData.append('idList', checkedList.join(',')); + formData.append('url', insertListLink); + $.post(url, formData, function(resp) + { + resp = JSON.parse(resp); + if(resp.result == 'success') + { + const oldBlockID = resp.oldBlockID; + const newBlockID = resp.newBlockID; + zui.Modal.hide(); + window.insertZentaoList && window.insertZentaoList(blockType, newBlockID, null, oldBlockID); + } + }); +} + +window.firstRendered = false; +window.toggleCheckRows = function(idList) +{ + if(!idList?.length || firstRendered) return; + firstRendered = true; + const dtable = zui.DTable.query($('#releases')); + dtable.$.toggleCheckRows(idList.split(','), true); +} diff --git a/module/release/ui/browse.html.php b/module/release/ui/browse.html.php index 8a6a4c5c1a..33f189e865 100644 --- a/module/release/ui/browse.html.php +++ b/module/release/ui/browse.html.php @@ -10,16 +10,79 @@ declare(strict_types=1); */ namespace zin; -dropmenu(); +$isFromDoc = $from == 'doc'; + +$isFromDoc ? null : dropmenu(); + +if($isFromDoc) +{ + jsVar('blockID', $blockID); + + $this->app->loadLang('doc'); + $productChangeLink = createLink('release', 'browse', "productID={productID}&branch=$branch&type=$type&orderBy=$orderBy¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&from=$from&blockID=$blockID"); + + jsVar('insertListLink', createLink('release', 'browse', "productID={$product->id}&branch=$branch&type=$type&orderBy=$orderBy¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&from=$from&blockID={blockID}")); + + formPanel + ( + setID('zentaolist'), + setClass('mb-4-important'), + set::title(sprintf($this->lang->doc->insertTitle, $this->lang->doc->zentaoList['productRelease'])), + set::actions(array()), + set::showExtra(false), + to::titleSuffix + ( + span + ( + setClass('text-muted text-sm text-gray-600 font-light'), + span + ( + setClass('text-warning mr-1'), + icon('help'), + ), + $lang->doc->previewTip + ) + ), + formRow + ( + formGroup + ( + set::width('1/2'), + set::name('product'), + set::label($lang->doc->product), + set::control(array('required' => false)), + set::items($products), + set::value($product->id), + set::required(), + span + ( + setClass('error-tip text-danger hidden'), + $lang->doc->emptyError + ), + on::change('[name="product"]')->do("loadModal('$productChangeLink'.replace('{productID}', $(this).val()))") + ) + ) + ); +} /* zin: Define the set::module('release') feature bar on main menu. */ featureBar ( set::current($type), - set::linkParams("productID={$product->id}&branch={$branch}&type={key}&orderBy={$orderBy}¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}"), - li(searchToggle(set::module('release'), set::open($type == 'bySearch'))) + set::linkParams("productID={$product->id}&branch={$branch}&type={key}&orderBy={$orderBy}¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}&from={$from}&blockID={$blockID}"), + set::isModal($isFromDoc), + set::modalTarget('#releases_table'), + li(searchToggle + ( + set::simple($isFromDoc), + set::open($type == 'bysearch'), + set::module('release'), + $isFromDoc ? set::target('#docSearchForm') : null + )) ); +if($isFromDoc) div(setID('docSearchForm')); + /* zin: Define the toolbar on main menu. */ $canCreateRelease = hasPriv('release', 'create') && common::canModify('product', $product); $canManageSystem = hasPriv('system', 'browse') && common::canModify('product', $product); @@ -27,6 +90,7 @@ if($canCreateRelease) $createItem = array('icon' => 'plus', 'class' => 'primary' if($canManageSystem) $manageSystemItem = array('class' => 'primary', 'text' => $lang->release->manageSystem, 'url' => $this->createLink('system', 'browse', "productID={$product->id}"), 'data-app' => 'product'); toolbar ( + setClass(array('hidden' => $isFromDoc)), !empty($manageSystemItem) ? item(set($manageSystemItem)) : null, !empty($createItem) ? item(set($createItem)) : null ); @@ -44,19 +108,31 @@ foreach(array_column($releases, 'system') as $system) } if(!empty($cols['system'])) $cols['system']['map'] = array(0 => '') + $appList; +if($isFromDoc) +{ + $cols['id']['type'] = 'checkID'; + + if(isset($cols['actions'])) unset($cols['actions']); + + foreach($cols as $key => $col) + { + $cols[$key]['sortType'] = false; + if(isset($col['link'])) unset($cols[$key]['link']); + } +} + + $releases = initTableData($releases, $cols, $this->release); dtable ( + set::id('releases'), set::cols(array_values($cols)), set::data($releases), - set::customCols(true), set::rowKey('rowID'), set::plugins(array('cellspan')), set::onRenderCell(jsRaw('window.renderCell')), set::getCellSpan(jsRaw('window.getCellSpan')), set::orderBy($orderBy), - set::sortLink(createLink('release', 'browse', "productID={$product->id}&branch={$branch}&type={$type}&orderBy={name}_{sortType}¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}")), - set::footer([jsRaw("function(){return {html: '{$pageSummary}'};}"), 'flex', 'pager']), set::footPager( usePager ( @@ -64,8 +140,14 @@ dtable ) ), set::emptyTip($lang->release->noRelease), - set::createTip($lang->release->create), - set::createLink($canCreateRelease ? createLink('release', 'create', "productID={$product->id}&branch={$branch}") : '') + set::checkable($isFromDoc), + $isFromDoc ? set::footToolbar(array(array('text' => $lang->doc->insertText, 'data-on' => 'click', 'data-call' => 'insertListToDoc'))) : set::footer([jsRaw("function(){return {html: '{$pageSummary}'};}"), 'flex', 'pager']), + !$isFromDoc ? null : set::afterRender(jsCallback()->call('toggleCheckRows', $idList)), + !$isFromDoc ? null : set::height(400), + $isFromDoc ? null : set::customCols(true), + $isFromDoc ? null : set::sortLink(createLink('release', 'browse', "productID={$product->id}&branch={$branch}&type={$type}&orderBy={name}_{sortType}¶m=$param&recTotal={$pager->recTotal}&recPerPage={$pager->recPerPage}&pageID={$pager->pageID}")), + $isFromDoc ? null : set::createTip($lang->release->create), + $isFromDoc ? null : set::createLink($canCreateRelease ? createLink('release', 'create', "productID={$product->id}&branch={$branch}") : '') ); /* ====== Render page ====== */