6

无限极分类树

 2 years ago
source link: https://zsmhub.github.io/post/%E5%AE%9E%E6%88%98%E6%A1%88%E4%BE%8B/%E6%97%A0%E9%99%90%E6%9E%81%E5%88%86%E7%B1%BB%E6%A0%91/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一般的分类树状结构有两种方式:

  • 一种是adjacency list,也就是是id,parent_id这种形式。
  • 另一种是nested set,即左右值的形式。

左右值形式查询起来比较高效,无需递归等,推荐使用,但是没有pid形式简单直观。

无限极分类树的使用场景:菜单、组织架构等

效率对比:递归效率低,引用方式效率高。

GO递归实现无限极系统菜单

实现无限级菜单

// 递归获取父节点下的菜单,roleMenuIds:当前用户角色被授权的菜单权限id,不传则返回全部菜单
var menu []model_account.Menu // 定义全局变量
func GetMenu(parentId uint64, roleMenuIds []uint64) []*form.MenuTree {
    if menu == nil {
        model_account.Menu{}.Model().Order("`order` asc").Find(&menu) // 一次性取出全部菜单,只需执行一次sql
    }

    var menuTreeList = make([]*form.MenuTree, 0)
    for _, v := range menu {
        if v.ParentId != parentId { // 关键一步:符合条件的才往下走
            continue;
        }
        child := GetMenu(v.Id, roleMenuIds)
        node := &form.MenuTree{
            Id:    v.Id,
            Title: v.Title,
            Slug:  v.Slug,
            Icon:  v.Icon,
            Uri:   v.Uri,
        }
        node.Children = child

        // 处理用户角色可查看的菜单
        if len(roleMenuIds) > 0 {
            var flag bool
            for _, vv := range roleMenuIds {
                if vv == v.Id {
                    flag = true
                }
            }

            // 当前菜单无权限且子菜单为空
            if !flag && len(node.Children) <= 0 {
                continue
            }

            // 处理父级菜单存在而子级菜单不存在的情况
            if flag && node.Uri == "" && len(node.Children) <= 0 {
                continue
            }
        }

        menuTreeList = append(menuTreeList, node)
    }

    return menuTreeList
}

php递归实现无限极分类树

<?php

// 采用引用方式:生成无限极分类树『tip:仅可用于数据量少的场景』

$arr = array(
    array("id" => 1 , "pid" => 0 , 'cat' => '栏目一'),
    array("id" => 2 , "pid" => 0 , 'cat' => '栏目二'),
    array("id" => 3 , "pid" => 1 , 'cat' => '栏目三'),
    array("id" => 4 , "pid" => 2 , 'cat' => '栏目四'),
    array("id" => 5 , "pid" => 1 , 'cat' => '栏目五'),
    array("id" => 6 , "pid" => 5 , 'cat' => '栏目六'),
    array("id" => 7 , "pid" => 5 , 'cat' => '栏目七'),
    array("id" => 8 , "pid" => 6 , 'cat' => '栏目八'),
    array("id" => 9 , "pid" => 1 , 'cat' => '栏目九'),
    array("id" => 10 , "pid" => 0 , 'cat' => '栏目十'),
    array("id" => 11 , "pid" => 10 , 'cat' => '栏目十一'),
    array("id" => 12 , "pid" => 11 , 'cat' => '栏目十二'),
    array("id" => 13 , "pid" => 2 , 'cat' => '栏目十三'),
    array("id" => 14, "pid" => 13 , 'cat' => '栏目十四')
);

function make_tree($arr, $pidInit=0)
{
    $refer = array();
    $tree = array();
    foreach ($arr as $k => $v) {
        $refer[$v['id']] = &$arr[$k];  // 创建主键的数组引用
    }

    foreach ($arr as $k => $v) {
        $pid = $v['pid'];   // 获取当前分类的父级id
        if ($pid == $pidInit) {
            $tree[] = &$arr[$k];   // 获取规定的栏目及子栏目{$pidInit}
        } elseif (isset($refer[$pid])) {
            $refer[$pid]['subcat'][] = &$arr[$k];  // 如果存在父级栏目,则添加进父级栏目的子栏目数组中
        }
    }

    return $tree;
}

$cat = make_tree($arr, 0);
print_r($cat);

另类的无限极分类树设计

# 部门无限极分类案例的建表sql
CREATE TABLE `t_department` (
  `id` smallint(6) unsigned NOT NULL AUTO_INCREMENT COMMENT '部门ID',
  `name` varchar(45) NOT NULL DEFAULT '""' COMMENT '部门名称',
  `created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name_UNIQUE` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门信息表';

CREATE TABLE `t_department_tree` (
    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
    `children_id` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '子节点ID',
    `parent_id` SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '父节点ID',
    `depth`SMALLINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '深度',
    PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='部门关系树,children_id=parent_id则为初始节点';

INSERT INTO `t_department` (`id`, `name`, `created_time`, `updated_time`)
VALUES
(1, '拓展与加盟中心', '2018-12-19 18:16:10', '2018-12-19 18:17:01'),
(2, '产品中心', '2018-12-19 18:16:10', '2018-12-19 18:17:02'),
(3, '运营中心', '2018-12-19 18:16:10', '2018-12-19 18:17:03'),
(4, '增值与服务中心', '2018-12-19 18:16:10', '2018-12-19 18:17:04'),
(5, '后端支持', '2018-12-19 18:16:10', '2018-12-19 18:17:04'),
(6, '运营管理部', '2019-06-14 12:38:58.000', '2019-06-14 12:38:58.000'),
(7, '客服管理部', '2019-06-14 12:39:11.000', '2019-06-14 12:39:11.000');

INSERT INTO `t_department_tree` (`children_id`,`parent_id`,`depth`)
VALUES
(1,1,0),
(2,2,0),
(3,3,0),
(4,4,0),
(5,5,0),
(6,6,0),
(6,3,1),
(7,3,1),
(7,7,0);

左右值无限极分类

参考文章

  • 优点:查询效率高,排序也很方便
  • 缺点:编辑是个麻烦

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK