UsAppPrintLogScopeHelper.cs
8.34 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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
using FoodLabeling.Application.Services.DbModels;
using SqlSugar;
using Volo.Abp;
using Volo.Abp.Users;
using Yi.Framework.Rbac.Domain.Entities;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace FoodLabeling.Application.Helpers;
/// <summary>
/// App 打印日志 / 门店报表:门店绑定校验;同一门店下已绑定账号可查看该门店全部打印记录(不按 CreatedBy 过滤)。
/// </summary>
public static class UsAppPrintLogScopeHelper
{
/// <summary>
/// 管理员、Company Admin,或角色码/名含 <c>partner</c>(如 Partner Admin):可查看门店下全部打印记录。
/// </summary>
public static async Task<bool> CanViewAllPrintsAtLocationAsync(
ICurrentUser currentUser,
ISqlSugarClient db)
{
if (ReportsRoleHelper.IsAdminRole(currentUser))
{
return true;
}
if (currentUser.Id is null)
{
return false;
}
if (await TeamMemberRoleHelper.IsCompanyAdminUserAsync(db, currentUser))
{
return true;
}
var roleRows = await db.Ado.SqlQueryAsync<UserRoleRow>(
@"SELECT r.RoleCode, r.RoleName
FROM UserRole ur
INNER JOIN Role r ON ur.RoleId = r.Id
WHERE ur.UserId = @UserId AND r.IsDeleted = 0 AND r.State = 1",
new { UserId = currentUser.Id.Value });
return roleRows.Any(r =>
ContainsPartnerKeyword(r.RoleCode) || ContainsPartnerKeyword(r.RoleName));
}
/// <summary>
/// 校验当前用户是否可访问指定门店(含 Company Admin 公司下全部门店)。
/// </summary>
public static async Task EnsureUserBoundToLocationAsync(
ICurrentUser currentUser,
ISqlSugarClient db,
string locationId)
{
await EnsureUserCanAccessLocationAsync(currentUser, db, locationId);
}
/// <summary>
/// 校验是否可访问指定门店:平台管理员不校验;Company Admin 可访问绑定 Company 下任意门店;其它账号须 userlocation 绑定。
/// </summary>
public static async Task EnsureUserCanAccessLocationAsync(
ICurrentUser currentUser,
ISqlSugarClient db,
string locationId)
{
if (ReportsRoleHelper.IsAdminRole(currentUser))
{
return;
}
if (currentUser.Id is null)
{
throw new UserFriendlyException("用户未登录");
}
var lid = TeamMemberListScopeHelper.NormalizeScopeKey(locationId);
if (string.IsNullOrEmpty(lid))
{
throw new UserFriendlyException("门店参数无效");
}
var accessible = await LocationScopeBindingHelper.ResolveAppAccessibleLocationIdsForUserAsync(
db, currentUser.Id.Value, currentUser);
if (!accessible.Contains(lid, StringComparer.OrdinalIgnoreCase))
{
throw new UserFriendlyException("当前账号未绑定该门店,无法查看");
}
}
/// <summary>
/// 构建 App 门店打印任务查询(必选门店;可选仅当前用户)。
/// </summary>
public static ISugarQueryable<FlLabelPrintTaskDbEntity, FlLabelDbEntity, FlProductDbEntity, FlLabelTypeDbEntity,
FlLabelTemplateDbEntity>
BuildLocationPrintTaskQuery(
ISqlSugarClient db,
string locationId,
bool restrictToCreator,
string currentUserIdStr)
{
var lid = locationId.Trim();
return db.Queryable<FlLabelPrintTaskDbEntity>()
.LeftJoin<FlLabelDbEntity>((t, l) => t.LabelId == l.Id)
.LeftJoin<FlProductDbEntity>((t, l, p) => t.ProductId == p.Id)
.LeftJoin<FlLabelTypeDbEntity>((t, l, p, lt) => t.LabelTypeId == lt.Id)
.LeftJoin<FlLabelTemplateDbEntity>((t, l, p, lt, tpl) => t.TemplateId == tpl.Id)
.Where((t, l, p, lt, tpl) => t.LocationId == lid)
.WhereIF(restrictToCreator, (t, l, p, lt, tpl) => t.CreatedBy == currentUserIdStr);
}
public static async Task<Dictionary<string, string>> LoadOperatorNameMapAsync(
ISqlSugarClient db,
IEnumerable<string?> userIdStrings)
{
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
var guids = userIdStrings
.Where(x => !string.IsNullOrWhiteSpace(x))
.Select(x => TeamMemberListScopeHelper.NormalizeScopeKey(x!))
.Where(x => Guid.TryParse(x, out _))
.Select(Guid.Parse)
.Distinct()
.ToList();
if (guids.Count == 0)
{
return map;
}
var parameters = new List<SugarParameter>(guids.Count);
var inClause = new List<string>(guids.Count);
for (var i = 0; i < guids.Count; i++)
{
var paramName = $"@uid{i}";
inClause.Add(paramName);
parameters.Add(new SugarParameter(paramName, guids[i]));
}
var users = await db.Ado.SqlQueryAsync<OperatorUserRow>(
$"""
SELECT Id, UserName, Name, Nick
FROM User
WHERE IsDeleted = 0 AND Id IN ({string.Join(", ", inClause)})
""",
parameters);
foreach (var u in users)
{
var display = BuildOperatorDisplayName(u.Name, u.Nick, u.UserName);
map[TeamMemberListScopeHelper.UserKey(u.Id)] = display;
}
return map;
}
public static string ResolveOperatorName(IReadOnlyDictionary<string, string> map, string? createdBy)
{
if (string.IsNullOrWhiteSpace(createdBy))
{
return "无";
}
var key = TeamMemberListScopeHelper.NormalizeScopeKey(createdBy);
return map.TryGetValue(key, out var name) ? name : "无";
}
private static string BuildOperatorDisplayName(string? name, string? nick, string? userName)
{
if (!string.IsNullOrWhiteSpace(name))
{
return name.Trim();
}
if (!string.IsNullOrWhiteSpace(nick))
{
return nick.Trim();
}
var user = userName?.Trim();
return string.IsNullOrWhiteSpace(user) ? "无" : user;
}
private sealed class OperatorUserRow
{
public Guid Id { get; set; }
public string? UserName { get; set; }
public string? Name { get; set; }
public string? Nick { get; set; }
}
private static bool ContainsPartnerKeyword(string? value) =>
!string.IsNullOrWhiteSpace(value) &&
value.Trim().Contains("partner", StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Label Report 聚合用(含分类 Join + 关键字筛选)。
/// </summary>
public static ISugarQueryable<FlLabelPrintTaskDbEntity, FlLabelDbEntity, FlProductDbEntity,
FlLabelCategoryDbEntity, FlProductCategoryDbEntity, FlLabelTypeDbEntity, FlLabelTemplateDbEntity>
BuildLocationPrintTaskReportQuery(
ISqlSugarClient db,
string locationId,
bool restrictToCreator,
string currentUserIdStr,
string? keyword)
{
var lid = locationId.Trim();
var kw = keyword?.Trim();
return db.Queryable<FlLabelPrintTaskDbEntity>()
.LeftJoin<FlLabelDbEntity>((t, l) => t.LabelId == l.Id)
.LeftJoin<FlProductDbEntity>((t, l, p) => t.ProductId == p.Id)
.LeftJoin<FlLabelCategoryDbEntity>((t, l, p, lc) => l.LabelCategoryId == lc.Id)
.LeftJoin<FlProductCategoryDbEntity>((t, l, p, lc, pc) => p.CategoryId == pc.Id)
.LeftJoin<FlLabelTypeDbEntity>((t, l, p, lc, pc, lt) => t.LabelTypeId == lt.Id)
.LeftJoin<FlLabelTemplateDbEntity>((t, l, p, lc, pc, lt, tpl) => t.TemplateId == tpl.Id)
.Where((t, l, p, lc, pc, lt, tpl) => t.LocationId == lid)
.WhereIF(restrictToCreator, (t, l, p, lc, pc, lt, tpl) => t.CreatedBy == currentUserIdStr)
.WhereIF(!string.IsNullOrWhiteSpace(kw),
(t, l, p, lc, pc, lt, tpl) =>
(p.ProductName != null && p.ProductName.Contains(kw!)) ||
(lc.CategoryName != null && lc.CategoryName.Contains(kw!)) ||
(pc.CategoryName != null && pc.CategoryName.Contains(kw!)));
}
private sealed class UserRoleRow
{
public string? RoleCode { get; set; }
public string? RoleName { get; set; }
}
}