diff --git a/module/common/model.php b/module/common/model.php index 504f4c49a8..5e8f8b5cd1 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -538,6 +538,147 @@ class commonModel extends model } } + /** + * Print top bar for ZIN demo. + * + * @static + * @access public + * @return array + */ + public static function printUserBarZin() + { + global $lang, $app; + + $menus = array(); + + if(isset($app->user)) + { + $isGuest = $app->user->account == 'guest'; + + if(!$isGuest) + { + $menus[] = array + ( + 'url' => helper::createLink('my', 'profile', '', '', true), + 'avatar' => $app->user->avatar, + 'text' => empty($app->user->realname) ? $app->user->account : $app->user->realname, + 'role' => isset($lang->user->roleList[$app->user->role]) ? $lang->user->roleList[$app->user->role] : '', + ); + $menus[] = array('text' => 'divider'); + + $vision = $app->config->vision == 'lite' ? 'rnd' : 'lite'; + + $menus[] = array + ( + 'url' => helper::createLink('my', 'profile', '', '', true), + 'icon' => 'account', + 'text' => $lang->profile, + ); + + if($app->config->vision === 'rnd') + { + if(!commonModel::isTutorialMode()) + { + $menus[] = array + ( + 'url' => helper::createLink('tutorial', 'start'), + 'icon' => 'guide', + 'text' => $lang->tutorialAB, + ); + } + + $menus[] = array + ( + 'url' => helper::createLink('my', 'preference', 'showTip=false', '', true), + 'icon' => 'controls', + 'text' => $lang->preference, + ); + } + + if(common::hasPriv('my', 'changePassword')) + { + $menus[] = array + ( + 'url' => helper::createLink('my', 'changepassword', '', '', true), + 'icon' => 'cog-outline', + 'text' => $lang->changePassword, + ); + } + + $menus[] = array('text' => 'divider'); + } + + $items = array(); + foreach($app->lang->themes as $key => $value) + { + $item = array + ( + 'url' => "javascript:selectTheme(\"$key\")", + 'text' => $value, + 'attr' => array('data-value' => $key), + ); + if($app->cookie->theme == $key) $item['attr']['class'] = 'selected'; + $items[] = $item; + } + $menus[] = array + ( + 'url' => 'javascript:;', + 'icon' => 'theme', + 'text' => $lang->theme, + 'items'=> $items, + ); + + $items = array(); + foreach($app->config->langs as $key => $value) + { + $item = array + ( + 'url' => "javascript:selectLang(\"$key\")", + 'text' => $value, + 'attr' => array('data-value' => $key), + ); + if($app->cookie->lang == $key) $item['attr']['class'] = 'selected'; + $items[] = $item; + } + $menus[] = array + ( + 'url' => 'javascript:;', + 'icon' => 'lang', + 'text' => $lang->lang, + 'items'=> $items, + ); + + //if(!$isGuest and !commonModel::isTutorialMode() and $app->viewType != 'mhtml') + //{ + // $customLink = helper::createLink('custom', 'ajaxMenu', "module={$app->getModuleName()}&method={$app->getMethodName()}", '', true); + // echo "
  • $lang->customMenu
  • "; + //} + + //commonModel::printAboutBar(); + $menus[] = array('text' => 'divider'); + if($isGuest) + { + $menus[] = array + ( + 'url' => helper::createLink('user', 'login'), + 'text' => $lang->login, + ); + } + else + { + $menus[] = array + ( + 'url' => helper::createLink('user', 'logout'), + 'icon' => 'exit', + 'text' => $lang->logout, + ); + } + + } + + return $menus; + } + /** * Print vision switcher. * @@ -576,6 +717,165 @@ class commonModel extends model } } + /** + * Print create button list for Zin Demo. + * + * @static + * @access public + * @return void + */ + public static function printCreateListZin() + { + global $app, $config, $lang; + + $menus = array(); + + /* Initialize the default values. */ + $showCreateList = $needPrintDivider = false; + + /* Get default product id. */ + $productID = isset($_SESSION['product']) ? $_SESSION['product'] : 0; + if($productID) + { + $product = $app->dbh->query("SELECT id FROM " . TABLE_PRODUCT . " WHERE `deleted` = '0' and vision = '{$config->vision}' and id = '{$productID}'")->fetch(); + if(empty($product)) $productID = 0; + } + if(!$productID and $app->user->view->products) + { + $product = $app->dbh->query("SELECT id FROM " . TABLE_PRODUCT . " WHERE `deleted` = '0' and vision = '{$config->vision}' and id " . helper::dbIN($app->user->view->products) . " order by `order` desc limit 1")->fetch(); + if($product) $productID = $product->id; + } + + if($config->vision == 'lite') + { + $condition = " WHERE `deleted` = '0' AND `vision` = 'lite' AND `model` = 'kanban'"; + if(!$app->user->admin) $condition .= " AND `id` " . helper::dbIN($app->user->view->projects); + + $object = $app->dbh->query("select id from " . TABLE_PROJECT . $condition . ' LIMIT 1')->fetch(); + if(empty($object)) unset($lang->createIcons['story'], $lang->createIcons['task'], $lang->createIcons['execution']); + } + + if($config->edition == 'open') unset($lang->createIcons['effort']); + if($config->systemMode == 'light') unset($lang->createIcons['program']); + + /* Check whether the creation permission is available, and print create buttons. */ + + foreach($lang->createIcons as $objectType => $objectIcon) + { + $createMethod = 'create'; + $module = $objectType == 'kanbanspace' ? 'kanban' : $objectType; + if($objectType == 'effort') $createMethod = 'batchCreate'; + if($objectType == 'kanbanspace') $createMethod = 'createSpace'; + if(strpos('|bug|execution|kanbanspace|', "|$objectType|") !== false) $needPrintDivider = true; + + if(common::hasPriv($module, $createMethod)) + { + if($objectType == 'doc' and !common::hasPriv('doc', 'tableContents')) continue; + + /* Determines whether to print a divider. */ + if($needPrintDivider and $showCreateList) + { + $menus[] = array('text' => 'divider'); + $needPrintDivider = false; + } + + $showCreateList = true; + $isOnlyBody = false; + $attr = array(); + + $params = ''; + switch($objectType) + { + case 'doc': + $params = "objectType=&objectID=0&libID=0"; + $createMethod = 'selectLibType'; + $isOnlyBody = true; + $attr = array('class'=>'iframe', 'data-width'=>'700px'); + break; + case 'project': + if($config->vision == 'lite') + { + $params = "model=kanban"; + } + else if(!defined('TUTORIAL')) + { + $params = "programID=0&from=global"; + $createMethod = 'createGuide'; + $attr = array('data-toggle'=>'modal'); + } + else + { + $params = "model=scrum&programID=0©ProjectID=0&extra=from=global"; + } + + break; + case 'bug': + $params = "productID=$productID&branch=&extras=from=global"; + break; + case 'story': + if(!$productID and $config->vision == 'lite') + { + $module = 'project'; + $params = "model=kanban"; + } + else + { + $params = "productID=$productID&branch=0&moduleID=0&storyID=0&objectID=0&bugID=0&planID=0&todoID=0&extra=from=global"; + if($config->vision == 'lite') + { + $projectID = isset($_SESSION['project']) ? $_SESSION['project'] : 0; + $projects = $app->dbh->query("SELECT t2.id FROM " . TABLE_PROJECTPRODUCT . " AS t1 LEFT JOIN " . TABLE_PROJECT . " AS t2 ON t1.project = t2.id WHERE t1.`product` = '{$productID}' and t2.`type` = 'project' and t2.id " . helper::dbIN($app->user->view->projects) . " ORDER BY `order` desc")->fetchAll(); + + $projectIdList = array(); + foreach($projects as $project) $projectIdList[$project->id] = $project->id; + if($projectID and !isset($projectIdList[$projectID])) $projectID = 0; + if(empty($projectID)) $projectID = key($projectIdList); + + $params = "productID={$productID}&branch=0&moduleID=0&storyID=0&objectID={$projectID}&bugID=0&planID=0&todoID=0&extra=from=global"; + } + } + + break; + case 'task': + $params = "executionID=0&storyID=0&moduleID=0&taskID=0&todoID=0&extra=from=global"; + break; + case 'testcase': + $params = "productID=$productID&branch=&moduleID=0&from=¶m=0&storyID=0&extras=from=global"; + break; + case 'execution': + $projectID = isset($_SESSION['project']) ? $_SESSION['project'] : 0; + $params = "projectID={$projectID}&executionID=0©ExecutionID=0&planID=0&confirm=no&productID=0&extra=from=global"; + break; + case 'product': + $params = "programID=&extra=from=global"; + break; + case 'program': + $params = "parentProgramID=0&extra=from=global"; + break; + case 'kanbanspace': + $isOnlyBody = true; + $attr = array('class'=>'iframe', 'data-width'=>'75%'); + break; + case 'kanban': + $isOnlyBody = true; + $attr = array('class'=>'iframe', 'data-width'=>'75%'); + break; + } + + $menus[] = array( + 'url' => helper::createLink($module, $createMethod, $params, '', $isOnlyBody), + 'icon' => $objectIcon, + 'text' => $lang->createObjects[$objectType], + 'attr' => $attr + ); + } + } + + if(!$showCreateList) return ''; + + return $menus; + } + /** * Print create button list. * diff --git a/module/program/ui/browse.html.php b/module/program/ui/browse.html.php index e38b3e9d6e..df118ea7e3 100644 --- a/module/program/ui/browse.html.php +++ b/module/program/ui/browse.html.php @@ -14,6 +14,13 @@ foreach(\customModel::getMainMenu() as $menuItem) ); } +/* Generate dropdown menu. */ +$shotcutAddMenu = dropdown(setId('shortcutAdd')); +foreach(\commonModel::printCreateListZin() as $item) $shotcutAddMenu->append(item($item)); + +$userMenu = dropdown(setId('userMenu')); +foreach(\commonModel::printUserBarZin() as $item) $userMenu->append(item($item)); + page ( set('title', $title), @@ -27,12 +34,9 @@ page ), pagenavbar ( - zuinav - ( - set('js-render', false), - set('items', $navItems), - item(array('text' => 'text')), - ), + set('js-render', false), + set('items', $navItems), + item(array('text' => 'text')), ), toolbar ( @@ -41,12 +45,28 @@ page item(array('icon' => 'icon-plus')), item(array('icon' => 'icon-group')), item(array('text' => '研发综合界面')), + btn + ( + icon('plus'), + setClass('rounded-sm btn square size-sm secondary'), + set('data-toggle', 'dropdown'), + set('data-trigger', 'hover'), + set('data-arrow', 'true'), + set('href', '#shortcutAdd'), + ), + avatar + ( + set('role', '研发'), + set('avatar', '/data/upload/1/202302/07134647027036pb'), + set('href', '#userMenu'), + ), ), ), - pagemain( ), + $shotcutAddMenu, + $userMenu, ); /* diff --git a/zin/wg.func.php b/zin/wg.func.php index cc8ed0b1d7..987c9ef45c 100755 --- a/zin/wg.func.php +++ b/zin/wg.func.php @@ -30,11 +30,11 @@ function data() return core\data::$global; } -function btn() {return createWg('btn', func_get_args());} -function icon() {return createWg('icon', func_get_args());} -function pagebase() {return createWg('pagebase', func_get_args());} -function page() {return createWg('page', func_get_args());} -function dtable() {return createWg('dtable', func_get_args());} +function btn() {return createWg('btn', func_get_args());} +function icon() {return createWg('icon', func_get_args());} +function pagebase() {return createWg('pagebase', func_get_args());} +function page() {return createWg('page', func_get_args());} +function dtable() {return createWg('dtable', func_get_args());} function pageheader() {return createWg('pageheader', func_get_args());} function pageheading() {return createWg('pageheading', func_get_args());} function pagenavbar() {return createWg('pagenavbar', func_get_args());} @@ -42,3 +42,4 @@ function zuinav() {return createWg('zuinav', func_get_args());} function toolbar() {return createWg('toolbar', func_get_args());} function pagemain() {return createWg('pagemain', func_get_args());} function dropdown() {return createWg('dropdown', func_get_args());} +function avatar() {return createWg('avatar', func_get_args());} diff --git a/zin/wg/avatar/v1.php b/zin/wg/avatar/v1.php new file mode 100644 index 0000000000..f688b88a94 --- /dev/null +++ b/zin/wg/avatar/v1.php @@ -0,0 +1,85 @@ + 'userMenu dropdown-toggle', + 'data-arrow' => true, + 'data-toggle' => 'dropdown', + 'data-trigger' => 'hover', + 'data-placement' => 'bottom', + 'href' => '#userMenu', + 'theme' => 'success', + 'radius' => 'circle', + 'size' => '', + 'outline' => '', + 'showName' => false, + ); + + static $customProps = 'text,theme,radius,size,outline,name,role'; + + protected function acceptChild($child, $strAsHtml = false) + { + $child = parent::acceptChild($child, $strAsHtml); + + if(!$strAsHtml && is_string($child) && !$this->props->has('name')) + { + $this->prop('name', $child); + return NULL; + } + return $child; + } + + protected function build($isPrint = false, $parent = NULL) + { + $builder = parent::build($isPrint, $parent); + + /* Strig avatar. */ + if($this->hasProp('name')) + { + $div = h5::div($this->prop('name'))->addClass('avatar'); + if(!empty($this->prop('radius'))) $div->addClass($this->prop('radius')); + if(!empty($this->prop('theme'))) $div->addClass($this->prop('theme')); + if(!empty($this->prop('outline'))) $div->addClass($this->prop('outline') . '-outline'); + if(!empty($this->prop('size'))) $div->addClass($this->prop('size')); + $builder->append($div); + + if(!empty($this->prop('showName'))) + { + $builder->append(h5::span($this->prop('name'))); + if(!empty($this->prop('role'))) $builder->append(h5::span($this->prop('role'))); + } + + return $builder; + } + + if(!$this->hasProp('avatar')) return $builder; + + /* Image avatar. */ + $div = h5::div(h5::img(\zin\set('src', $this->prop('avatar'))))->addClass('avatar'); + if(!empty($this->prop('radius'))) $div->addClass($this->prop('radius')); + if(!empty($this->prop('theme'))) $div->addClass($this->prop('theme')); + if(!empty($this->prop('outline'))) $div->addClass($this->prop('outline') . '-outline'); + if(!empty($this->prop('size'))) $div->addClass($this->prop('size')); + $builder->append($div); + + /* Show name and role. */ + if(!empty($this->prop('showName'))) + { + $builder->append(h5::span($this->prop('name'))); + if(!empty($this->prop('role'))) $builder->append(h5::span($this->prop('role'))); + } + + return $builder; + } +} + diff --git a/zin/wg/dropdown/v1.php b/zin/wg/dropdown/v1.php index 74aa01135e..f9f76647c5 100644 --- a/zin/wg/dropdown/v1.php +++ b/zin/wg/dropdown/v1.php @@ -26,12 +26,28 @@ class dropdown extends \zin\core\wg return $li; } + $li = h5::li()->addClass('menu-item'); + + /* Divider. */ + if(isset($item['text']) and ($item['text'] === '|' or $item['text'] === 'divider')) + { + $li->addClass('menu-divider'); + return $li; + } + $a = h5::a(); - if(isset($item['url'])) $a->prop('href', $item['url']); + + /* Avatar item. */ + if(isset($item['avatar'])) + { + $div = h5::div()->addClass('avatar')->addClass('avatar circle primary'); + $div->append(h5::img(\zin\set('src', $item['avatar']))); + $a->append($div); + } + if(isset($item['url'])) $a->prop('href', $item['url']); if(isset($item['icon'])) $a->append(h5::i()->addClass("icon icon-{$item['icon']}")); if(isset($item['text'])) $a->append($item['text']); - $li = h5::li()->addClass('menu-item'); $li->append($a); return $li;