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; /// /// App 打印日志 / 门店报表:门店绑定校验;同一门店下已绑定账号可查看该门店全部打印记录(不按 CreatedBy 过滤)。 /// public static class UsAppPrintLogScopeHelper { /// /// 管理员、Company Admin,或角色码/名含 partner(如 Partner Admin):可查看门店下全部打印记录。 /// public static async Task 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( @"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)); } /// /// 校验当前用户是否可访问指定门店(含 Company Admin 公司下全部门店)。 /// public static async Task EnsureUserBoundToLocationAsync( ICurrentUser currentUser, ISqlSugarClient db, string locationId) { await EnsureUserCanAccessLocationAsync(currentUser, db, locationId); } /// /// 校验是否可访问指定门店:平台管理员不校验;Company Admin 可访问绑定 Company 下任意门店;其它账号须 userlocation 绑定。 /// 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("当前账号未绑定该门店,无法查看"); } } /// /// 构建 App 门店打印任务查询(必选门店;可选仅当前用户)。 /// public static ISugarQueryable BuildLocationPrintTaskQuery( ISqlSugarClient db, string locationId, bool restrictToCreator, string currentUserIdStr) { var lid = locationId.Trim(); return db.Queryable() .LeftJoin((t, l) => t.LabelId == l.Id) .LeftJoin((t, l, p) => t.ProductId == p.Id) .LeftJoin((t, l, p, lt) => t.LabelTypeId == lt.Id) .LeftJoin((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> LoadOperatorNameMapAsync( ISqlSugarClient db, IEnumerable userIdStrings) { var map = new Dictionary(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(guids.Count); var inClause = new List(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( $""" 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 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); /// /// Label Report 聚合用(含分类 Join + 关键字筛选)。 /// public static ISugarQueryable BuildLocationPrintTaskReportQuery( ISqlSugarClient db, string locationId, bool restrictToCreator, string currentUserIdStr, string? keyword) { var lid = locationId.Trim(); var kw = keyword?.Trim(); return db.Queryable() .LeftJoin((t, l) => t.LabelId == l.Id) .LeftJoin((t, l, p) => t.ProductId == p.Id) .LeftJoin((t, l, p, lc) => l.LabelCategoryId == lc.Id) .LeftJoin((t, l, p, lc, pc) => p.CategoryId == pc.Id) .LeftJoin((t, l, p, lc, pc, lt) => t.LabelTypeId == lt.Id) .LeftJoin((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; } } }