ScopeAllEchoHelper.cs
8.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using SqlSugar;
namespace FoodLabeling.Application.Helpers;
/// <summary>
/// 编辑/列表回显:库中可存展开 Guid;若绑定覆盖全集则将 Id 数组折叠为 <c>["ALL"]</c> 哨兵(对齐 Team Member)。
/// </summary>
public static class ScopeAllEchoHelper
{
public sealed class ScopeAllEchoOptions
{
public bool IsPartnerAll { get; init; }
public bool IsRegionAll { get; init; }
public bool IsLocationAll { get; init; }
/// <summary>落库维度为 SPECIFIED 时禁止再按「恰好全选」折叠为 ALL 哨兵。</summary>
public string? AppliedPartnerType { get; init; }
public string? AppliedRegionType { get; init; }
public string? AppliedLocationType { get; init; }
}
/// <summary>
/// 将 partnerIds / regionIds / locationIds 折叠为 ALL 哨兵(编辑弹窗与列表 Id 数组回显)。
/// </summary>
public static async Task<(List<string> PartnerIds, List<string> RegionIds, List<string> LocationIds)>
CollapseScopeIdsToAllSentinelAsync(
ISqlSugarClient db,
IReadOnlyList<string>? partnerIds,
IReadOnlyList<string>? regionIds,
IReadOnlyList<string>? locationIds,
ScopeAllEchoOptions? options = null)
{
options ??= new ScopeAllEchoOptions();
var partners = LocationScopeBindingHelper.NormalizeIds(partnerIds);
var regions = LocationScopeBindingHelper.NormalizeIds(regionIds);
var locations = LocationScopeBindingHelper.NormalizeIds(locationIds);
if (options.IsPartnerAll)
{
partners = new List<string> { AllScopeBindingHelper.ScopeAll };
}
else if (!AllScopeBindingHelper.IsDeclaredSpecified(options.AppliedPartnerType) && partners.Count > 0)
{
var allPartners = await AllScopeBindingHelper.ResolveAllPartnerIdsAsync(db);
if (allPartners.Count > 0 && AllScopeBindingHelper.IsFullIdSelection(partners, allPartners))
{
partners = new List<string> { AllScopeBindingHelper.ScopeAll };
}
}
if (options.IsRegionAll)
{
regions = new List<string> { AllScopeBindingHelper.ScopeAll };
}
else if (!AllScopeBindingHelper.IsDeclaredSpecified(options.AppliedRegionType) && regions.Count > 0)
{
regions = await CollapseRegionsIfFullAsync(db, partners, regions);
}
if (options.IsLocationAll)
{
locations = new List<string> { AllScopeBindingHelper.ScopeAll };
}
else if (!AllScopeBindingHelper.IsDeclaredSpecified(options.AppliedLocationType) && locations.Count > 0)
{
locations = await CollapseLocationsIfFullAsync(db, partners, regions, locations);
}
return (partners, regions, locations);
}
/// <summary>AvailabilityType=ALL 时 Region 与 Location 均为 ALL。</summary>
public static ScopeAllEchoOptions ForAvailabilityAll(bool isAll) =>
new() { IsRegionAll = isAll, IsLocationAll = isAll };
/// <summary>LabelTemplate 各维度独立 ALL 标记。</summary>
public static ScopeAllEchoOptions ForLabelTemplateDimensions(
string? appliedPartnerType,
string? appliedRegionType,
string? appliedLocationType) =>
new()
{
IsPartnerAll = AllScopeBindingHelper.IsDeclaredAll(appliedPartnerType),
IsRegionAll = AllScopeBindingHelper.IsDeclaredAll(appliedRegionType),
IsLocationAll = AllScopeBindingHelper.IsDeclaredAll(appliedLocationType),
AppliedPartnerType = appliedPartnerType,
AppliedRegionType = appliedRegionType,
AppliedLocationType = appliedLocationType
};
/// <summary>标签类型/分类/多选项:Company + Region + Location 可用范围。</summary>
public static ScopeAllEchoOptions ForLabelEntityScope(
string? appliedPartnerType,
string? appliedRegionType,
string? availabilityType) =>
new()
{
IsPartnerAll = AllScopeBindingHelper.IsDeclaredAll(appliedPartnerType),
IsRegionAll = AllScopeBindingHelper.IsDeclaredAll(appliedRegionType),
IsLocationAll = AllScopeBindingHelper.IsDeclaredAll(availabilityType),
AppliedPartnerType = appliedPartnerType,
AppliedRegionType = appliedRegionType,
AppliedLocationType = availabilityType
};
/// <summary>兼容旧调用:无 Region 类型时用 AvailabilityType 同时驱动 Region/Location。</summary>
public static ScopeAllEchoOptions ForLabelEntityScope(
string? appliedPartnerType,
string? availabilityType) =>
ForLabelEntityScope(appliedPartnerType, availabilityType, availabilityType);
/// <summary>Label:AppliedRegionType=ALL 且未落门店快照时 Region/Location 均为 ALL。</summary>
public static ScopeAllEchoOptions ForLabelRegionScope(
string? appliedRegionType,
IReadOnlyList<string> locationIds)
{
var isRegionAll = AllScopeBindingHelper.IsDeclaredAll(appliedRegionType);
var normalizedLocations = LocationScopeBindingHelper.NormalizeIds(locationIds);
var isLocationAll = isRegionAll && normalizedLocations.Count == 0;
return new ScopeAllEchoOptions
{
IsRegionAll = isRegionAll,
IsLocationAll = isLocationAll,
AppliedRegionType = appliedRegionType,
AppliedLocationType = isLocationAll
? AllScopeBindingHelper.ScopeAll
: AllScopeBindingHelper.ScopeSpecified
};
}
private static async Task<List<string>> CollapseRegionsIfFullAsync(
ISqlSugarClient db,
IReadOnlyList<string> partners,
IReadOnlyList<string> regions)
{
var partnerContext = ResolvePartnerContextForCollapse(partners);
var allRegionIds = partnerContext is { Count: > 0 }
? await LocationScopeBindingHelper.ResolveGroupIdsFromPartnerIdsAsync(db, partnerContext)
: await AllScopeBindingHelper.ResolveAllRegionIdsAsync(db, null);
if (allRegionIds.Count > 0 && AllScopeBindingHelper.IsFullIdSelection(regions, allRegionIds))
{
return new List<string> { AllScopeBindingHelper.ScopeAll };
}
return regions.ToList();
}
private static async Task<List<string>> CollapseLocationsIfFullAsync(
ISqlSugarClient db,
IReadOnlyList<string> partners,
IReadOnlyList<string> regions,
IReadOnlyList<string> locations)
{
var partnerContext = ResolvePartnerContextForCollapse(partners);
List<string> allLocationIds;
if (regions.Count == 1 && AllScopeBindingHelper.IsDeclaredAll(regions[0]))
{
allLocationIds = partnerContext is { Count: > 0 }
? await LocationScopeBindingHelper.ResolveLocationIdsFromPartnerIdsAsync(db, partnerContext)
: await AllScopeBindingHelper.ResolveAllLocationIdsAsync(db, null, null);
}
else if (regions.Count > 0 && !regions.Any(r => AllScopeBindingHelper.IsDeclaredAll(r)))
{
allLocationIds = await AllScopeBindingHelper.ResolveAllLocationIdsAsync(db, partnerContext, regions);
}
else if (partnerContext is { Count: > 0 })
{
allLocationIds = await LocationScopeBindingHelper.ResolveLocationIdsFromPartnerIdsAsync(db, partnerContext);
}
else
{
allLocationIds = await AllScopeBindingHelper.ResolveAllLocationIdsAsync(db, null, null);
}
if (allLocationIds.Count > 0 && AllScopeBindingHelper.IsFullIdSelection(locations, allLocationIds))
{
// 具体 Region:覆盖该区全部门店时一律回显 ["ALL"](含区内仅 1 店;前端 ALL 常展开为具体 Guid)
var hasConcreteRegions = regions.Count > 0
&& !regions.Any(AllScopeBindingHelper.IsDeclaredAll);
if (hasConcreteRegions)
{
return new List<string> { AllScopeBindingHelper.ScopeAll };
}
// Region=ALL(或无具体 Region)时:仅多店才折叠,避免「Region=ALL + 选 1 店」误成 Location ALL
if (locations.Count > 1 || allLocationIds.Count > 1)
{
return new List<string> { AllScopeBindingHelper.ScopeAll };
}
}
return locations.ToList();
}
private static List<string>? ResolvePartnerContextForCollapse(IReadOnlyList<string> partners)
{
if (partners.Count == 0 || AllScopeBindingHelper.IsDeclaredAll(partners[0]))
{
return null;
}
return partners.ToList();
}
}