goupan
2024-04-03 5506e9a45e717ffcb67ec313b5a4e8206d9b3a39
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
/*
 * Copyright [2020-2030] [https://www.stylefeng.cn]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Guns采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Guns源码头部的版权声明。
 * 3.请保留源码和相关描述文件的项目出处,作者声明等。
 * 4.分发源码时候,请注明软件出处 https://gitee.com/stylefeng/guns
 * 5.在修改包名,模块名称,项目代码等时,请注明软件出处 https://gitee.com/stylefeng/guns
 * 6.若您的项目无法满足以上几点,可申请商业授权
 */
package cn.stylefeng.roses.kernel.system.modular.menu.service.impl;
 
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
import cn.stylefeng.roses.kernel.auth.api.pojo.login.basic.SimpleRoleInfo;
import cn.stylefeng.roses.kernel.db.api.DbOperatorApi;
import cn.stylefeng.roses.kernel.rule.constants.SymbolConstant;
import cn.stylefeng.roses.kernel.rule.constants.TreeConstants;
import cn.stylefeng.roses.kernel.rule.enums.StatusEnum;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.roses.kernel.rule.tree.factory.DefaultTreeBuildFactory;
import cn.stylefeng.roses.kernel.rule.tree.ztree.ZTreeNode;
import cn.stylefeng.roses.kernel.system.api.AppServiceApi;
import cn.stylefeng.roses.kernel.system.api.MenuServiceApi;
import cn.stylefeng.roses.kernel.system.api.RoleServiceApi;
import cn.stylefeng.roses.kernel.system.api.enums.AntdvFrontTypeEnum;
import cn.stylefeng.roses.kernel.system.api.exception.SystemModularException;
import cn.stylefeng.roses.kernel.system.api.exception.enums.menu.SysMenuExceptionEnum;
import cn.stylefeng.roses.kernel.system.api.pojo.app.SysAppResult;
import cn.stylefeng.roses.kernel.system.api.pojo.login.v3.IndexMenuInfo;
import cn.stylefeng.roses.kernel.system.api.pojo.menu.MenuAndButtonTreeResponse;
import cn.stylefeng.roses.kernel.system.api.pojo.menu.SysMenuButtonDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.menu.SysMenuRequest;
import cn.stylefeng.roses.kernel.system.api.pojo.menu.antd.AntdMenuSelectTreeNode;
import cn.stylefeng.roses.kernel.system.api.pojo.menu.antd.AntdSysMenuDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.menu.layui.LayuiAppIndexMenusVO;
import cn.stylefeng.roses.kernel.system.api.pojo.menu.layui.LayuiMenuAndButtonTreeResponse;
import cn.stylefeng.roses.kernel.system.api.pojo.role.dto.SysRoleMenuButtonDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.role.dto.SysRoleMenuDTO;
import cn.stylefeng.roses.kernel.system.api.pojo.role.request.SysRoleRequest;
import cn.stylefeng.roses.kernel.system.modular.menu.entity.SysMenu;
import cn.stylefeng.roses.kernel.system.modular.menu.entity.SysMenuButton;
import cn.stylefeng.roses.kernel.system.modular.menu.entity.SysMenuResource;
import cn.stylefeng.roses.kernel.system.modular.menu.factory.AntdMenusFactory;
import cn.stylefeng.roses.kernel.system.modular.menu.factory.Antdv3MenusFactory;
import cn.stylefeng.roses.kernel.system.modular.menu.factory.LayuiMenusFactory;
import cn.stylefeng.roses.kernel.system.modular.menu.factory.MenuTypeFactory;
import cn.stylefeng.roses.kernel.system.modular.menu.mapper.SysMenuMapper;
import cn.stylefeng.roses.kernel.system.modular.menu.service.SysMenuButtonService;
import cn.stylefeng.roses.kernel.system.modular.menu.service.SysMenuResourceService;
import cn.stylefeng.roses.kernel.system.modular.menu.service.SysMenuService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
 
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
 
/**
 * 系统菜单service接口实现类
 *
 * @author fengshuonan
 * @date 2020/3/13 16:05
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService, MenuServiceApi {
 
    @Resource
    private DbOperatorApi dbOperatorApi;
 
    @Resource
    private RoleServiceApi roleServiceApi;
 
    @Resource
    private AppServiceApi appServiceApi;
 
    @Resource
    private SysMenuButtonService sysMenuButtonService;
 
    @Resource
    private SysMenuResourceService sysMenuResourceService;
 
    @Override
    public void add(SysMenuRequest sysMenuRequest) {
 
        // 如果父节点为空,则填充为默认的父节点id
        if (sysMenuRequest.getMenuParentId() == null) {
            sysMenuRequest.setMenuParentId(TreeConstants.DEFAULT_PARENT_ID);
        }
 
        // 如果父节点不为空,并且不是-1,则判断父节点存不存在,防止脏数据
        else {
            if (!TreeConstants.DEFAULT_PARENT_ID.equals(sysMenuRequest.getMenuParentId())) {
                SysMenuRequest tempParam = new SysMenuRequest();
                tempParam.setMenuId(sysMenuRequest.getMenuParentId());
                this.querySysMenu(tempParam);
            }
        }
 
        SysMenu sysMenu = new SysMenu();
        BeanUtil.copyProperties(sysMenuRequest, sysMenu);
 
        // 组装pids
        String newPids = createPids(sysMenuRequest.getMenuParentId());
        sysMenu.setMenuPids(newPids);
 
        // 设置启用状态
        sysMenu.setStatusFlag(StatusEnum.ENABLE.getCode());
        sysMenu.setDelFlag(YesOrNotEnum.N.getCode());
 
        // 设置添加的菜单的类型
        MenuTypeFactory.processMenuType(sysMenu, sysMenuRequest.getVisible());
 
        // 设置如果菜单前后台类型如果为空,则默认为都显示
        if (ObjectUtil.isEmpty(sysMenuRequest.getAntdvFrontType())) {
            sysMenu.setAntdvFrontType(AntdvFrontTypeEnum.TOTAL_SHOW.getCode());
        }
 
        this.save(sysMenu);
    }
 
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void del(SysMenuRequest sysMenuRequest) {
 
        Long id = sysMenuRequest.getMenuId();
 
        // 获取所有子级的节点id
        Set<Long> childIdList = this.dbOperatorApi.findSubListByParentId("sys_menu", "menu_pids", "menu_id", id);
        childIdList.add(id);
 
        // 逻辑删除,设置删除标识
        LambdaUpdateWrapper<SysMenu> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(SysMenu::getMenuId, childIdList).set(SysMenu::getDelFlag, YesOrNotEnum.Y.getCode());
        this.update(updateWrapper);
 
        // 删除该菜单下的按钮
        sysMenuButtonService.deleteMenuButtonByMenuId(id);
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(SysMenuRequest sysMenuRequest) {
 
        // 获取库中的菜单信息
        SysMenu oldMenu = this.querySysMenu(sysMenuRequest);
 
        // 更新子节点以及子节点的子节点的appCode和层级关系(pids)
        String newPids = updateChildrenAppAndLevel(sysMenuRequest, oldMenu);
 
        // 拷贝参数到实体中
        BeanUtil.copyProperties(sysMenuRequest, oldMenu);
 
        // 设置新的pids
        oldMenu.setMenuPids(newPids);
 
        // 不能修改状态,用修改状态接口修改状态
        oldMenu.setStatusFlag(null);
 
        // 设置添加的菜单的类型
        MenuTypeFactory.processMenuType(oldMenu, sysMenuRequest.getVisible());
 
        this.updateById(oldMenu);
    }
 
    @Override
    public SysMenu detail(SysMenuRequest sysMenuRequest) {
        SysMenu sysMenu = this.querySysMenu(sysMenuRequest);
 
        // 设置父级菜单名称
        if (sysMenu != null) {
            Long menuParentId = sysMenu.getMenuParentId();
            if (TreeConstants.DEFAULT_PARENT_ID.equals(menuParentId)) {
                sysMenu.setMenuParentName("顶级");
            } else {
                Long parentId = sysMenu.getMenuParentId();
                SysMenu parentMenu = this.getById(parentId);
                if (parentMenu == null) {
                    sysMenu.setMenuParentName("无");
                } else {
                    sysMenu.setMenuParentName(parentMenu.getMenuName());
                }
            }
        }
 
        return sysMenu;
    }
 
    @Override
    public List<SysMenu> findList(SysMenuRequest sysMenuRequest) {
 
        LambdaQueryWrapper<SysMenu> wrapper = createWrapper(sysMenuRequest);
 
        List<SysMenu> list = this.list(wrapper);
 
        // 应用编码转化为应用名称
        HashMap<String, String> appCodeName = new HashMap<>();
        Set<String> appCodeSet = list.stream().map(SysMenu::getAppCode).collect(Collectors.toSet());
        for (String appCode : appCodeSet) {
            String appName = appServiceApi.getAppNameByAppCode(appCode);
            appCodeName.put(appCode, appName);
        }
 
        // 查询对应菜单的应用名称
        for (SysMenu sysMenu : list) {
            sysMenu.setAppName(appCodeName.get(sysMenu.getAppCode()));
        }
 
        return list;
    }
 
    @Override
    public List<SysMenu> findListWithTreeStructure(SysMenuRequest sysMenuRequest) {
 
        List<SysMenu> sysMenuList = this.findList(sysMenuRequest);
 
        // 遍历菜单,设置是否是叶子节点属性
        AntdMenusFactory.fillLeafFlag(sysMenuList);
 
        // 将结果集处理成树
        List<SysMenu> treeMenus = new DefaultTreeBuildFactory<SysMenu>().doTreeBuild(sysMenuList);
 
        // 如果树节点构建失败,则返回平级节点
        if (ObjectUtil.isEmpty(treeMenus)) {
            return sysMenuList;
        } else {
            return treeMenus;
        }
    }
 
    @Override
    public List<ZTreeNode> layuiSelectParentMenuTreeList() {
 
        ArrayList<ZTreeNode> zTreeNodes = new ArrayList<>();
 
        List<SysMenu> allMenus = this.list();
        for (SysMenu sysMenu : allMenus) {
            ZTreeNode zTreeNode = new ZTreeNode();
            zTreeNode.setId(sysMenu.getMenuId());
            zTreeNode.setpId(sysMenu.getMenuParentId());
            zTreeNode.setName(sysMenu.getMenuName());
            zTreeNode.setOpen(false);
            zTreeNodes.add(zTreeNode);
        }
 
        // 创建顶级节点
        zTreeNodes.add(ZTreeNode.createParent());
 
        return zTreeNodes;
    }
 
    @Override
    public List<AntdMenuSelectTreeNode> tree(SysMenuRequest sysMenuRequest) {
        List<AntdMenuSelectTreeNode> menuTreeNodeList = CollectionUtil.newArrayList();
 
        // 添加根节点
        AntdMenuSelectTreeNode rootNode = AntdMenusFactory.createRootNode();
        menuTreeNodeList.add(rootNode);
 
        LambdaQueryWrapper<SysMenu> wrapper = createWrapper(sysMenuRequest);
        this.list(wrapper).forEach(sysMenu -> {
            AntdMenuSelectTreeNode menuTreeNode = AntdMenusFactory.parseMenuBaseTreeNode(sysMenu);
            menuTreeNodeList.add(menuTreeNode);
        });
 
        // -2是根节点的上级
        return new DefaultTreeBuildFactory<AntdMenuSelectTreeNode>("-2").doTreeBuild(menuTreeNodeList);
    }
 
    @Override
    public List<LayuiAppIndexMenusVO> getLayuiIndexMenus() {
 
        // 获取当前用户所有菜单
        List<SysMenu> currentUserMenus = this.getCurrentUserMenus(null, true, null);
 
        // 组装每个应用的菜单树
        List<LayuiAppIndexMenusVO> layuiAppIndexMenuVOS = LayuiMenusFactory.createLayuiAppIndexMenus(currentUserMenus);
 
        // 给应用排序,激活的应用放在前边
        String activeAppCode = appServiceApi.getActiveAppCode();
        if (activeAppCode != null) {
            List<LayuiAppIndexMenusVO> layuiAppIndexMenusVOArrayList = layuiAppIndexMenuVOS.stream().filter(i -> activeAppCode.equals(i.getAppCode())).collect(Collectors.toList());
            layuiAppIndexMenusVOArrayList.addAll(layuiAppIndexMenuVOS.stream().filter(i -> !activeAppCode.equals(i.getAppCode())).collect(Collectors.toList()));
            return layuiAppIndexMenusVOArrayList;
        }
 
        return layuiAppIndexMenuVOS;
    }
 
    @Override
    public List<AntdSysMenuDTO> getLeftMenusAntdv(SysMenuRequest sysMenuRequest) {
 
        // 获取前台或者后台类型
        Integer antdvFrontType = sysMenuRequest.getAntdvFrontType();
        if (antdvFrontType == null) {
            antdvFrontType = AntdvFrontTypeEnum.BACKEND.getCode();
        }
 
        // 获取当前已经启用的应用,并且按排序字段排序的
        List<SysAppResult> appNameSorted = appServiceApi.getSortedApps();
        if (ObjectUtil.isEmpty(appNameSorted)) {
            throw new ServiceException(SysMenuExceptionEnum.CANT_FIND_APPS);
        }
 
        // 查询菜单
        List<String> appCodes = appNameSorted.stream().map(SysAppResult::getAppCode).collect(Collectors.toList());
        List<SysMenu> currentUserMenus = this.getCurrentUserMenus(appCodes, false, antdvFrontType);
 
        // 将菜单按应用编码分类
        Map<String, List<SysMenu>> sortedUserMenus = AntdMenusFactory.sortUserMenusByAppCode(currentUserMenus);
 
        // 获取应用名称集合,带顺序
        List<String> appNames = appNameSorted.stream().map(SysAppResult::getAppName).collect(Collectors.toList());
        return AntdMenusFactory.createTotalMenus(sortedUserMenus, appNames);
    }
 
    @Override
    public List<LayuiMenuAndButtonTreeResponse> getMenuAndButtonTree(SysRoleRequest sysRoleRequest, Boolean lateralFlag) {
        List<LayuiMenuAndButtonTreeResponse> menuTreeNodeList = CollectionUtil.newArrayList();
 
        // 查询未删除的启用的菜单列表
        LambdaQueryWrapper<SysMenu> menuWrapper = new LambdaQueryWrapper<>();
        menuWrapper.eq(SysMenu::getStatusFlag, StatusEnum.ENABLE.getCode());
        menuWrapper.eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode());
 
        // 非超级管理员则获取自己拥有的菜单
        if (!LoginContext.me().getSuperAdminFlag()) {
            List<Long> menuIdList = getCurrentUserMenuIds();
            if (!menuIdList.isEmpty()) {
                menuWrapper.in(SysMenu::getMenuId, menuIdList);
            }
        }
        List<SysMenu> sysMenuList = this.list(menuWrapper);
 
        // 获取菜单的id集合
        List<Long> menuList = sysMenuList.parallelStream().map(SysMenu::getMenuId).collect(Collectors.toList());
 
        // 查询这些菜单对应的所有按钮
        LambdaQueryWrapper<SysMenuButton> buttonWrapper = new LambdaQueryWrapper<>();
        buttonWrapper.eq(SysMenuButton::getDelFlag, YesOrNotEnum.N.getCode());
        buttonWrapper.in(SysMenuButton::getMenuId, menuList);
        List<SysMenuButton> sysMenuButtons = sysMenuButtonService.list(buttonWrapper);
 
        // 把按钮按照菜单id存起来,方便后续操作
        Map<Long, List<SysMenuButton>> buttons = new HashMap<>(menuList.size());
        for (SysMenuButton menuButton : sysMenuButtons) {
            List<SysMenuButton> buttonList = buttons.get(menuButton.getMenuId());
            if (ObjectUtil.isEmpty(buttonList)) {
                buttonList = new ArrayList<>();
                buttons.put(menuButton.getMenuId(), buttonList);
            }
            buttonList.add(menuButton);
        }
 
        // 查询所有已有的权限
        // 所有已有的菜单权限
        List<SysRoleMenuDTO> roleMenuList = roleServiceApi.getRoleMenuList(Collections.singletonList(sysRoleRequest.getRoleId()));
 
        // 转换成map方便后续处理
        Map<Long, SysRoleMenuDTO> roleMenuMap = new HashMap<>();
        for (SysRoleMenuDTO sysRoleMenuResponse : roleMenuList) {
            roleMenuMap.put(sysRoleMenuResponse.getMenuId(), sysRoleMenuResponse);
        }
 
        // 所有的按钮权限
        List<SysRoleMenuButtonDTO> roleMenuButtonList = roleServiceApi.getRoleMenuButtonList(Collections.singletonList(sysRoleRequest.getRoleId()));
 
        // 转换成map方便后续处理
        Map<Long, SysRoleMenuButtonDTO> roleMenuButtonMap = new HashMap<>();
        for (SysRoleMenuButtonDTO buttonResponse : roleMenuButtonList) {
            roleMenuButtonMap.put(buttonResponse.getButtonId(), buttonResponse);
        }
 
        // 组装树结果
        for (SysMenu sysMenu : sysMenuList) {
            LayuiMenuAndButtonTreeResponse menuTree = new LayuiMenuAndButtonTreeResponse();
            menuTree.setId(sysMenu.getMenuId());
            menuTree.setMenuFlag(true);
            menuTree.setName(sysMenu.getMenuName());
            menuTree.setMenuCode(sysMenu.getMenuCode());
            menuTree.setPid(sysMenu.getMenuParentId());
            // 判断是否已经有了
            SysRoleMenuDTO roleMenuResponse = roleMenuMap.get(sysMenu.getMenuId());
            menuTree.setChecked(!ObjectUtil.isEmpty(roleMenuResponse));
 
            // 处理该菜单的按钮
            List<SysMenuButton> menuButtons = buttons.get(sysMenu.getMenuId());
 
            // 不为空就去处理
            if (ObjectUtil.isNotEmpty(menuButtons)) {
                for (SysMenuButton menuButton : menuButtons) {
                    LayuiMenuAndButtonTreeResponse buttonTree = new LayuiMenuAndButtonTreeResponse();
                    buttonTree.setName(menuButton.getButtonName());
                    buttonTree.setId(menuButton.getButtonId());
                    buttonTree.setPid(menuButton.getMenuId());
                    buttonTree.setButtonCode(menuButton.getButtonCode());
                    buttonTree.setMenuFlag(false);
                    // 判断是否已经拥有
                    SysRoleMenuButtonDTO buttonResponse = roleMenuButtonMap.get(menuButton.getButtonId());
                    if (ObjectUtil.isNotEmpty(buttonResponse)) {
                        buttonTree.setChecked(true);
                        menuTree.setChecked(true);
                    } else {
                        buttonTree.setChecked(false);
                    }
                    // 记录按钮节点
                    menuTreeNodeList.add(buttonTree);
                }
            }
            // 记录菜单节点
            menuTreeNodeList.add(menuTree);
        }
 
        // 返回结果
        if (lateralFlag) {
            return menuTreeNodeList;
        } else {
            return new DefaultTreeBuildFactory<LayuiMenuAndButtonTreeResponse>().doTreeBuild(menuTreeNodeList);
        }
    }
 
    @Override
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    public List<MenuAndButtonTreeResponse> getRoleMenuAndButtons(SysRoleRequest sysRoleRequest) {
        // 查询未删除的启用的菜单列表
        LambdaQueryWrapper<SysMenu> menuWrapper = new LambdaQueryWrapper<>();
        menuWrapper.eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode());
        menuWrapper.eq(SysMenu::getStatusFlag, StatusEnum.ENABLE.getCode());
 
        // 查询所有菜单列表
        List<SysMenu> sysMenuList = this.list(menuWrapper);
 
        // 获取菜单的id集合
        List<Long> menuIdList = sysMenuList.stream().map(SysMenu::getMenuId).collect(Collectors.toList());
 
        // 获取角色绑定的菜单的id
        List<SysRoleMenuDTO> roleMenuList = roleServiceApi.getRoleMenuList(Collections.singletonList(sysRoleRequest.getRoleId()));
 
        // 转化 --->>> 菜单列表自转化为响应的节点类型
        List<MenuAndButtonTreeResponse> menuAndButtonTreeResponses = AntdMenusFactory.parseMenuAndButtonTreeResponse(sysMenuList, roleMenuList);
 
        // 查询这些菜单对应的所有按钮
        LambdaQueryWrapper<SysMenuButton> buttonWrapper = new LambdaQueryWrapper<>();
        buttonWrapper.eq(SysMenuButton::getDelFlag, YesOrNotEnum.N.getCode());
        buttonWrapper.in(SysMenuButton::getMenuId, menuIdList);
        List<SysMenuButton> buttonList = sysMenuButtonService.list(buttonWrapper);
 
        // 获取角色绑定的按钮的id
        List<SysRoleMenuButtonDTO> roleMenuButtonList = roleServiceApi.getRoleMenuButtonList(Collections.singletonList(sysRoleRequest.getRoleId()));
 
        // 转化 --->>> 将这些按钮,分别绑定在各自的菜单上
        AntdMenusFactory.fillButtons(menuAndButtonTreeResponses, buttonList, roleMenuButtonList);
 
        // 菜单列表转化为一棵树
        return new DefaultTreeBuildFactory<MenuAndButtonTreeResponse>().doTreeBuild(menuAndButtonTreeResponses);
    }
 
    @Override
    public List<MenuAndButtonTreeResponse> getRoleBindMenuList(SysRoleRequest sysRoleRequest) {
 
        // 获取所有一级菜单,子菜单包含在children内
        List<SysMenu> sysMenus = totalMenusWithOneLevel(sysRoleRequest.getResourceBizType());
 
        // 获取角色绑定的菜单
        List<SysRoleMenuDTO> roleMenuList = roleServiceApi.getRoleMenuList(Collections.singletonList(sysRoleRequest.getRoleId()));
 
        // 将组装好的一级菜单和里边的children都转化为响应对象,并填充checked标识
        return AntdMenusFactory.parseMenuAndButtonTreeResponseWithChildren(sysMenus, roleMenuList);
    }
 
    @Override
    public List<MenuAndButtonTreeResponse> getRoleBindOperateList(SysRoleRequest sysRoleRequest) {
 
        // 获取所有一级菜单,子菜单包含在children内
        List<SysMenu> sysMenus = totalMenusWithOneLevel(sysRoleRequest.getResourceBizType());
 
        // 查询这些菜单对应的所有按钮
        LambdaQueryWrapper<SysMenuButton> buttonWrapper = new LambdaQueryWrapper<>();
        buttonWrapper.eq(SysMenuButton::getDelFlag, YesOrNotEnum.N.getCode());
        List<SysMenuButton> buttonList = sysMenuButtonService.list(buttonWrapper);
 
        // 将组装好的一级菜单和里边的children都转化为响应对象
        List<MenuAndButtonTreeResponse> menuAndButtonTreeResponses = AntdMenusFactory.fillButtons(sysMenus, buttonList);
 
        // 填充checked对象
        List<SysRoleMenuButtonDTO> roleMenuButtonList = roleServiceApi.getRoleMenuButtonList(Collections.singletonList(sysRoleRequest.getRoleId()));
        return AntdMenusFactory.fillButtonsChecked(menuAndButtonTreeResponses, roleMenuButtonList);
    }
 
    @Override
    public List<MenuAndButtonTreeResponse> getRoleBindMenuListV2(List<Long> roleIdList) {
 
        // 获取所有一级菜单,子菜单包含在children内
        List<SysMenu> sysMenus = totalMenusWithOneLevel(null);
 
        // 获取角色绑定的菜单
        List<SysRoleMenuDTO> roleMenuList = roleServiceApi.getRoleMenuList(roleIdList);
 
        // 将组装好的一级菜单和里边的children都转化为响应对象,并填充checked标识
        return AntdMenusFactory.parseMenuAndButtonTreeResponseWithChildren(sysMenus, roleMenuList);
    }
 
    @Override
    public List<MenuAndButtonTreeResponse> getRoleBindOperateListV2(List<Long> roleIdList) {
 
        // 获取所有一级菜单,子菜单包含在children内
        List<SysMenu> sysMenus = totalMenusWithOneLevel(null);
 
        // 查询这些菜单对应的所有按钮
        LambdaQueryWrapper<SysMenuButton> buttonWrapper = new LambdaQueryWrapper<>();
        buttonWrapper.eq(SysMenuButton::getDelFlag, YesOrNotEnum.N.getCode());
        List<SysMenuButton> buttonList = sysMenuButtonService.list(buttonWrapper);
 
        // 将组装好的一级菜单和里边的children都转化为响应对象
        List<MenuAndButtonTreeResponse> menuAndButtonTreeResponses = AntdMenusFactory.fillButtons(sysMenus, buttonList);
 
        // 填充checked对象
        List<SysRoleMenuButtonDTO> roleMenuButtonList = roleServiceApi.getRoleMenuButtonList(roleIdList);
        return AntdMenusFactory.fillButtonsChecked(menuAndButtonTreeResponses, roleMenuButtonList);
    }
 
    @Override
    public List<Long> getTotalMenuIdList(AntdvFrontTypeEnum antdvFrontTypeEnum) {
 
        // 查询所有菜单列表,根据前台传递参数,可选择前台还是后台菜单
        LambdaQueryWrapper<SysMenu> menuWrapper = new LambdaQueryWrapper<>();
        menuWrapper.select(SysMenu::getMenuId);
 
        menuWrapper.eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode());
        menuWrapper.eq(SysMenu::getStatusFlag, StatusEnum.ENABLE.getCode());
 
        if (antdvFrontTypeEnum != null) {
            menuWrapper.nested(i -> i.eq(SysMenu::getAntdvFrontType, antdvFrontTypeEnum.getCode()).or().eq(SysMenu::getAntdvFrontType, AntdvFrontTypeEnum.TOTAL_SHOW.getCode()));
        }
 
        List<SysMenu> sysMenuList = this.list(menuWrapper);
        return sysMenuList.stream().map(SysMenu::getMenuId).collect(Collectors.toList());
    }
 
    @Override
    public List<SysMenuButtonDTO> getTotalMenuButtonIdList(AntdvFrontTypeEnum antdvFrontTypeEnum) {
 
        List<Long> totalMenuIdList = this.getTotalMenuIdList(antdvFrontTypeEnum);
 
        if (ObjectUtil.isEmpty(totalMenuIdList)) {
            return new ArrayList<>();
        }
 
        // 获取所有按钮id集合
        LambdaQueryWrapper<SysMenuButton> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(SysMenuButton::getButtonId, SysMenuButton::getButtonCode);
        wrapper.eq(SysMenuButton::getDelFlag, YesOrNotEnum.N.getCode());
        wrapper.in(SysMenuButton::getMenuId, totalMenuIdList);
 
        List<SysMenuButton> list = this.sysMenuButtonService.list(wrapper);
 
        ArrayList<SysMenuButtonDTO> menuButtonDTOS = new ArrayList<>();
        for (SysMenuButton sysMenuButton : list) {
            SysMenuButtonDTO sysMenuButtonDTO = new SysMenuButtonDTO();
            sysMenuButtonDTO.setButtonId(sysMenuButton.getButtonId());
            sysMenuButtonDTO.setButtonCode(sysMenuButton.getButtonCode());
            menuButtonDTOS.add(sysMenuButtonDTO);
        }
        return menuButtonDTOS;
    }
 
    @Override
    public AntdvFrontTypeEnum getUserMenuType(List<Long> menuIds) {
 
        // 用户没有菜单,默认只返回前台菜单类型
        if (ObjectUtil.isEmpty(menuIds)) {
            return AntdvFrontTypeEnum.FRONT;
        }
 
        // 判断菜单中有多少种类的菜单
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(SysMenu::getAntdvFrontType);
        queryWrapper.in(SysMenu::getMenuId, menuIds);
        List<SysMenu> sysMenuList = this.list(queryWrapper);
 
        // 获取各类菜单的数量
        long frontTypes = sysMenuList.stream().filter(sysMenu -> AntdvFrontTypeEnum.FRONT.getCode().equals(sysMenu.getAntdvFrontType())).count();
        long backendTypes = sysMenuList.stream().filter(sysMenu -> AntdvFrontTypeEnum.BACKEND.getCode().equals(sysMenu.getAntdvFrontType())).count();
 
        if (frontTypes > 0 && backendTypes > 0) {
            return AntdvFrontTypeEnum.TOTAL_SHOW;
        } else if (frontTypes > 0) {
            return AntdvFrontTypeEnum.FRONT;
        } else if (backendTypes > 0) {
            return AntdvFrontTypeEnum.BACKEND;
        }
 
        return AntdvFrontTypeEnum.FRONT;
    }
 
    @Override
    public List<SysMenu> getCurrentUserMenus(List<String> appCodeList, Boolean layuiVisibleFlag, Integer antdvFrontType) {
 
        // 菜单查询条件
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysMenu::getStatusFlag, StatusEnum.ENABLE.getCode()).eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode()).orderByAsc(SysMenu::getMenuSort);
 
        // 如果应用编码不为空,则拼接应用编码
        if (ObjectUtil.isNotEmpty(appCodeList)) {
            queryWrapper.in(SysMenu::getAppCode, appCodeList);
        }
 
        // 判断前台还是后台菜单
        if (ObjectUtil.isNotEmpty(antdvFrontType)) {
            queryWrapper.in(SysMenu::getAntdvFrontType, ListUtil.list(true, antdvFrontType, AntdvFrontTypeEnum.TOTAL_SHOW.getCode()));
        }
 
        // 如果是不分离版本,则筛选一下不需要显示的菜单
        if (layuiVisibleFlag != null && layuiVisibleFlag) {
            queryWrapper.eq(SysMenu::getLayuiVisible, YesOrNotEnum.Y.getCode());
        }
 
        // 如果是超级管理员,则获取所有的菜单
        if (LoginContext.me().getSuperAdminFlag()) {
            return this.list(queryWrapper);
        }
 
        // 非超级管理员,获取当前用户所有的菜单id
        List<Long> menuIdList = getCurrentUserMenuIds();
        if (menuIdList.isEmpty()) {
            return new ArrayList<>();
        }
        queryWrapper.in(SysMenu::getMenuId, menuIdList);
 
        return this.list(queryWrapper);
    }
 
    @Override
    public boolean hasMenu(String appCode) {
        SysMenuRequest sysMenuRequest = new SysMenuRequest();
        sysMenuRequest.setAppCode(appCode);
        LambdaQueryWrapper<SysMenu> wrapper = this.createWrapper(sysMenuRequest);
 
        List<SysMenu> list = this.list(wrapper);
        return !list.isEmpty();
    }
 
    @Override
    public List<String> getUserAppCodeList() {
 
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(SysMenu::getAppCode);
        queryWrapper.groupBy(SysMenu::getAppCode);
 
        // 非超级管理员获取自己的菜单
        if (!LoginContext.me().getSuperAdminFlag()) {
            List<Long> currentUserMenuIds = this.getCurrentUserMenuIds();
            queryWrapper.in(SysMenu::getMenuId, currentUserMenuIds);
        }
 
        List<SysMenu> list = this.list(queryWrapper);
        return list.stream().map(SysMenu::getAppCode).collect(Collectors.toList());
    }
 
    @Override
    public Set<Long> getMenuAllParentMenuId(Set<Long> menuIds) {
        Set<Long> parentMenuIds = new HashSet<>();
 
        // 查询所有菜单信息
        List<SysMenu> sysMenus = this.listByIds(menuIds);
        if (ObjectUtil.isEmpty(sysMenus)) {
            return parentMenuIds;
        }
 
        // 获取所有父菜单ID
        for (SysMenu sysMenu : sysMenus) {
            String menuPids = sysMenu.getMenuPids().replaceAll("\\[", "").replaceAll("\\]", "");
            String[] ids = menuPids.split(SymbolConstant.COMMA);
            for (String id : ids) {
                parentMenuIds.add(Long.parseLong(id));
            }
        }
 
        return parentMenuIds;
    }
 
    @Override
    public String getMenuButtonCodeByButtonId(Long buttonId) {
        SysMenuButton sysMenuButton = this.sysMenuButtonService.getById(buttonId);
        if (sysMenuButton != null) {
            return sysMenuButton.getButtonCode();
        } else {
            return "";
        }
    }
 
    @Override
    public List<String> getResourceCodesByBusinessId(List<Long> businessIds) {
        if (ObjectUtil.isEmpty(businessIds)) {
            return new ArrayList<>();
        }
 
        LambdaQueryWrapper<SysMenuResource> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(SysMenuResource::getBusinessId, businessIds);
        wrapper.select(SysMenuResource::getResourceCode);
        List<SysMenuResource> list = sysMenuResourceService.list(wrapper);
 
        return list.stream().map(SysMenuResource::getResourceCode).collect(Collectors.toList());
    }
 
    @Override
    public List<IndexMenuInfo> buildAuthorities(Integer menuFrontType, Boolean devopsFlag) {
 
        // 不分离应用查询菜单
        List<SysAppResult> sortedApps = appServiceApi.getSortedApps(devopsFlag);
        List<String> appCodes = sortedApps.stream().map(SysAppResult::getAppCode).collect(Collectors.toList());
        List<SysMenu> currentUserMenus = this.getCurrentUserMenus(appCodes, false, menuFrontType);
 
        // 获取当前激活的应用
        List<String> appNames = sortedApps.stream().map(SysAppResult::getAppName).collect(Collectors.toList());
 
        // 将菜单按应用编码分类,激活的应用放在最前边
        Map<String, List<SysMenu>> sortedUserMenus = AntdMenusFactory.sortUserMenusByAppCode(currentUserMenus);
 
        return Antdv3MenusFactory.createTotalMenus(sortedUserMenus, appNames);
    }
 
    /**
     * 获取系统菜单
     *
     * @author fengshuonan
     * @date 2020/3/27 9:13
     */
    private SysMenu querySysMenu(SysMenuRequest sysMenuRequest) {
        SysMenu sysMenu = this.getById(sysMenuRequest.getMenuId());
        if (ObjectUtil.isNull(sysMenu) || YesOrNotEnum.Y.getCode().equals(sysMenu.getDelFlag())) {
            throw new SystemModularException(SysMenuExceptionEnum.MENU_NOT_EXIST, sysMenuRequest.getMenuId());
        }
        return sysMenu;
    }
 
    /**
     * 创建pids的值
     * <p>
     * 如果pid是0顶级节点,pids就是 [-1],
     * <p>
     * 如果pid不是顶级节点,pids就是父菜单的pids + [pid] + ,
     *
     * @author fengshuonan, stylefeng
     * @date 2020/3/26 11:28
     */
    private String createPids(Long pid) {
        if (pid.equals(TreeConstants.DEFAULT_PARENT_ID)) {
            return SymbolConstant.LEFT_SQUARE_BRACKETS + TreeConstants.DEFAULT_PARENT_ID + SymbolConstant.RIGHT_SQUARE_BRACKETS + SymbolConstant.COMMA;
        } else {
            //获取父菜单
            SysMenuRequest sysMenuRequest = new SysMenuRequest();
            sysMenuRequest.setMenuId(pid);
            SysMenu parentMenu = this.querySysMenu(sysMenuRequest);
 
            // 组装pids
            return parentMenu.getMenuPids() + SymbolConstant.LEFT_SQUARE_BRACKETS + pid + SymbolConstant.RIGHT_SQUARE_BRACKETS + SymbolConstant.COMMA;
        }
    }
 
    /**
     * 创建查询条件wrapper
     *
     * @author fengshuonan
     * @date 2020/11/6 10:16
     */
    private LambdaQueryWrapper<SysMenu> createWrapper(SysMenuRequest sysMenuRequest) {
        LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
 
        // 查询未删除状态的
        queryWrapper.eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode());
 
        // 根据排序升序排列,序号越小越在前
        queryWrapper.orderByAsc(SysMenu::getAppCode);
        queryWrapper.orderByAsc(SysMenu::getMenuSort);
 
        if (ObjectUtil.isEmpty(sysMenuRequest)) {
            return queryWrapper;
        }
 
        // 根据应用查询
        if (ObjectUtil.isNotEmpty(sysMenuRequest.getAppCode())) {
            queryWrapper.eq(SysMenu::getAppCode, sysMenuRequest.getAppCode());
        }
 
        // 根据菜单名称模糊查询
        if (ObjectUtil.isNotEmpty(sysMenuRequest.getMenuName())) {
            queryWrapper.like(SysMenu::getMenuName, sysMenuRequest.getMenuName());
        }
 
        // 根据菜单编码模糊查询
        if (ObjectUtil.isNotEmpty(sysMenuRequest.getMenuCode())) {
            queryWrapper.like(SysMenu::getMenuCode, sysMenuRequest.getMenuCode());
        }
 
        return queryWrapper;
    }
 
    /**
     * 获取当前用户的菜单id集合
     *
     * @author fengshuonan
     * @date 2020/11/22 23:15
     */
    private List<Long> getCurrentUserMenuIds() {
 
        // 获取当前用户的角色id集合
        LoginUser loginUser = LoginContext.me().getLoginUser();
        List<Long> roleIdList = loginUser.getSimpleRoleInfoList().stream().map(SimpleRoleInfo::getRoleId).collect(Collectors.toList());
 
        // 当前用户角色为空,则没菜单
        if (ObjectUtil.isEmpty(roleIdList)) {
            return CollectionUtil.newArrayList();
        }
 
        // 获取角色拥有的菜单id集合
        List<Long> menuIdList = roleServiceApi.getMenuIdsByRoleIds(roleIdList);
        if (ObjectUtil.isEmpty(menuIdList)) {
            return CollectionUtil.newArrayList();
        }
 
        return menuIdList;
    }
 
    /**
     * 更新子节点以及子节点的子节点的appCode和层级关系(pids)
     *
     * @author fengshuonan
     * @date 2020/11/23 22:05
     */
    private String updateChildrenAppAndLevel(SysMenuRequest sysMenuRequest, SysMenu oldMenu) {
 
        // 本菜单旧的pids
        Long oldPid = oldMenu.getMenuParentId();
        String oldPids = oldMenu.getMenuPids();
 
        // 生成新的pid和pids
        Long newPid = sysMenuRequest.getMenuParentId();
        String newPids = this.createPids(sysMenuRequest.getMenuParentId());
 
        // 是否更新子应用的标识
        boolean updateSubAppsFlag = false;
 
        // 是否更新子节点的pids的标识
        boolean updateSubPidsFlag = false;
 
        // 如果应用有变化,不能把非一级菜单转移应用
        if (StrUtil.isNotEmpty(sysMenuRequest.getAppCode()) && !oldMenu.getAppCode().equals(sysMenuRequest.getAppCode())) {
            if (!oldPid.equals(TreeConstants.DEFAULT_PARENT_ID)) {
                throw new ServiceException(SysMenuExceptionEnum.CANT_MOVE_APP);
            }
            updateSubAppsFlag = true;
        }
 
        // 父节点有变化
        if (!newPid.equals(oldPid)) {
            updateSubPidsFlag = true;
        }
 
        // 开始更新所有子节点的配置
        if (updateSubAppsFlag || updateSubPidsFlag) {
 
            // 查找所有叶子节点,包含子节点的子节点
            LambdaQueryWrapper<SysMenu> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.like(SysMenu::getMenuPids, oldMenu.getMenuId());
            List<SysMenu> list = this.list(queryWrapper);
 
            // 更新所有子节点的应用为当前菜单的应用
            if (ObjectUtil.isNotEmpty(list)) {
 
                // 更新所有子节点的application
                if (updateSubAppsFlag) {
                    list.forEach(child -> child.setAppCode(sysMenuRequest.getAppCode()));
                }
 
                // 更新所有子节点的pids
                if (updateSubPidsFlag) {
                    list.forEach(child -> {
                        // 子节点pids组成 = 当前菜单新pids + 当前菜单id + 子节点自己的pids后缀
                        String oldParentCodesPrefix = oldPids + SymbolConstant.LEFT_SQUARE_BRACKETS + oldMenu.getMenuId() + SymbolConstant.RIGHT_SQUARE_BRACKETS + SymbolConstant.COMMA;
                        String oldParentCodesSuffix = child.getMenuPids().substring(oldParentCodesPrefix.length());
                        String menuParentCodes =
                                newPids + SymbolConstant.LEFT_SQUARE_BRACKETS + oldMenu.getMenuId() + SymbolConstant.RIGHT_SQUARE_BRACKETS + SymbolConstant.COMMA + oldParentCodesSuffix;
                        child.setMenuPids(menuParentCodes);
                    });
                }
 
                this.updateBatchById(list);
            }
        }
        return newPids;
    }
 
    /**
     * 获取所有的菜单,以一级菜单的形式展示
     *
     * @param antdvFrontType 菜单是前台显示还是后台显示
     * @author fengshuonan
     * @date 2022/9/28 17:46
     */
    private List<SysMenu> totalMenusWithOneLevel(Integer antdvFrontType) {
        // 查询所有菜单列表,根据前台传递参数,可选择前台还是后台菜单
        LambdaQueryWrapper<SysMenu> menuWrapper = new LambdaQueryWrapper<>();
        menuWrapper.eq(SysMenu::getDelFlag, YesOrNotEnum.N.getCode());
        menuWrapper.eq(SysMenu::getStatusFlag, StatusEnum.ENABLE.getCode());
        menuWrapper.orderByAsc(SysMenu::getMenuSort);
        // 查询所有指定类型的菜单
        if (antdvFrontType != null) {
            menuWrapper.nested(i -> i.eq(SysMenu::getAntdvFrontType, antdvFrontType).or().eq(SysMenu::getAntdvFrontType, AntdvFrontTypeEnum.TOTAL_SHOW.getCode()));
        }
 
        List<SysMenu> sysMenuList = this.list(menuWrapper);
 
        // 将所有节点转化成树结构,整体只要两级结构,一级是一级菜单,第二级是所有以下菜单
        Map<Long, SysMenu> firstLevelMenus = new LinkedHashMap<>();
 
        // 找到所有第一级的菜单
        for (SysMenu sysMenu : sysMenuList) {
            if (TreeConstants.DEFAULT_PARENT_ID.equals(sysMenu.getMenuParentId())) {
                firstLevelMenus.put(sysMenu.getMenuId(), sysMenu);
            }
        }
 
        // 找到所有二级和以下菜单,并添加到一级菜单以下
        for (Map.Entry<Long, SysMenu> menuEntry : firstLevelMenus.entrySet()) {
            SysMenu firstLevelMenuItem = menuEntry.getValue();
            List<SysMenu> children = firstLevelMenuItem.getChildren();
            if (children == null) {
                children = new ArrayList<>();
                firstLevelMenuItem.setChildren(children);
            }
            for (SysMenu sysMenu : sysMenuList) {
                if (sysMenu.getMenuPids().contains("[" + firstLevelMenuItem.getMenuId() + "]")) {
                    children.add(sysMenu);
                }
            }
        }
 
        return ListUtil.toList(firstLevelMenus.values());
    }
 
}