TeamMemberScopeDisplayHelper.cs 10.3 KB
using FoodLabeling.Application.Contracts.Dtos.TeamMember;
using FoodLabeling.Domain.Shared;
using SqlSugar;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// Team Member 列表展示:适用全部 Region/Location 时返回 All Region / All Location。
/// </summary>
public static class TeamMemberScopeDisplayHelper
{
    public static List<TeamMemberAssignedLocationDto> AllLocationDisplay { get; } =
        new()
        {
            new TeamMemberAssignedLocationDto
            {
                LocationName = FoodLabelingDisplayConsts.AllLocation
            }
        };

    /// <summary>
    /// 列表/导出用:当成员绑定范围覆盖其 Company/Region 下全部门店时,折叠为 All Location。
    /// </summary>
    public static async Task<List<TeamMemberAssignedLocationDto>> FormatAssignedLocationsForListAsync(
        ISqlSugarClient db,
        Guid? roleId,
        IReadOnlyList<string> partnerIds,
        IReadOnlyList<string> regionIds,
        IReadOnlyList<TeamMemberAssignedLocationDto> assigned,
        string? appliedLocationType = null)
    {
        var assignedIds = assigned
            .Select(x => x.Id)
            .Where(x => !string.IsNullOrWhiteSpace(x))
            .Select(x => x.Trim())
            .Distinct(StringComparer.Ordinal)
            .ToList();

        if (AllScopeBindingHelper.IsDeclaredAll(appliedLocationType))
        {
            if (partnerIds.Count > 0)
            {
                var concreteRegions = LocationScopeBindingHelper.FilterConcreteScopeIds(regionIds);
                var universe = concreteRegions.Count > 0
                    ? await AllScopeBindingHelper.ResolveAllLocationIdsAsync(db, partnerIds, concreteRegions)
                    : await LocationScopeBindingHelper.ResolveLocationIdsFromPartnerIdsAsync(db, partnerIds);
                if (universe.Count > 0
                    && !AllScopeBindingHelper.IsFullIdSelection(assignedIds, universe))
                {
                    return assigned.ToList();
                }
            }

            return AllLocationDisplay;
        }

        if (assignedIds.Count == 0)
        {
            return assigned.ToList();
        }

        if (partnerIds.Count > 0)
        {
            // 有具体 Region 时按 Region 范围内全选判断;否则按 Company 全部门店
            var concreteRegions = LocationScopeBindingHelper.FilterConcreteScopeIds(regionIds);
            var universe = concreteRegions.Count > 0
                ? await AllScopeBindingHelper.ResolveAllLocationIdsAsync(db, partnerIds, concreteRegions)
                : await LocationScopeBindingHelper.ResolveLocationIdsFromPartnerIdsAsync(db, partnerIds);
            if (universe.Count > 0 &&
                AllScopeBindingHelper.IsFullIdSelection(assignedIds, universe))
            {
                return AllLocationDisplay;
            }
        }

        return assigned.ToList();
    }

    /// <summary>
    /// 列表/导出用:当 Region 覆盖 Company 下全部 Region 时,返回 All Region 展示文案。
    /// </summary>
    public static async Task<string> FormatRegionTextForListAsync(
        ISqlSugarClient db,
        IReadOnlyList<string> partnerIds,
        IReadOnlyList<string> regionIds,
        IReadOnlyDictionary<string, string> regionNameMap,
        string? appliedRegionType = null)
    {
        if (AllScopeBindingHelper.IsDeclaredAll(appliedRegionType)
            || (regionIds.Count == 1 && AllScopeBindingHelper.IsDeclaredAll(regionIds[0])))
        {
            return FoodLabelingDisplayConsts.AllRegion;
        }

        if (regionIds.Count == 0)
        {
            return FoodLabelingDisplayConsts.NotAvailable;
        }

        if (partnerIds.Count > 0)
        {
            var allRegions = await LocationScopeBindingHelper.ResolveGroupIdsFromPartnerIdsAsync(db, partnerIds);
            if (allRegions.Count > 0 && AllScopeBindingHelper.IsFullIdSelection(regionIds, allRegions))
            {
                return FoodLabelingDisplayConsts.AllRegion;
            }
        }

        return string.Join("; ",
            regionIds.Select(id =>
                regionNameMap.TryGetValue(id, out var name) && !string.IsNullOrWhiteSpace(name)
                    ? name
                    : id));
    }

    /// <summary>
    /// 编辑回显:库中存展开后的 Guid;结合 AppliedRegionType/AppliedLocationType 折叠为 <c>["ALL"]</c>。
    /// </summary>
    public static async Task<(List<string> RegionIds, List<string> LocationIds, List<TeamMemberAssignedLocationDto> Assigned)>
        CollapseScopeIdsToAllSentinelForEditAsync(
            ISqlSugarClient db,
            IReadOnlyList<string> partnerIds,
            IReadOnlyList<string> regionIds,
            IReadOnlyList<string> locationIds,
            IReadOnlyList<TeamMemberAssignedLocationDto> assigned,
            string? appliedRegionType = null,
            string? appliedLocationType = null)
    {
        var partners = LocationScopeBindingHelper.NormalizeIds(partnerIds);
        var regions = LocationScopeBindingHelper.NormalizeIds(regionIds);
        var locations = LocationScopeBindingHelper.NormalizeIds(locationIds);
        var assignedList = assigned?.ToList() ?? new List<TeamMemberAssignedLocationDto>();

        if (AllScopeBindingHelper.IsDeclaredAll(appliedRegionType))
        {
            regions = new List<string> { AllScopeBindingHelper.ScopeAll };
        }

        if (AllScopeBindingHelper.IsDeclaredAll(appliedLocationType))
        {
            // 误标 ALL 但库中仅为部分门店时,回显具体 Id(与新增传参对称)
            if (locations.Count > 0 && partners.Count > 0)
            {
                var scopedRegions = LocationScopeBindingHelper.FilterConcreteScopeIds(regions);
                var universe = scopedRegions.Count > 0
                    ? await AllScopeBindingHelper.ResolveAllLocationIdsAsync(db, partners, scopedRegions)
                    : await LocationScopeBindingHelper.ResolveLocationIdsFromPartnerIdsAsync(db, partners);
                if (!AllScopeBindingHelper.IsFullIdSelection(locations, universe))
                {
                    return (regions, locations, assignedList);
                }
            }

            locations = new List<string> { AllScopeBindingHelper.ScopeAll };
            assignedList = AllLocationDisplay;
            return (regions, locations, assignedList);
        }

        // 落库为 SPECIFIED(显式选店):禁止再按「区内恰好全选」折叠成 ALL
        if (AllScopeBindingHelper.IsDeclaredSpecified(appliedLocationType))
        {
            if (partners.Count == 0)
            {
                return (regions, locations, assignedList);
            }

            if (!AllScopeBindingHelper.IsDeclaredAll(appliedRegionType))
            {
                var allRegionIds = await LocationScopeBindingHelper.ResolveGroupIdsFromPartnerIdsAsync(db, partners);
                if (allRegionIds.Count > 0 && AllScopeBindingHelper.IsFullIdSelection(regions, allRegionIds))
                {
                    regions = new List<string> { AllScopeBindingHelper.ScopeAll };
                }
            }

            return (regions, locations, assignedList);
        }

        if (partners.Count == 0)
        {
            return (regions, locations, assignedList);
        }

        if (!AllScopeBindingHelper.IsDeclaredAll(appliedRegionType))
        {
            var allRegionIds = await LocationScopeBindingHelper.ResolveGroupIdsFromPartnerIdsAsync(db, partners);
            if (allRegionIds.Count > 0 && AllScopeBindingHelper.IsFullIdSelection(regions, allRegionIds))
            {
                regions = new List<string> { AllScopeBindingHelper.ScopeAll };
            }
        }

        // Region=ALL + 具体门店:禁止再按「派生单 Region 区内全选」把 Location 折成 ALL
        if (AllScopeBindingHelper.IsDeclaredAll(appliedRegionType)
            || (regions.Count == 1 && AllScopeBindingHelper.IsDeclaredAll(regions[0])))
        {
            var partnerUniverse = await LocationScopeBindingHelper.ResolveLocationIdsFromPartnerIdsAsync(
                db, partners);
            if (partnerUniverse.Count > 1
                && locations.Count > 1
                && AllScopeBindingHelper.IsFullIdSelection(locations, partnerUniverse))
            {
                locations = new List<string> { AllScopeBindingHelper.ScopeAll };
                assignedList = AllLocationDisplay;
            }

            return (regions, locations, assignedList);
        }

        // 具体 Region:按区内门店全集判断是否折叠 locationIds
        var concreteRegions = LocationScopeBindingHelper.FilterConcreteScopeIds(regions);
        var allLocationIds = concreteRegions.Count > 0
            ? await AllScopeBindingHelper.ResolveAllLocationIdsAsync(db, partners, concreteRegions)
            : await LocationScopeBindingHelper.ResolveLocationIdsFromPartnerIdsAsync(db, partners);
        if (allLocationIds.Count > 0 && AllScopeBindingHelper.IsFullIdSelection(locations, allLocationIds))
        {
            var hasConcreteRegions = concreteRegions.Count > 0;
            if (hasConcreteRegions || locations.Count > 1 || allLocationIds.Count > 1)
            {
                locations = new List<string> { AllScopeBindingHelper.ScopeAll };
                assignedList = AllLocationDisplay;
            }
        }

        return (regions, locations, assignedList);
    }

    public static string FormatLocationTextForList(IReadOnlyList<TeamMemberAssignedLocationDto> assigned)
    {
        if (assigned.Count == 0)
        {
            return FoodLabelingDisplayConsts.NotAvailable;
        }

        if (assigned.Count == 1 &&
            string.Equals(assigned[0].LocationName, FoodLabelingDisplayConsts.AllLocation, StringComparison.Ordinal) &&
            string.IsNullOrWhiteSpace(assigned[0].LocationCode))
        {
            return FoodLabelingDisplayConsts.AllLocation;
        }

        return string.Join("; ",
            assigned.Select(a =>
            {
                var code = a.LocationCode?.Trim() ?? string.Empty;
                var name = a.LocationName?.Trim() ?? string.Empty;
                if (!string.IsNullOrEmpty(code) && !string.IsNullOrEmpty(name))
                {
                    return $"{code} - {name}";
                }

                return !string.IsNullOrEmpty(name) ? name : code;
            }));
    }
}