【Vue】树状节点接口 与 级联选择框组件
原来有一个组织机构的渲染,
我自己写的我自己看也8太明白了:
https://www.cnblogs.com/mindzone/p/14888046.html
现在,有一个位置选择,使用这个级联选择器做的
https://element.eleme.cn/#/zh-CN/component/cascader#cascader-ji-lian-xuan-ze-qi
后台接口部分
首先是组件需要的节点数据结构:
package cn.ymcd.aisw.store.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
/**
* 树状节点PO
* @author cloud9
* @createTime 2022/5/18 09:55
*
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class TreeNode implements Serializable {
private static final long serialVersionUID = 1L;
private String label;
private Integer value;
private List<TreeNode> children;
public TreeNode(String label, Integer value) {
this.label = label;
this.value = value;
}
}
数据库PO
package cn.ymcd.aisw.store.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 行政区域PO
* @author cloud9
* @createTime 2022/5/18 09:57
*
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("PT_AREA")
public class AreaDTO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 区域Id<br/> TYPE:NUMBER(22)
*/
@TableField("AREAID")
private Integer areaid;
/**
* 区域编码<br/> TYPE:NUMBER(22)
*/
@TableField("AREACODE")
private Integer areacode;
/**
* 区域名称<br/> TYPE:VARCHAR2(200)
*/
@TableField("AREANAME")
private String areaname;
/**
* 区域等级<br/> TYPE:VARCHAR2(2)
*/
@TableField("AREALEVEL")
private String arealevel;
/**
* 区域父级<br/> TYPE:NUMBER(22)
*/
@TableField("AREAPARENT")
private Integer areaparent;
/**
* 区域序号<br/> TYPE:NUMBER(22)
*/
@TableField("AREASEQ")
private Integer areaseq;
/**
* 是否可用<br/> TYPE:VARCHAR2(2)
*/
@TableField("ISENABLED")
private String isenabled;
}
接口业务实现类,就是如何组装级联选择器需要的数据结构:
省市县,全部最多的情况是四千多个不到,使用这种递归,还是能处理的
package cn.ymcd.aisw.store.service.impl;
import cn.ymcd.aisw.common.ApiConstants;
import cn.ymcd.aisw.store.dao.AreaDAO;
import cn.ymcd.aisw.store.dto.AreaDTO;
import cn.ymcd.aisw.store.dto.TreeNode;
import cn.ymcd.aisw.store.service.IAreaService;
import cn.ymcd.comm.base.BaseService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* @projectName: aisw-root
* @author: cloud9
* @date: 2022年05月18日 10:02
* @version: 1.0
*/
@Service("iAreaService")
public class AreaServiceImpl extends BaseService<AreaDAO, AreaDTO> implements IAreaService {
@Resource
private AreaDAO areaDAO;
@Override
public List<TreeNode> getAreaCodeList() {
// 筛选所有(可用的 -> isenabled = 1)区域列表
final List<AreaDTO> ALL_AVAILABLE_AREAS = areaDAO.selectList(
new QueryWrapper<AreaDTO>()
.lambda()
.eq(AreaDTO::getIsenabled, ApiConstants.STATUS_NORMAL)
);
// 筛选第一级区域的 TreeNode列表,此时每一个节点都没有子集
List<TreeNode> headerTreeNodes = ALL_AVAILABLE_AREAS
.stream()
.filter(area -> area.getAreaparent().equals(0))
.map(area -> new TreeNode(area.getAreaname(), area.getAreacode()))
.collect(Collectors.toList());
// 然后对头的每个节点进行递归获取内部节点
headerTreeNodes.forEach(header -> buildTreeNodeWithRecursive(header, ALL_AVAILABLE_AREAS));
return headerTreeNodes;
}
/**
* 使用递归进行树状节点集构建
* @param treeNode 需要被装填(若干层级)的节点
* @param ALL_AREA_LIST 树状节点的数据源
* @return void
* @author cloud9
* @createTime 2022/5/18 11:53
*
*/
private void buildTreeNodeWithRecursive(TreeNode treeNode, final List<AreaDTO> ALL_AREA_LIST) {
// 获取入参节点的的子节点列表, 从总集合中过滤
List<TreeNode> recursiveTreeNodeList = ALL_AREA_LIST
.stream()
.filter(area -> area.getAreaparent().equals(treeNode.getValue()))
.map(area -> new TreeNode(area.getAreaname(), area.getAreacode()))
.collect(Collectors.toList());
// 如果这子节点是最后一层了,也就是查不到子节点集合,则终止这个递归
if (CollectionUtils.isEmpty(recursiveTreeNodeList)) return;
// 1、否则继续下去, 将子节点存入这个节点下面
treeNode.setChildren(recursiveTreeNodeList);
// 2、然后将这个子节点列表遍历, 获取它的后代
recursiveTreeNodeList.forEach(childTreeNode -> this.buildTreeNodeWithRecursive(childTreeNode, ALL_AREA_LIST));
}
}
前台渲染部分:
<el-form-item label="门店位置" prop="areaName">
<el-cascader
:ref="selectorRefTag"
v-model="store.areaAddrs"
placeholder="试试搜索:南昌"
:props="{ value: 'label' }"
:options="areaTreeNode"
style="width: 220px"
filterable
@change="handleAreaSelectChange"
/>
</el-form-item>
数据来源,接口就是GET请求,不进行任何认证校验:
async created() {
const { data: res } = await getAreaTreeNodeList()
console.log(res)
this.areaTreeNode = res
},
绑定的Change事件方法:
选中的数据会排在第一个,这里因为业务需要,我要的是路径标签
就是把这个PathLabels数组,转成拼接字符,也可以取PathValues取ID值
handleAreaSelectChange() {
// 获取选中的所有节点的路径,并且用join()方法分割转换为字符串
this.labels = this.$refs[this.selectorRefTag]
.getCheckedNodes()[0]
.pathLabels.join('')
console.log(this.labels)
},
回显的问题:
设置的v-model值就是绑定选中数据,所以回显的时候,把这个绑定值赋值上去即可
/* 区域回显 */
if (this.store.areaName) this.store.areaAddrs = this.store.areaName.split(',')

浙公网安备 33010602011771号