DashboardScopeHelper.cs 5.38 KB
using FoodLabeling.Application.Services.DbModels;
using FoodLabeling.Domain.Entities;
using SqlSugar;
using Volo.Abp.Users;
using Yi.Framework.Rbac.Domain.Entities;
using Yi.Framework.Rbac.Domain.Shared.Consts;
using Yi.Framework.SqlSugarCore.Abstractions;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// Dashboard 数据范围:管理员看全平台(用户指标排除内置系统 admin);非管理员仅看绑定门店所属公司范围。
/// </summary>
public static class DashboardScopeHelper
{
    /// <summary>
    /// 解析 Dashboard 统计适用的门店 Id 集合。
    /// <c>null</c> 表示不限制门店(系统管理员);空列表表示无可见范围。
    /// </summary>
    public static Task<List<string>?> ResolveDashboardLocationIdsAsync(
        ICurrentUser currentUser,
        ISqlSugarDbContext dbContext) =>
        TeamMemberListScopeHelper.ResolveListLocationIdsAsync(currentUser, dbContext, null, null, null);

    /// <summary>
    /// 平台系统管理员用户 Id(不计入 People / Active Users,也不视为某公司成员)。
    /// 含内置用户名 <see cref="UserConst.Admin"/> 及绑定角色码 <see cref="UserConst.AdminRolesCode"/> 的账号。
    /// </summary>
    public static async Task<HashSet<string>> GetPlatformAdminUserIdStringsAsync(ISqlSugarClient db)
    {
        var result = new HashSet<string>(StringComparer.Ordinal);

        var nameIds = await db.Queryable<UserAggregateRoot>()
            .Where(u => !u.IsDeleted && u.UserName == UserConst.Admin)
            .Select(u => u.Id)
            .ToListAsync();
        foreach (var id in nameIds)
        {
            result.Add(id.ToString());
        }

        var adminRoleIds = await db.Queryable<RoleAggregateRoot>()
            .Where(r => !r.IsDeleted && r.RoleCode == UserConst.AdminRolesCode)
            .Select(r => r.Id)
            .ToListAsync();
        if (adminRoleIds.Count > 0)
        {
            var roleUserIds = await db.Queryable<UserRoleEntity>()
                .Where(ur => adminRoleIds.Contains(ur.RoleId))
                .Select(ur => ur.UserId)
                .ToListAsync();
            foreach (var id in roleUserIds)
            {
                result.Add(id.ToString());
            }
        }

        return result;
    }

    /// <summary>
    /// 统计范围内成员数:须在 <c>userlocation</c> 中绑定范围内门店;排除平台系统 admin。
    /// </summary>
    public static async Task<int> CountScopedTeamMembersAsync(
        ISqlSugarClient db,
        List<string>? scopeLocationIds,
        HashSet<string> platformAdminUserIds,
        bool activeOnly,
        DateTime? createdBefore)
    {
        if (scopeLocationIds is { Count: 0 })
        {
            return 0;
        }

        var userLocQuery = db.Queryable<UserLocationDbEntity>()
            .Where(ul => !ul.IsDeleted);
        if (scopeLocationIds is not null)
        {
            userLocQuery = userLocQuery.Where(ul => scopeLocationIds.Contains(ul.LocationId));
        }

        var scopedUserIdStrings = await userLocQuery
            .Select(ul => ul.UserId)
            .Distinct()
            .ToListAsync();

        if (scopedUserIdStrings.Count == 0)
        {
            return 0;
        }

        var scopedUserIds = new List<Guid>();
        foreach (var s in scopedUserIdStrings)
        {
            if (platformAdminUserIds.Contains(s))
            {
                continue;
            }

            if (Guid.TryParse(s, out var gid) && gid != Guid.Empty)
            {
                scopedUserIds.Add(gid);
            }
        }

        if (scopedUserIds.Count == 0)
        {
            return 0;
        }

        var userQuery = db.Queryable<UserAggregateRoot>()
            .Where(u => !u.IsDeleted && scopedUserIds.Contains(u.Id));
        if (activeOnly)
        {
            userQuery = userQuery.Where(u => u.State);
        }

        if (createdBefore.HasValue)
        {
            userQuery = userQuery.Where(u => u.CreationTime < createdBefore.Value);
        }

        return await userQuery.CountAsync();
    }

    /// <summary>
    /// 统计范围内门店数。
    /// </summary>
    public static async Task<int> CountScopedLocationsAsync(
        ISqlSugarClient db,
        List<string>? scopeLocationIds,
        DateTime? createdBefore)
    {
        if (scopeLocationIds is { Count: 0 })
        {
            return 0;
        }

        var q = db.Queryable<LocationAggregateRoot>().Where(x => !x.IsDeleted);
        if (scopeLocationIds is not null)
        {
            q = q.Where(x => scopeLocationIds.Contains(SqlFunc.ToString(x.Id)));
        }

        if (createdBefore.HasValue)
        {
            q = q.Where(x => x.CreationTime < createdBefore.Value);
        }

        return await q.CountAsync();
    }

    /// <summary>
    /// 为打印任务查询附加门店范围(<c>scopeLocationIds == null</c> 不限制)。
    /// </summary>
    public static ISugarQueryable<FlLabelPrintTaskDbEntity> ApplyPrintTaskLocationScope(
        ISugarQueryable<FlLabelPrintTaskDbEntity> query,
        List<string>? scopeLocationIds)
    {
        if (scopeLocationIds is null)
        {
            return query;
        }

        if (scopeLocationIds.Count == 0)
        {
            return query.Where(_ => false);
        }

        return query.Where(t =>
            t.LocationId != null && scopeLocationIds.Contains(t.LocationId));
    }
}