首页 > 其他分享 >若依框架构造树形结构数据

若依框架构造树形结构数据

时间:2024-06-06 11:54:56浏览次数:20  
标签:GroupData group 框架 list List 若依 树形 data groupId

若依框架构造树形结构数据

一、数据库表结构

以分组为例,仅创建分组所需字段,其余业务需要字段后续再添加即可

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for ggroup_data
-- ----------------------------
DROP TABLE IF EXISTS `group_data`;
CREATE TABLE `group_data`  (
  `group_id` bigint NOT NULL AUTO_INCREMENT COMMENT '分组id',
  `parent_id` bigint NULL DEFAULT NULL COMMENT '父组id',
  `ancestors` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '祖级列表',
  `group_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '分组名称',
  `order_num` int NULL DEFAULT NULL COMMENT '显示顺序',
  `type` int NULL DEFAULT NULL COMMENT '节点类型,用于业务处理',
  PRIMARY KEY (`group_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 58 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;

二、前端 - 表格

1、表格结构

<el-table v-if="refreshTable" v-loading="loading" :data="groupList" row-key="groupId" :default-expand-all="isExpandAll" :tree-props="{children:'children',hasChildren:'hasChildren'}">
    <el-table-column label="分组名称" align="left" prop="groupName" />
    <el-table-column label="排序" align="left" prop="orderNum" />
    <el-table-column label="节点类型" align="center" prop="type" >
        <template slot-scope="scope">
            <span v-if="scope.row.type === 0">xxx</span>
            <span v-else-if="scope.row.type === 1">xxx</span>
        </template>
    </el-table-column>
    <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template slot-scope="scope">
			<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['device:group:edit']">	修改</el-button>
<!--  可根据不同的节点类型来实现不同的逻辑   -->
			<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['device:group:remove']">{{scope.row.type === 0 ? '删除' : '解绑/xxx' }}</el-button>
			<el-button size="mini" type="text" icon="el-icon-plus" @click="handleAdd(scope.row)" v-hasPermi="['device:group:add']" v-if="scope.row.type===0">新增</el-button>
        </template>
    </el-table-column>
</el-table>

2、添加对话中上级节点

<!-- 添加或修改场景管理对话框 -->
    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body @close="cancel">
      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
          <!-- 上级节点 -->
        <el-form-item label="上级分组" prop="parentId" v-if="form.parentId !== 0">
          <treeselect v-model="form.parentId" :options="groupOptions" :normalizer="normalizer" placeholder="选择上级场景" />
        </el-form-item>
          
        <el-form-item label="类型" prop="type">
          <el-radio-group v-model="form.type" size="small" @change="handleTypeChange($event)" :disabled="isUpdate">
            <el-radio v-for="(item, index) in groupTypeList" :key="index" :label="item.value"
                      :disabled="item.disabled">{{item.label}}</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">确 定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>

3、需要引入依赖

import Treeselect from '@riophae/vue-treeselect'
import "@riophae/vue-treeselect/dist/vue-treeselect.css";

4、data中数据

data() {
    return {
      // 遮罩层
      loading: true,
      // 分组管理表格数据
      groupList: [],
      // 是否展开,默认全部展开
      isExpandAll: true,
      refreshTable: true,   
      groupOptions:[],
      //例子
      groupTypeList: [
          {"label": "文件夹","value": 0}, 
          {"label": "SMCB",	"value": 1}, 
          {"label": "SMCT",	"value": 2}
       ],
    };
  },

5、相关方法

/** 查询分组管理列表 */
getList() {
    this.loading = true;
    listGroup(this.queryParams).then(response => {
        //TODO:使用handleTree构造为树形数据让表格显示为可折叠类型
        this.groupList = this.handleTree(response.data,"groupId")
        this.loading = false;
    });
},
/** 新增按钮操作 */
handleAdd(row) {
    //传统添加逻辑
    
    //TODO:获取树形结构
    listGroup().then(res => {
        this.groupOptions = this.handleTree(res.data,"groupId");
    })
},
/** 展开/折叠操作 */
toggleExpandAll() {
    this.refreshTable = false;
    this.isExpandAll = !this.isExpandAll;
    this.$nextTick(() => {
        this.refreshTable = true;
    });
},
 /** 修改按钮操作 */
handleUpdate(row) {
    //传统修改逻辑
    
    //TODO:查询除自身节点外的其他数据
    listGroupExcludeChild(row.groupId).then(response => {
        this.groupOptions = this.handleTree(response.data,"groupId");
        if (this.groupOptions.length == 0){
            const noResultOptions = {groupId:this.form.parentId,groupName:this.form.groupName,children:[]};
            this.groupOptions.push(noResultOptions);
        }
    });
},
/** 转换分组数据结构 */
normalizer(node) {
    if (node.children && !node.children.length) {
        delete node.children;
    }
    return {
        id: node.groupId,
        label: node.groupName,
        children: node.children
    };
},

三、前端 - 侧边栏树形结构

1、侧边栏树形结构

<el-row :gutter="20">
    <el-col :span="4" :xs="24">
        <!-- 筛选分组节点 -->
        <div class="head-container">
            <el-input v-model="groupName" placeholder="请输入分组名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px"/>
        </div>
         <!-- 分组树形结构 -->
        <div class="head-container">
            <el-tree :data="groupOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="groupId" default-expand-all highlight-current @node-click="handleNodeClick"/>
        </div>
    </el-col>
    <el-col :span="20" :xs="24">
    </el-col>
</el-row>

2、data中数据

groupOptions: 	[],
groupName: 		"",
nodeInfo: 		{},
defaultProps: {
    children: 	"children",
    label: 		"label",
    groupData: 	"groupData",
},

3、监听器方法

watch: {
    //监听groupName,用于筛选分组数据
    groupName(val) {
      this.$refs.tree.filter(val);
    },
},

4、相关方法

//节点过滤方法
filterNode(value, data) {
    if (!value) return true;
    return data.label.indexOf(value) !== -1;
},
//点击节点触发的方法
handleNodeClick(data) {
    this.nodeInfo = data.groupData;
    //TODO:后续的业务处理,例如建立连接/展示数据...
}
//获取分组树
getGroupTree() {
    groupSelectTree().then(res => {
        this.groupOptions = res.data;
    })
},

四、后端

1、表格数据 - excludeChild

对应前端的listGroupExcludeChild

//controller
@GetMapping("/list/exclude/{groupId}")
public AjaxResult excludeChild(@PathVariable(value = "groupId",required = false)Long groupId)
{
    //查询要分组列表
    List<GroupData> list = groupDataService.selectGroupDataList(new GroupData());
    //使用流的方式处理数据
    list.removeIf(g -> g.getGroupId().intValue() == groupId || ArrayUtils.contains(StringUtils.split(g.getAncestors(),","),groupId+""));
    return success(list);
}

2、树形数据

对应前端的groupSelectTree

//controller
@GetMapping("/groupSelectTree")
public AjaxResult selectGroupTreeList(GdtGroupData group){
    logger.info("分组构建树为:{}",success(groupDataService.selectGroupTreeList(group)));
    return success(groupDataService.selectGroupTreeList(group));
}

//---------------------------------------------------------------------------------------------------------------------------------------

//service
List<GroupTreeSelect> selectGroupTreeList(GroupData group);

//---------------------------------------------------------------------------------------------------------------------------------------

//impl
//1、查询树形结构数据
@Override
public List<GroupTreeSelect> selectGroupTreeList(GroupData group) {
    List<GroupData> groupData = selectGroupDataList(group);
    return buildGroupTreeSelect(groupData);
}

//2、构建前端下拉框结构
private List<GroupTreeSelect> buildGroupTreeSelect(List<GroupData> list) {
    List<GroupData> groupDataList = buildGroupTree(list);
    return groupDataList.stream().map(GroupTreeSelect::new).collect(Collectors.toList());
}

 //3、构建前端所需树结构
public List<GroupData> buildGroupTree(List<GroupData> groups){
    List<GroupData> resultList = new ArrayList<>();
    List<Long> tempList = groups.stream().map(GroupData::getGroupId).collect(Collectors.toList());
    for (GroupData group : groups) {
        if (!tempList.contains(group.getParentId())){
            recursionFn(groups,group);
            resultList.add(group);
        }
    }
    if (resultList.isEmpty()){
        resultList = groups;
    }
    return resultList;
}

//4、递归列表
private void recursionFn(List<GroupData> list, GroupData g) {
    List<GroupData> childList = getChildList(list,g);
    g.setChildren(childList);
    for (GroupData gChild : childList) {
        if (hasChild(list,gChild)){
            recursionFn(list,gChild);
        }
    }
}

//5、得到子节点
private List<GroupData> getChildList(List<GroupData> list, GroupData g) {
    List<GroupData> tList = new ArrayList<>();
    Iterator<GroupData> iterator = list.iterator();
    while (iterator.hasNext()){
        GroupData n = iterator.next();
        if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == g.getGroupId().longValue()){
            tList.add(n);
        }
    }
    return tList;
}

//6、判断是否有子节点
private boolean hasChild(List<GroupData> list, GroupData gChild) {
    return getChildList(list,gChild).size() > 0;
}

//---------------------------------------------------------------------------------------------------------------------------------------

//domain
/**
 * GroupTreeselect树结构实体类
 *
 * @author Mr.Liu
 */
@Data
public class GroupTreeSelect implements Serializable
{
    private static final long serialVersionUID = 1L;

    /** 节点ID */
    private Long id;

    /** 节点名称 */
    private String label;

    /** 子节点 */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private List<GroupTreeSelect> children;

    private GroupData groupData;

    public GroupTreeSelect() { }

    public GroupTreeSelect(GroupData group)
    {
        this.id = group.getGroupId();
        this.label = group.getGroupName();
        this.groupData = group;
        this.children = group.getChildren().stream().map(GroupTreeSelect::new).collect(Collectors.toList());
    }
}

标签:GroupData,group,框架,list,List,若依,树形,data,groupId
From: https://www.cnblogs.com/jundong2177/p/18234868

相关文章

  • 从提示工程到代理工程:构建高效AI代理的策略框架概述
    自ChatGPT推出以来,仅仅一年多的时间里,公众对于“人工智能”(AI)的认识已经发生了根本性的变化。这种变化部分源于公众意识的提高,更多则是基于这样一个认识:AI驱动的系统不仅可能,而且可能已经具备了与人类相当的能力和表现。ChatGPT不仅是AI能力的一个验证,更是半个多世纪以来AI研究成......
  • vue框架页面外链进来加"/"拼接参数的使用及获取;PC及手机端的判断;
     一开始没有看懂,后来知道了 他的意思 就是在pages目录下的页面,如果需要通过比如'pages/qr/56'这种斜杠链接进入的话 就需要吧detail.vue页面变成目录结构,页面名称改为'_'+参数名;如下图 然后在_code页面可以通过如下方式获取code值进行操作:mounted(){constc......
  • Yii2 框架中,通过 yii\db\Command 对象来执行原生 SQL 语句
    在Yii2中,你可以通过yii\db\Command对象来执行原生SQL语句。这包括查询操作(如SELECT)和数据操作(如INSERT、UPDATE、DELETE)。以下是一些常见的例子,展示如何在Yii2中执行SQL语句。执行查询语句执行SELECT查询并获取结果你可以使用queryAll()、queryOne()、queryColu......
  • 【Spring Cloud应用框架的讲解】
    ......
  • 进程切换分析(1):基本框架
    一、前言本文主要是以context_switch为起点,分析了整个进程切换过程中的基本操作和基本的代码框架,很多细节,例如tlb的操作,cache的操作,锁的操作等等会在其他专门的文档中描述。进程切换包括体系结构相关的代码和系统结构无关的代码。第二、三、四分别描述了context_switch的代码脉络......
  • Springboot框架开发与实用篇之热部署 2024详解
    开发与实用手动启动热部署热部署(HotDeployment)指的是在应用程序正在运行的情况下,对其进行更新或修改并将这些变更应用到正在运行的应用程序中的过程。通常情况下,传统的部署方式需要停止应用程序、部署更新,然后重新启动应用程序才能使更新生效。而热部署则允许在无需停止应用......
  • 囚徒5.4_基于texlive的PlotNeuralNet画深度学习框架图
    首先下载并安装texlive连接如下texlive安装教程接着下载PlotNeuralNet项目下载链接PlotNeuralNet对PlotNeuralNet的一些解释它其实是基于texlive语言,然后通过python语言按照texlive的语法格式进行拼接生成tex文档之后使用pdflatex命令生成pdf.PlotNeuralNet中有一系列的写......
  • Vue的viewUI框架安装与使用
    1.安装pycharm进入到项目目录C:\Users\Administrator\PycharmProjects\myvue02>npminstallview-design--save 2.引用在项目的src/main.js中加入如下代码【src/main.js】importVuefrom'vue'importAppfrom'./App.vue'importViewUIfrom'view-design&......
  • 若依框架整合WebSocket
    若依框架整合WebSocket一、前端1、定义socket对象data(){return{webSocket:null,}}2、建立连接//如果webSocket为null进行建立连接if(!this.webSocket){this.webSocket=newWebSocket(`ws://localhost:8081/handleData/`); //建立连接......
  • 2024流行的前端框架
     随着技术的进步,一些前端框架的设计是为了让开发人员获得最高的效率。所有框架都有其独特的功能,使得开发人员很难选择一个。由于每个企业都有不同的需求和目标,因此其网站和应用程序的开发也应根据其需求和梦想进行管理。市场上最好的前端框架一直存在争议。然而,最近的......