一个关于多层级排序的问题

发布时间 2024-01-02 09:36:56作者: PasteSpider

比如我们在设计架构的时候,或者权限,菜单的时候一般有多层级的概念,这个时候要排序就有点困难了!这里引入另外一个字段,然后按照自己的层级进行排序!

        /// <summary>
        /// 添加一个权限列表
        ///</summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<RoleInfoDto> CreateItemAsync(RoleInfoAddDto input)
        {
            //做排重处理
            var find = _dbContext.RoleInfo.Where(x => x.Model == input.Model && x.Role == input.Role).Any();
            if (find)
            {
                throw new DataSupperException("已经存在这样的权限,无法重复添加");
            }
            var info = ObjectMapper.Map<RoleInfoAddDto, RoleInfo>(input);
            info.IsEnable = true;//添加自定义
            _dbContext.Add(info);

            info.SortStr = info.Sort.ToString().PadLeft(_persize, '0') + "0".PadLeft((_maxlevel - 1) * _persize, '0');

            await _dbContext.SaveChangesAsync();
            if (input.FatherId != 0)
            {
                var father = _dbContext.RoleInfo.Where(x => x.Id == input.FatherId).AsNoTracking().FirstOrDefault();
                if (father != null && father != default)
                {
                    info.FatherStr = $"{father.FatherStr}{info.Id},";
                    info.Level = (father.Level + 1);
                    info.FatherId = father.Id;
                    info.RootId = father.RootId != 0 ? father.RootId : father.Id;
                    BuildSortStr(info, father);
                }
                else
                {
                    input.FatherId = 0;
                }
            }
            if (input.FatherId == 0)
            {
                info.FatherStr = $"{info.Id},";
                info.RootId = info.Id;
            }
            await _dbContext.SaveChangesAsync();
            var backinfo = ObjectMapper.Map<RoleInfo, RoleInfoDto>(info);
            return backinfo;
        }

        /// <summary>
        /// 更新一个权限列表
        ///</summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<RoleInfoDto> UpdateItemAsync(RoleInfoUpdateDto input)
        {
            var find = _dbContext.RoleInfo.Where(x => x.Id != input.Id && x.Model == input.Model && x.Role == input.Role).Select(x => x.Id).FirstOrDefault();
            if (find != 0)
            {
                throw new DataSupperException($"数据重复,权限的模块和权限值的组合不能重复! {input.Model}-{input.Role}");
            }
            var info = await _dbContext.RoleInfo.Where(x => x.Id == input.Id).FirstOrDefaultAsync();
            if (info == null || info == default)
            {
                throw new DataSupperException("需要查询的信息不存在");
            }
            var old_father_str = info.FatherStr;
            var _chat_level = info.Level;
            ObjectMapper.Map<RoleInfoUpdateDto, RoleInfo>(input, info);
            if (info.FatherId != 0)
            {
                var father = _dbContext.RoleInfo.Where(x => x.Id == info.FatherId).AsNoTracking().FirstOrDefault();
                if (father != null && father != default)
                {
                    info.Level = father.Level + 1;
                    info.FatherStr = $"{father.FatherStr}{info.Id},";
                    info.RootId = father.RootId;
                    BuildSortStr(info, father);
                }
                else
                {
                    info.FatherId = 0;
                    info.FatherStr = $"{info.Id},";
                    info.Level = 0;
                    info.RootId = info.Id;
                    BuildSortStr(info, null);
                }
            }
            else
            {
                info.FatherId = 0;
                info.FatherStr = $"{info.Id},";
                info.Level = 0;
                info.RootId = info.Id;
                BuildSortStr(info, null);
            }
            _chat_level = _chat_level - (info.Level);
            if (old_father_str != info.FatherStr)
            {
                var suns = _dbContext.RoleInfo.Where(x => x.Id != info.Id && x.FatherStr.StartsWith(old_father_str)).ToList();
                if (suns != null && suns.Count > 0)
                {
                    foreach (var item in suns)
                    {
                        item.FatherStr = item.FatherStr.Replace(old_father_str, info.FatherStr);
                        item.Level = item.Level + _chat_level;
                        item.RootId = info.RootId;
                        BuildFootSortStr(item, info);
                    }
                }
            }
            var backinfo = ObjectMapper.Map<RoleInfo, RoleInfoDto>(info);
            await _dbContext.SaveChangesAsync();
            return backinfo;
        }

        /// <summary>
        /// 每层最大支持的排序位数 5表示00000
        /// </summary>
        private const int _persize = 3;
        /// <summary>
        /// 最大层级个数,从0开始 比如4就是 0 1 2 3
        /// </summary>
        private const int _maxlevel = 4;

        /// <summary>
        /// 基于父级和当前自己的排序信息,构建对应的排序字符串
        /// </summary>
        /// <param name="_info"></param>
        /// <param name="_father"></param>
        private void BuildSortStr(RoleInfo _info, RoleInfo _father)
        {
            if (_info.Level < _maxlevel)
            {
                if (_father == null)
                {
                    _info.SortStr = _info.Sort.ToString().PadLeft(_persize, '0') + "0".PadLeft(_persize * (_maxlevel - 1), '0');
                }
                else
                {
                    if (!string.IsNullOrEmpty(_father.SortStr))
                    {
                        _info.SortStr = _father.SortStr.Substring(0, (_father.Level + 1) * _persize) + _info.Sort.ToString().PadLeft(_persize, '0');
                        //补充尾巴
                        if (_info.Level < (_maxlevel - 1))
                        {
                            _info.SortStr += "0".PadLeft(_persize * (_maxlevel - 1 - _info.Level), '0');
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 上级或者祖籍变更的替换,自己之后的不变,中间层级也不变 
        /// </summary>
        /// <param name="_info"></param>
        /// <param name="_father">是自己的上级或者祖级</param>
        private void BuildFootSortStr(RoleInfo _info, RoleInfo _father)
        {
            var _old_sort_str = _info.SortStr;
            _info.SortStr = _father.SortStr.Substring(0, (_father.Level + 1) * _persize);
            _info.SortStr += _old_sort_str.Substring((_father.Level + 1) * _persize);
        }

按照代码的意思,就是创建类似000000000000这样的,每个level各自管控自己的,然后基于这个排序!