OrganizeService.cs 11 KB
using NCC.Common.Entity;
using NCC.Extend.Entitys.Dto.Organize;
using NCC.Extend.Interfaces.Organize;
using NCC.System.Entitys.Permission;
using NCC.Dependency;
using NCC.DynamicApiController;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NCC.Extend
{
    /// <summary>
    /// 组织架构服务实现
    /// </summary>
    [ApiDescriptionSettings(Tag = "绿纤组织架构服务", Name = "Organize", Order = 201)]
    [Route("api/Extend/[controller]")]
    public class OrganizeService : IOrganizeService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarClient _db;

        /// <summary>
        /// 初始化组织架构服务
        /// </summary>
        /// <param name="db">数据库客户端</param>
        public OrganizeService(ISqlSugarClient db)
        {
            _db = db;
        }

        #region 组织架构查询

        /// <summary>
        /// 获取组织架构列表
        /// </summary>
        /// <param name="input">查询参数</param>
        /// <returns>组织架构列表</returns>
        [HttpGet("")]
        public async Task<dynamic> GetList([FromQuery] OrganizeListQueryInput input)
        {
            var query = _db.Queryable<OrganizeEntity>()
                .WhereIF(!string.IsNullOrEmpty(input.FullName), x => x.FullName.Contains(input.FullName))
                .WhereIF(!string.IsNullOrEmpty(input.EnCode), x => x.EnCode.Contains(input.EnCode))
                .WhereIF(!string.IsNullOrEmpty(input.Category), x => x.Category == input.Category)
                .WhereIF(!string.IsNullOrEmpty(input.ParentId), x => x.ParentId == input.ParentId)
                .WhereIF(input.EnabledMark.HasValue, x => x.EnabledMark == input.EnabledMark)
                .Where(x => x.DeleteMark == null)
                .OrderBy(x => x.SortCode, OrderByType.Asc)
                .OrderBy(x => x.CreatorTime, OrderByType.Desc);

            var total = await query.CountAsync();
            var list = await query
                .Select(x => new OrganizeListOutput
                {
                    Id = x.Id,
                    FullName = x.FullName,
                    EnCode = x.EnCode,
                    Category = x.Category,
                    ParentId = x.ParentId,
                    ManagerId = x.ManagerId,
                    Description = x.Description,
                    SortCode = x.SortCode,
                    EnabledMark = x.EnabledMark,
                    CreatorTime = x.CreatorTime
                })
                .ToPagedListAsync(input.currentPage, input.pageSize);

            // 获取父级组织名称和主管姓名
            var parentIds = list.list.Where(x => !string.IsNullOrEmpty(x.ParentId)).Select(x => x.ParentId).Distinct().ToList();
            var managerIds = list.list.Where(x => !string.IsNullOrEmpty(x.ManagerId)).Select(x => x.ManagerId).Distinct().ToList();

            var parentMap = new Dictionary<string, string>();
            var managerMap = new Dictionary<string, string>();

            if (parentIds.Any())
            {
                var parents = await _db.Queryable<OrganizeEntity>()
                    .Where(x => parentIds.Contains(x.Id))
                    .Select(x => new { x.Id, x.FullName })
                    .ToListAsync();
                parentMap = parents.ToDictionary(x => x.Id, x => x.FullName);
            }

            if (managerIds.Any())
            {
                var managers = await _db.Queryable<UserEntity>()
                    .Where(x => managerIds.Contains(x.Id))
                    .Select(x => new { x.Id, x.RealName })
                    .ToListAsync();
                managerMap = managers.ToDictionary(x => x.Id, x => x.RealName);
            }

            // 填充父级组织名称和主管姓名
            foreach (var item in list.list)
            {
                if (!string.IsNullOrEmpty(item.ParentId) && parentMap.ContainsKey(item.ParentId))
                {
                    item.ParentName = parentMap[item.ParentId];
                }

                if (!string.IsNullOrEmpty(item.ManagerId) && managerMap.ContainsKey(item.ManagerId))
                {
                    item.ManagerName = managerMap[item.ManagerId];
                }

                // 获取子组织数量
                item.ChildrenCount = await _db.Queryable<OrganizeEntity>()
                    .Where(x => x.ParentId == item.Id && x.DeleteMark == null)
                    .CountAsync();
            }

            return new { list = list.list, total };
        }

        /// <summary>
        /// 获取组织架构树形结构
        /// </summary>
        /// <param name="parentId">父级组织ID(可选)</param>
        /// <returns>组织架构树形结构</returns>
        [HttpGet("Tree")]
        public async Task<List<OrganizeTreeOutput>> GetTree([FromQuery] string parentId = null)
        {
            var query = _db.Queryable<OrganizeEntity>()
                .Where(x => x.DeleteMark == null)
                .WhereIF(!string.IsNullOrEmpty(parentId), x => x.ParentId == parentId)
                .WhereIF(string.IsNullOrEmpty(parentId), x => string.IsNullOrEmpty(x.ParentId))
                .OrderBy(x => x.SortCode, OrderByType.Asc)
                .OrderBy(x => x.CreatorTime, OrderByType.Desc);

            var list = await query
                .Select(x => new OrganizeTreeOutput
                {
                    Id = x.Id,
                    FullName = x.FullName,
                    EnCode = x.EnCode,
                    Category = x.Category,
                    ParentId = x.ParentId,
                    ManagerId = x.ManagerId,
                    Description = x.Description,
                    SortCode = x.SortCode,
                    EnabledMark = x.EnabledMark
                })
                .ToListAsync();


            // 构建树形结构
            return BuildTree(list, parentId);
        }

        /// <summary>
        /// 根据组织名称获取该机构下面的所有组织
        /// </summary>
        /// <param name="organizeName">组织名称</param>
        /// <returns>组织及其子组织列表</returns>
        [HttpGet("GetByName")]
        public async Task<dynamic> GetOrganizationsByName([FromQuery] string organizeName)
        {
            if (string.IsNullOrEmpty(organizeName))
            {
                throw new ArgumentException("组织名称不能为空", nameof(organizeName));
            }

            // 查找匹配的组织
            var matchedOrganizes = await _db.Queryable<OrganizeEntity>().Where(x => x.FullName == organizeName && x.DeleteMark == null).FirstAsync();
            if (matchedOrganizes == null)
            {
                throw new ArgumentException("未找到指定组织", nameof(organizeName));
            }
            var result = await _db.Queryable<OrganizeEntity>().Where(x => x.ParentId == matchedOrganizes.Id && x.DeleteMark == null).Select(x => new OrganizeTreeOutput
            {
                Id = x.Id,
                FullName = x.FullName,
                EnCode = x.EnCode,
                Category = x.Category,
            }).ToListAsync();
            return result;
        }

        /// <summary>
        /// 获取组织选择器数据
        /// </summary>
        /// <param name="parentId">父级组织ID(可选)</param>
        /// <returns>组织选择器数据</returns>
        [HttpGet("Selector")]
        public async Task<dynamic> GetSelector([FromQuery] string parentId = null)
        {
            var query = _db.Queryable<OrganizeEntity>()
                .Where(x => x.DeleteMark == null && x.EnabledMark == 1)
                .WhereIF(!string.IsNullOrEmpty(parentId), x => x.ParentId == parentId)
                .WhereIF(string.IsNullOrEmpty(parentId), x => string.IsNullOrEmpty(x.ParentId))
                .OrderBy(x => x.SortCode, OrderByType.Asc)
                .OrderBy(x => x.CreatorTime, OrderByType.Desc);

            var list = await query
                .Select(x => new
                {
                    id = x.Id,
                    fullName = x.FullName,
                    enCode = x.EnCode,
                    category = x.Category,
                    parentId = x.ParentId
                })
                .ToListAsync();

            return new { list };
        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 构建树形结构
        /// </summary>
        /// <param name="list">组织列表</param>
        /// <param name="parentId">父级ID</param>
        /// <returns>树形结构</returns>
        private List<OrganizeTreeOutput> BuildTree(List<OrganizeTreeOutput> list, string parentId)
        {
            var result = new List<OrganizeTreeOutput>();
            var parentIdValue = parentId ?? "";

            foreach (var item in list.Where(x => x.ParentId == parentIdValue))
            {
                var children = BuildTree(list, item.Id);
                item.Children = children;
                result.Add(item);
            }

            return result;
        }

        /// <summary>
        /// 获取所有子组织
        /// </summary>
        /// <param name="parentId">父级组织ID</param>
        /// <returns>子组织列表</returns>
        private async Task<List<OrganizeTreeOutput>> GetAllChildren(string parentId)
        {
            var children = await _db.Queryable<OrganizeEntity>()
                .Where(x => x.ParentId == parentId && x.DeleteMark == null)
                .Select(x => new OrganizeTreeOutput
                {
                    Id = x.Id,
                    FullName = x.FullName,
                    EnCode = x.EnCode,
                    Category = x.Category,
                    ParentId = x.ParentId,
                    ManagerId = x.ManagerId,
                    Description = x.Description,
                    SortCode = x.SortCode,
                    EnabledMark = x.EnabledMark
                })
                .ToListAsync();

            var allChildren = new List<OrganizeTreeOutput>(children);

            foreach (var child in children)
            {
                var grandChildren = await GetAllChildren(child.Id);
                allChildren.AddRange(grandChildren);
            }

            return allChildren;
        }

        #endregion
    }

    /// <summary>
    /// 组织比较器
    /// </summary>
    public class OrganizeComparer : IEqualityComparer<OrganizeTreeOutput>
    {
        /// <summary>
        /// 比较两个组织是否相等
        /// </summary>
        /// <param name="x">组织1</param>
        /// <param name="y">组织2</param>
        /// <returns>是否相等</returns>
        public bool Equals(OrganizeTreeOutput x, OrganizeTreeOutput y)
        {
            return x?.Id == y?.Id;
        }

        /// <summary>
        /// 获取组织的哈希码
        /// </summary>
        /// <param name="obj">组织对象</param>
        /// <returns>哈希码</returns>
        public int GetHashCode(OrganizeTreeOutput obj)
        {
            return obj?.Id?.GetHashCode() ?? 0;
        }
    }
}