LocationRegionScopeHelper.cs 2.97 KB
using FoodLabeling.Application.Services.DbModels;
using FoodLabeling.Domain.Entities;
using SqlSugar;
using Volo.Abp.Users;
using Yi.Framework.SqlSugarCore.Abstractions;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// 门店列表数据范围:管理员可见全部;非管理员仅可见其 <c>userlocation</c> 绑定门店所属 Region
///(<c>location.Partner</c> + <c>location.GroupName</c>,与 <c>fl_group</c> 一致)。
/// </summary>
public static class LocationRegionScopeHelper
{
    /// <summary>
    /// 门店列表 Token 范围解析结果。
    /// </summary>
    public sealed class LocationListScopeFilter
    {
        public bool IsUnrestricted { get; init; }

        public IReadOnlyList<(string Partner, string GroupName)> RegionKeys { get; init; } =
            Array.Empty<(string, string)>();
    }

    /// <summary>
    /// 解析当前用户可查询的 Region(公司 + 组织名)集合。
    /// </summary>
    public static async Task<LocationListScopeFilter> ResolveLocationListScopeAsync(
        ICurrentUser currentUser,
        ISqlSugarDbContext dbContext)
    {
        if (ReportsRoleHelper.IsAdminRole(currentUser))
        {
            return new LocationListScopeFilter { IsUnrestricted = true };
        }

        if (currentUser.Id is null)
        {
            return new LocationListScopeFilter();
        }

        var userId = currentUser.Id.Value.ToString();
        var rows = await dbContext.SqlSugarClient.Queryable<UserLocationDbEntity>()
            .InnerJoin<LocationAggregateRoot>((ul, loc) =>
                !loc.IsDeleted && ul.LocationId == loc.Id.ToString())
            .Where(ul => !ul.IsDeleted && ul.UserId == userId)
            .Select((ul, loc) => new { loc.Partner, loc.GroupName })
            .ToListAsync();

        var keys = rows
            .Where(x => !string.IsNullOrWhiteSpace(x.GroupName) && !string.IsNullOrWhiteSpace(x.Partner))
            .Select(x => (Partner: x.Partner!.Trim(), GroupName: x.GroupName!.Trim()))
            .Distinct()
            .ToList();

        return new LocationListScopeFilter { RegionKeys = keys };
    }

    /// <summary>
    /// 将 Region 范围应用到 <c>location</c> 查询(须在其它 Where 之前或之后均可,建议在 IsDeleted 之后)。
    /// </summary>
    public static ISugarQueryable<LocationAggregateRoot> ApplyLocationListScope(
        ISugarQueryable<LocationAggregateRoot> query,
        LocationListScopeFilter scope)
    {
        if (scope.IsUnrestricted)
        {
            return query;
        }

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

        var exp = Expressionable.Create<LocationAggregateRoot>();
        foreach (var key in scope.RegionKeys)
        {
            var partner = key.Partner;
            var groupName = key.GroupName;
            exp = exp.Or(x => x.Partner == partner && x.GroupName == groupName);
        }

        return query.Where(exp.ToExpression());
    }
}