• ElementUI中Tree组件使用


           首先官网上的树形控件教程地址为Element - The world's most popular Vue UI framework

    案例一:

    要实现这种类型的树控件,并且后边相关操作:

    1.1后端准备工作

     首先,数据库表为:

     查询接口返回的实体类为:

    1. @Data
    2. @NoArgsConstructor
    3. @RequiredArgsConstructor // 有参构造
    4. @EqualsAndHashCode(callSuper = false ,of = "name")// 表示以name去重写的Equals和HashCode
    5. @Accessors(chain = true)
    6. @TableName("t_department")
    7. @ApiModel(value="Department对象", description="")
    8. public class Department implements Serializable {
    9. private static final long serialVersionUID = 1L;
    10. @ApiModelProperty(value = "id")
    11. @TableId(value = "id", type = IdType.AUTO)
    12. private Integer id;
    13. @ApiModelProperty(value = "部门名称")
    14. @Excel(name = "部门")
    15. @NonNull
    16. private String name;
    17. @ApiModelProperty(value = "父id")
    18. private Integer parentId;
    19. @ApiModelProperty(value = "路径")
    20. private String depPath;
    21. @ApiModelProperty(value = "是否启用")
    22. private Boolean enabled;
    23. @ApiModelProperty(value = "是否上级")
    24. private Boolean isParent;
    25. @ApiModelProperty(value = "子部门列表")
    26. @TableField(exist = false)
    27. private List children;
    28. @ApiModelProperty(value = "返回结果,存储过程使用")
    29. @TableField(exist = false)
    30. private Integer result;
    31. }

    查询接口返回的数据格式:通过属性 children来判断是否有子节点

    1. [
    2. {
    3. "id": 1,
    4. "name": "股东会",
    5. "parentId": -1,
    6. "depPath": ".1",
    7. "enabled": true,
    8. "isParent": true,
    9. "children": [
    10. {
    11. "id": 2,
    12. "name": "董事会",
    13. "parentId": 1,
    14. "depPath": ".1.2",
    15. "enabled": true,
    16. "isParent": true,
    17. "children": [
    18. {
    19. "id": 3,
    20. "name": "总办",
    21. "parentId": 2,
    22. "depPath": ".1.2.3",
    23. "enabled": true,
    24. "isParent": true,
    25. "children": [
    26. {
    27. "id": 4,
    28. "name": "财务部",
    29. "parentId": 3,
    30. "depPath": ".1.2.3.4",
    31. "enabled": true,
    32. "isParent": false,
    33. "children": [],
    34. "result": null
    35. },
    36. {
    37. "id": 5,
    38. "name": "市场部",
    39. "parentId": 3,
    40. "depPath": ".1.2.3.5",
    41. "enabled": true,
    42. "isParent": true,
    43. "children": [
    44. {
    45. "id": 6,
    46. "name": "华东市场部",
    47. "parentId": 5,
    48. "depPath": "1.2.3.5.6",
    49. "enabled": true,
    50. "isParent": true,
    51. "children": [
    52. {
    53. "id": 8,
    54. "name": "上海市场部",
    55. "parentId": 6,
    56. "depPath": "1.2.3.5.6.8",
    57. "enabled": true,
    58. "isParent": false,
    59. "children": [],
    60. "result": null
    61. }
    62. ],
    63. "result": null
    64. },
    65. {
    66. "id": 7,
    67. "name": "华南市场部",
    68. "parentId": 5,
    69. "depPath": "1.2.3.5.7",
    70. "enabled": true,
    71. "isParent": false,
    72. "children": [],
    73. "result": null
    74. },
    75. {
    76. "id": 9,
    77. "name": "西北市场部",
    78. "parentId": 5,
    79. "depPath": ".1.2.3.5.9",
    80. "enabled": true,
    81. "isParent": true,
    82. "children": [
    83. {
    84. "id": 10,
    85. "name": "贵阳市场",
    86. "parentId": 9,
    87. "depPath": ".1.2.3.5.9.10",
    88. "enabled": true,
    89. "isParent": true,
    90. "children": [
    91. {
    92. "id": 11,
    93. "name": "乌当区市场",
    94. "parentId": 10,
    95. "depPath": ".1.2.3.5.9.10.11",
    96. "enabled": true,
    97. "isParent": false,
    98. "children": [],
    99. "result": null
    100. }
    101. ],
    102. "result": null
    103. }
    104. ],
    105. "result": null
    106. }
    107. ],
    108. "result": null
    109. },
    110. {
    111. "id": 12,
    112. "name": "技术部",
    113. "parentId": 3,
    114. "depPath": ".1.2.3.12",
    115. "enabled": true,
    116. "isParent": false,
    117. "children": [],
    118. "result": null
    119. },
    120. {
    121. "id": 13,
    122. "name": "运维部",
    123. "parentId": 3,
    124. "depPath": ".1.2.3.13",
    125. "enabled": true,
    126. "isParent": false,
    127. "children": [],
    128. "result": null
    129. }
    130. ],
    131. "result": null
    132. }
    133. ],
    134. "result": null
    135. },
    136. {
    137. "id": 150,
    138. "name": "aaa",
    139. "parentId": 1,
    140. "depPath": ".1.150",
    141. "enabled": true,
    142. "isParent": true,
    143. "children": [
    144. {
    145. "id": 151,
    146. "name": "abbb",
    147. "parentId": 150,
    148. "depPath": ".1.150.151",
    149. "enabled": true,
    150. "isParent": false,
    151. "children": [],
    152. "result": null
    153. }
    154. ],
    155. "result": null
    156. },
    157. {
    158. "id": 154,
    159. "name": "ccc",
    160. "parentId": 1,
    161. "depPath": ".1.154",
    162. "enabled": true,
    163. "isParent": false,
    164. "children": [],
    165. "result": null
    166. },
    167. {
    168. "id": 157,
    169. "name": "dddd",
    170. "parentId": 1,
    171. "depPath": ".1.157",
    172. "enabled": true,
    173. "isParent": false,
    174. "children": [],
    175. "result": null
    176. }
    177. ],
    178. "result": null
    179. }
    180. ]

    1.2前端代码

    从官网上复制一个模板过来,搜索的话,直接往下找一个有搜索框的,把搜索框复制过来,复制好就可以开始修改,写增删改查的方法调用了。

     写好的代码如下:

    1. <template>
    2. <div style="width: 550px;">
    3. <el-input
    4. placeholder="请输入部门名称进行搜索..."
    5. prefix-icon="el-icon-search"
    6. v-model="filterText">
    7. el-input>
    8. <el-tree
    9. :data="deps"
    10. :props="defaultProps"
    11. :filter-node-method="filterNode"
    12. :expand-on-click-node="false"
    13. ref="tree">
    14. <span class="custom-tree-node" slot-scope="{ node, data }" style="display:flex; justify-content: space-between;width: 100%;">
    15. <span>{{ data.name }}span>
    16. <span>
    17. <el-button
    18. type="primary"
    19. size="mini"
    20. class="depBtn"
    21. @click="() => showAddDep(data)">
    22. 添加部门
    23. el-button>
    24. <el-button
    25. type="danger"
    26. size="mini"
    27. class="depBtn"
    28. @click="() => deleteDep(data)">
    29. 删除部门
    30. el-button>
    31. span>
    32. span>
    33. el-tree>
    34. <el-dialog
    35. title="添加部门"
    36. :visible.sync="dialogVisible"
    37. width="30%">
    38. <div>
    39. <table>
    40. <tr>
    41. <td><el-tag>上级部门el-tag>td>
    42. <td><el-tag>{{pname}}el-tag>td>
    43. tr>
    44. <tr>
    45. <td><el-tag>部门名称el-tag>td>
    46. <td><el-input v-model="dep.name" placeholder="请输入部门名称...">el-input>td>
    47. tr>
    48. table>
    49. div>
    50. <span slot="footer" class="dialog-footer">
    51. <el-button @click="dialogVisible = false">取 消el-button>
    52. <el-button type="primary" @click="doAddDep">确 定el-button>
    53. span>
    54. el-dialog>
    55. div>
    56. template>
    57. <script>
    58. export default {
    59. data(){
    60. return{
    61. // 树的搜索条件
    62. filterText: '',
    63. // 树的数据
    64. deps: [],
    65. // 树的配置
    66. defaultProps: {
    67. children: 'children',
    68. label: 'name'
    69. },
    70. // 添加弹出框
    71. dialogVisible: false,
    72. // 添加的部门数据
    73. dep:{
    74. name:'',
    75. parentId: -1
    76. },
    77. // 上级部门名称
    78. pname: ''
    79. }
    80. },
    81. mounted(){
    82. this.initDeps();
    83. },
    84. methods: {
    85. // 初始化数据
    86. initDeps(){
    87. this.getRequest('/system/basic/department/').then(resp=>{
    88. this.deps = resp;
    89. })
    90. },
    91. // 树的搜索
    92. filterNode(value, data) {
    93. if (!value) return true;
    94. return data.name.indexOf(value) !== -1;
    95. },
    96. // 添加弹框
    97. showAddDep(data){
    98. console.log(data)
    99. this.dep.parentId = data.id;
    100. this.pname = data.name;
    101. this.dialogVisible = 'true'
    102. },
    103. // 添加
    104. doAddDep(){
    105. this.postRequest('/system/basic/department/',this.dep).then(resp=>{
    106. if(resp.code==200){
    107. resp.obj.children = []
    108. this.addDep2Deps(this.deps,resp.obj);
    109. this.initDep();
    110. this.dialogVisible = false;
    111. }
    112. })
    113. },
    114. initDep(){
    115. this.dep = {
    116. name: '',
    117. parentId: -1
    118. }
    119. this.panme = ''
    120. },
    121. // 添加成功后手动的给树加数据
    122. addDep2Deps(deps,dep){
    123. for(let i = 0; ilength; i++){
    124. let d= deps[i];
    125. if(d.id == dep.parentId){
    126. d.children = d.children.concat(dep);
    127. if(d.children.length>0){
    128. d.isParent = true;
    129. }
    130. return;
    131. }else{
    132. // 递归
    133. this.addDep2Deps(d.children,dep);
    134. }
    135. }
    136. },
    137. // 删除
    138. deleteDep(data){
    139. console.log(data)
    140. if(data.isParent){
    141. this.$message.error("父部门无法删除");
    142. }else{
    143. this.$confirm('此操作将永久['+data.name+']部门, 是否继续?', '提示', {
    144. confirmButtonText: '确定',
    145. cancelButtonText: '取消',
    146. type: 'warning'
    147. }).then(() => {
    148. this.deleteRequest('/system/basic/department/'+data.id).then(resp=>{
    149. if(resp.code==200){
    150. this.removeDepFromDeps(null,this.deps,data.id);
    151. }
    152. })
    153. }).catch(() => {
    154. this.$message({
    155. type: 'info',
    156. message: '已取消删除'
    157. });
    158. });
    159. }
    160. },
    161. // 手动删除 (父部门,总部门数据,要删除的部门id)
    162. removeDepFromDeps(p,deps,id){
    163. for(let i=0; ilength; i++){
    164. let d = deps[i];
    165. if(d.id==id){
    166. deps.splice(i,1);
    167. if(deps.length==0){
    168. p.isParent = false;
    169. }
    170. return;
    171. }else{
    172. this.removeDepFromDeps(d,d.children,id);
    173. }
    174. }
    175. }
    176. },
    177. watch: {
    178. filterText(val) {
    179. this.$refs.tree.filter(val);
    180. }
    181. }
    182. }
    183. script>
    184. <style>
    185. .depBtn{
    186. padding: 3px;
    187. }
    188. style>

    需要注意的是:

    1:树组件中    :data="deps" 加载树组建的数据。:props="defaultProps" 加载树组件的配置,其中label是给个枝叶的名字对应的字段,children是子节点对应的字段。:filter-node-method="filterNode" 树组件的搜索,filterNode过滤的回调,这个官网拷贝即可。:expand-on-click-node="false" 关闭点击折叠,只有点击前面的小三角才能展开折叠。

    2:搜索框绑定的数据filterText,下面监听这个数据的改变,如果改变了,就调用树的filter方法(this.$refs.tree.filter(val);),进行过滤,这个方法的回调在树组件的属性中定义:filter-node-method="filterNode" ,也就是输入框值改变了,会去掉filterNode这个方法,这个方法传入两个值,value是文本框输入值,data是树组件的数据,value为空直接返回,不为空则过滤。

    3: 添加部门的时候,添加成功后不能单纯的掉接口,重新请求一次树中的数据,这样的话,每添加一个部门,整个树就会折叠起来。这时候就需要不调接口请求新的数据,在js中操作树中的数据this.deps,让它和数据库保持同步。首先在成功后调用方法: addDep2Deps(deps,dep)  这个方法第一个参数是整个树中的数据,第二个参数是新添加的树的数据(这个数据是添加成功接口回显的数据,也就是添加的这条记录信息)在这个方法中,会循环,找到对应的父节点,给它的子节点拼接数据,修改父节点isParent属性(是否有孩子),之后就一直递归,知道添加完成为止。这个数据添加成功后,清空弹出框中输入的信息,关闭弹出框。

    4:删除操作,同样,删除时也要手动的在js中把这条数据删除,不能请求新数据,请求新数据会导致树整个关闭,用户体验十分不好,需要在js中把树中的数据和数据库中进行同步。

    调用接口删除成功后,调用removeDepFromDeps(p,deps,id)方法,在js中进行数据删除,调用时,第一个参数传null表示从顶层节点开始往下找,第二个参数是树的数据,第三个参数是要删除部门的id。同样进行循环,添加中比较的是父节点的id,删除是,比较的就是这个叶子的id,如果相同,那就删除,同时,判断把这个叶子删掉后,这个枝下面还有没有叶子,因为有叶子的枝是不能删除的,所以要再判断一下修改isParent的状态,之后还是一样,在一层中没有查询到的话,就递归到下一层去找。

    案例二

    这种前面带有选择框的,进行授权操作 

    2.1后端准备

    对应的数据库表

     对应的实体类:

    1. @Data
    2. @EqualsAndHashCode(callSuper = false)
    3. @Accessors(chain = true)
    4. @TableName("t_menu")
    5. @ApiModel(value="Menu对象", description="")
    6. public class Menu implements Serializable {
    7. private static final long serialVersionUID = 1L;
    8. @ApiModelProperty(value = "id")
    9. @TableId(value = "id", type = IdType.AUTO)
    10. private Integer id;
    11. @ApiModelProperty(value = "url")
    12. private String url;
    13. @ApiModelProperty(value = "path")
    14. private String path;
    15. @ApiModelProperty(value = "组件")
    16. private String component;
    17. @ApiModelProperty(value = "菜单名")
    18. private String name;
    19. @ApiModelProperty(value = "图标")
    20. private String iconCls;
    21. @ApiModelProperty(value = "是否保持激活")
    22. private Boolean keepAlive;
    23. @ApiModelProperty(value = "是否要求权限")
    24. private Boolean requireAuth;
    25. @ApiModelProperty(value = "父id")
    26. private Integer parentId;
    27. @ApiModelProperty(value = "是否启用")
    28. private Boolean enabled;
    29. @ApiModelProperty(value = "子菜单")
    30. @TableField(exist = false) // 告诉mybatisplus这个字段不在表中,查询的时候不要去查
    31. private List children;
    32. @ApiModelProperty(value = "角色列表")
    33. @TableField(exist = false)
    34. private List roles;
    35. }

     查询接口返回的数据

    1. {
    2. "code": 200,
    3. "message": "查询成功",
    4. "obj": [
    5. {
    6. "id": 1,
    7. "url": null,
    8. "path": null,
    9. "component": null,
    10. "name": "所有",
    11. "iconCls": null,
    12. "keepAlive": null,
    13. "requireAuth": null,
    14. "parentId": null,
    15. "enabled": null,
    16. "children": [
    17. {
    18. "id": 2,
    19. "url": null,
    20. "path": null,
    21. "component": null,
    22. "name": "员工资料",
    23. "iconCls": null,
    24. "keepAlive": null,
    25. "requireAuth": null,
    26. "parentId": null,
    27. "enabled": null,
    28. "children": [
    29. {
    30. "id": 7,
    31. "url": null,
    32. "path": null,
    33. "component": null,
    34. "name": "基本资料",
    35. "iconCls": null,
    36. "keepAlive": null,
    37. "requireAuth": null,
    38. "parentId": null,
    39. "enabled": null,
    40. "children": null,
    41. "roles": null
    42. },
    43. {
    44. "id": 8,
    45. "url": null,
    46. "path": null,
    47. "component": null,
    48. "name": "高级资料",
    49. "iconCls": null,
    50. "keepAlive": null,
    51. "requireAuth": null,
    52. "parentId": null,
    53. "enabled": null,
    54. "children": null,
    55. "roles": null
    56. }
    57. ],
    58. "roles": null
    59. },
    60. {
    61. "id": 3,
    62. "url": null,
    63. "path": null,
    64. "component": null,
    65. "name": "人事管理",
    66. "iconCls": null,
    67. "keepAlive": null,
    68. "requireAuth": null,
    69. "parentId": null,
    70. "enabled": null,
    71. "children": [
    72. {
    73. "id": 9,
    74. "url": null,
    75. "path": null,
    76. "component": null,
    77. "name": "员工资料",
    78. "iconCls": null,
    79. "keepAlive": null,
    80. "requireAuth": null,
    81. "parentId": null,
    82. "enabled": null,
    83. "children": null,
    84. "roles": null
    85. },
    86. {
    87. "id": 10,
    88. "url": null,
    89. "path": null,
    90. "component": null,
    91. "name": "员工奖惩",
    92. "iconCls": null,
    93. "keepAlive": null,
    94. "requireAuth": null,
    95. "parentId": null,
    96. "enabled": null,
    97. "children": null,
    98. "roles": null
    99. },
    100. {
    101. "id": 11,
    102. "url": null,
    103. "path": null,
    104. "component": null,
    105. "name": "员工培训",
    106. "iconCls": null,
    107. "keepAlive": null,
    108. "requireAuth": null,
    109. "parentId": null,
    110. "enabled": null,
    111. "children": null,
    112. "roles": null
    113. },
    114. {
    115. "id": 12,
    116. "url": null,
    117. "path": null,
    118. "component": null,
    119. "name": "员工调薪",
    120. "iconCls": null,
    121. "keepAlive": null,
    122. "requireAuth": null,
    123. "parentId": null,
    124. "enabled": null,
    125. "children": null,
    126. "roles": null
    127. },
    128. {
    129. "id": 13,
    130. "url": null,
    131. "path": null,
    132. "component": null,
    133. "name": "员工调动",
    134. "iconCls": null,
    135. "keepAlive": null,
    136. "requireAuth": null,
    137. "parentId": null,
    138. "enabled": null,
    139. "children": null,
    140. "roles": null
    141. }
    142. ],
    143. "roles": null
    144. },
    145. {
    146. "id": 4,
    147. "url": null,
    148. "path": null,
    149. "component": null,
    150. "name": "薪资管理",
    151. "iconCls": null,
    152. "keepAlive": null,
    153. "requireAuth": null,
    154. "parentId": null,
    155. "enabled": null,
    156. "children": [
    157. {
    158. "id": 14,
    159. "url": null,
    160. "path": null,
    161. "component": null,
    162. "name": "工资账套管理",
    163. "iconCls": null,
    164. "keepAlive": null,
    165. "requireAuth": null,
    166. "parentId": null,
    167. "enabled": null,
    168. "children": null,
    169. "roles": null
    170. },
    171. {
    172. "id": 15,
    173. "url": null,
    174. "path": null,
    175. "component": null,
    176. "name": "员工账套设置",
    177. "iconCls": null,
    178. "keepAlive": null,
    179. "requireAuth": null,
    180. "parentId": null,
    181. "enabled": null,
    182. "children": null,
    183. "roles": null
    184. },
    185. {
    186. "id": 16,
    187. "url": null,
    188. "path": null,
    189. "component": null,
    190. "name": "工资表管理",
    191. "iconCls": null,
    192. "keepAlive": null,
    193. "requireAuth": null,
    194. "parentId": null,
    195. "enabled": null,
    196. "children": null,
    197. "roles": null
    198. },
    199. {
    200. "id": 17,
    201. "url": null,
    202. "path": null,
    203. "component": null,
    204. "name": "月末处理",
    205. "iconCls": null,
    206. "keepAlive": null,
    207. "requireAuth": null,
    208. "parentId": null,
    209. "enabled": null,
    210. "children": null,
    211. "roles": null
    212. },
    213. {
    214. "id": 18,
    215. "url": null,
    216. "path": null,
    217. "component": null,
    218. "name": "工资表查询",
    219. "iconCls": null,
    220. "keepAlive": null,
    221. "requireAuth": null,
    222. "parentId": null,
    223. "enabled": null,
    224. "children": null,
    225. "roles": null
    226. }
    227. ],
    228. "roles": null
    229. },
    230. {
    231. "id": 5,
    232. "url": null,
    233. "path": null,
    234. "component": null,
    235. "name": "统计管理",
    236. "iconCls": null,
    237. "keepAlive": null,
    238. "requireAuth": null,
    239. "parentId": null,
    240. "enabled": null,
    241. "children": [
    242. {
    243. "id": 19,
    244. "url": null,
    245. "path": null,
    246. "component": null,
    247. "name": "综合信息统计",
    248. "iconCls": null,
    249. "keepAlive": null,
    250. "requireAuth": null,
    251. "parentId": null,
    252. "enabled": null,
    253. "children": null,
    254. "roles": null
    255. },
    256. {
    257. "id": 20,
    258. "url": null,
    259. "path": null,
    260. "component": null,
    261. "name": "员工积分统计",
    262. "iconCls": null,
    263. "keepAlive": null,
    264. "requireAuth": null,
    265. "parentId": null,
    266. "enabled": null,
    267. "children": null,
    268. "roles": null
    269. },
    270. {
    271. "id": 21,
    272. "url": null,
    273. "path": null,
    274. "component": null,
    275. "name": "人事信息统计",
    276. "iconCls": null,
    277. "keepAlive": null,
    278. "requireAuth": null,
    279. "parentId": null,
    280. "enabled": null,
    281. "children": null,
    282. "roles": null
    283. },
    284. {
    285. "id": 22,
    286. "url": null,
    287. "path": null,
    288. "component": null,
    289. "name": "人事记录统计",
    290. "iconCls": null,
    291. "keepAlive": null,
    292. "requireAuth": null,
    293. "parentId": null,
    294. "enabled": null,
    295. "children": null,
    296. "roles": null
    297. }
    298. ],
    299. "roles": null
    300. },
    301. {
    302. "id": 6,
    303. "url": null,
    304. "path": null,
    305. "component": null,
    306. "name": "系统管理",
    307. "iconCls": null,
    308. "keepAlive": null,
    309. "requireAuth": null,
    310. "parentId": null,
    311. "enabled": null,
    312. "children": [
    313. {
    314. "id": 23,
    315. "url": null,
    316. "path": null,
    317. "component": null,
    318. "name": "基础信息设置",
    319. "iconCls": null,
    320. "keepAlive": null,
    321. "requireAuth": null,
    322. "parentId": null,
    323. "enabled": null,
    324. "children": null,
    325. "roles": null
    326. },
    327. {
    328. "id": 24,
    329. "url": null,
    330. "path": null,
    331. "component": null,
    332. "name": "系统管理",
    333. "iconCls": null,
    334. "keepAlive": null,
    335. "requireAuth": null,
    336. "parentId": null,
    337. "enabled": null,
    338. "children": null,
    339. "roles": null
    340. },
    341. {
    342. "id": 25,
    343. "url": null,
    344. "path": null,
    345. "component": null,
    346. "name": "操作日志管理",
    347. "iconCls": null,
    348. "keepAlive": null,
    349. "requireAuth": null,
    350. "parentId": null,
    351. "enabled": null,
    352. "children": null,
    353. "roles": null
    354. },
    355. {
    356. "id": 26,
    357. "url": null,
    358. "path": null,
    359. "component": null,
    360. "name": "操作员管理",
    361. "iconCls": null,
    362. "keepAlive": null,
    363. "requireAuth": null,
    364. "parentId": null,
    365. "enabled": null,
    366. "children": null,
    367. "roles": null
    368. },
    369. {
    370. "id": 27,
    371. "url": null,
    372. "path": null,
    373. "component": null,
    374. "name": "备份恢复数据库",
    375. "iconCls": null,
    376. "keepAlive": null,
    377. "requireAuth": null,
    378. "parentId": null,
    379. "enabled": null,
    380. "children": null,
    381. "roles": null
    382. },
    383. {
    384. "id": 28,
    385. "url": null,
    386. "path": null,
    387. "component": null,
    388. "name": "初始化数据库",
    389. "iconCls": null,
    390. "keepAlive": null,
    391. "requireAuth": null,
    392. "parentId": null,
    393. "enabled": null,
    394. "children": null,
    395. "roles": null
    396. }
    397. ],
    398. "roles": null
    399. }
    400. ],
    401. "roles": null
    402. }
    403. ]
    404. }

    2.2前端代码

    1. <template>
    2. <div>
    3. <div class="permissManaTool">
    4. <el-input size="small" placeholder="请输入角色英文名" v-model="role.name">
    5. <template slot="prepend">ROLE_template>
    6. el-input>
    7. <el-input size="small" placeholder="请输入角色中文名" v-model="role.nameZh" @keydown.enter.native="addRole">el-input>
    8. <el-button size="small" type="primary" icon="el-icon-plus" @click="addRole">添加角色el-button>
    9. div>
    10. <div style="margin-top:10px; width:660px">
    11. <el-collapse v-model="activeName" accordion @change="change">
    12. <el-collapse-item :title="r.nameZh" :name="r.id" v-for="(r,index) in roles" :key="index">
    13. <el-card class="box-card">
    14. <div slot="header" class="clearfix">
    15. <span>可访问资源span>
    16. <el-button style="float: right; padding: 3px 0; color: #ff0000;" type="text" icon="el-icon-delete" @click="doDeleteRole(r)">el-button>
    17. div>
    18. <div>
    19. <el-tree
    20. show-checkbox
    21. node-key="id"
    22. ref="tree"
    23. :key="index"
    24. :default-checked-keys="selectMenus"
    25. :data="allMenus" :props="defaultProps">el-tree>
    26. <div style="display:flex; justify-content: flex-end">
    27. <el-button size="mini" @click="cancelUpdate">取消修改el-button>
    28. <el-button size="mini" type="primary" @click="doUpdate(r.id,index)">确定修改el-button>
    29. div>
    30. div>
    31. el-card>
    32. el-collapse-item>
    33. el-collapse>
    34. div>
    35. div>
    36. template>
    37. <script>
    38. export default {
    39. data(){
    40. return{
    41. role:{
    42. name:'',
    43. nameZh:''
    44. },
    45. activeName : '-1',
    46. roles:[],
    47. allMenus: [],
    48. // 树菜单的属性,children子菜单的属性,label显示出来的名字,都是后端接口返回来的字段名字
    49. defaultProps: {
    50. children: 'children',
    51. label: 'name'
    52. },
    53. // 树中选中的节点
    54. selectMenus: []
    55. }
    56. },
    57. mounted(){
    58. this.initRoles();
    59. },
    60. methods:{
    61. // 初始化所有菜单
    62. initAllMenus(){
    63. this.getRequest('/system/basic/permiss/menus').then(resp=>{
    64. if(resp.code==200){
    65. this.allMenus = resp.obj;
    66. }
    67. })
    68. },
    69. // 根据角色id获取菜单
    70. initSelectdMenus(rid){
    71. this.getRequest('/system/basic/permiss/mid/'+rid).then(resp=>{
    72. if(resp.code==200){
    73. this.selectMenus = resp.obj;
    74. }
    75. })
    76. },
    77. // 获取角色列表
    78. initRoles(){
    79. this.getRequest('/system/basic/permiss/').then(resp=>{
    80. if(resp.code==200){
    81. this.roles = resp.obj;
    82. }
    83. })
    84. },
    85. // 手风琴点击事件,展开rid是每个name,name对应着后端字段id,关闭时rid为空
    86. change(rid){
    87. if(rid){
    88. this.initAllMenus();
    89. this.initSelectdMenus(rid);
    90. }
    91. },
    92. // 修改角色权限
    93. doUpdate(rid,index){
    94. // 拿到这个手风琴下面的树
    95. let tree = this.$refs.tree[index];
    96. // 传true只打印叶子节点的id
    97. let selectedKeys = tree.getCheckedKeys(true);
    98. let url = '/system/basic/permiss/?rid='+ rid;
    99. selectedKeys.forEach(key => {
    100. url += '&mids='+ key;
    101. });
    102. this.putRequest(url).then(resp=>{
    103. if(resp.code==200){
    104. this.activeName = '-1'
    105. }
    106. })
    107. },
    108. cancelUpdate(){
    109. this.activeName = '-1'
    110. },
    111. // 添加角色
    112. addRole(){
    113. if(this.role.name && this.role.nameZh){
    114. this.postRequest('/system/basic/permiss/',this.role).then(resp=>{
    115. if(resp.code==200){
    116. this.initRoles();
    117. this.role.name = '';
    118. this.role.nameZh = '';
    119. }
    120. })
    121. }else{
    122. this.$message.error("所有字段不能为空");
    123. }
    124. },
    125. // 删除角色
    126. doDeleteRole(role){
    127. this.$confirm('此操作将永久删除'+role.nameZh+'角色, 是否继续?', '提示', {
    128. confirmButtonText: '确定',
    129. cancelButtonText: '取消',
    130. type: 'warning'
    131. }).then(() => {
    132. this.deleteRequest('/system/basic/permiss/role/'+r.id).then(resp => {
    133. if(resp.code == 200){
    134. this.initRoles();
    135. }else{
    136. this.$message.error(resp.message)
    137. }
    138. })
    139. }).catch(() => {
    140. this.$message({
    141. type: 'info',
    142. message: '已取消删除'
    143. });
    144. });
    145. }
    146. }
    147. }
    148. script>
    149. <style>
    150. .permissManaTool{
    151. display: flex;
    152. justify-content: flex-start;
    153. }
    154. .permissManaTool .el-input{
    155. width: 300px;
    156. margin-right: 10px;
    157. }
    158. style>

    值得注意的是:

    1:每个角色下面展开的权限树列表用的是手风琴组件(折叠面板)这里还要给树加上key,因为每个手风琴下面都是一个树 折叠面板饿了吗官网

    2:树要展示前面的选择框,要给树组件加上show-checkbox属性。:default-checked-keys="selectMenus" 默认选中的key,这个selectMenus需要去data中定义一个数组。

    3:在添加时,可通过 let tree = this.$refs.tree[index]; 拿到整个手风琴下面的树,let selectedKeys = tree.getCheckedKeys(true) 获取选中节点的id,修改成功后,把手风琴的折叠属性,定义成-1,折叠即可,因为下次再打开的时候,会去数据库查出这个角色对应菜单的最新数据。

     

     

  • 相关阅读:
    653. 两数之和 IV - 输入二叉搜索树
    【网络】- 计算机网络体系结构 - OSI七层模型、TCP/IP四层(五层)协议
    SAP PI PO 接口常见问题处理:队列平衡的统计平均分配
    springboot+电子族谱信息系统 毕业设计-附源码161714
    【总结】深度学习阶段性总结
    Vue3 项目中 vue文件出现大面积爆红问题
    DAZ To UMA⭐五.模型在Blender中的配置教程
    阿里云一键登录(号码认证服务)
    SQL常用语句 笔记
    Java - 手写识别; 如何用spring ai和大模型做手写识别教程
  • 原文地址:https://blog.csdn.net/w13966597931/article/details/128177033