From 04a4c4559df225f2f499264a1ef47530f496be0f Mon Sep 17 00:00:00 2001 From: 李曜臣 Date: Tue, 14 Jul 2026 10:01:29 +0800 Subject: [PATCH] 2026-07-14 --- 泰额版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts | 16 +++++++++++++--- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs | 12 ++++-------- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs | 33 +++++++++------------------------ 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs | 27 ++++----------------------- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs | 30 +++++++++++++++++++++++++++--- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs | 46 ++++++++++++++++++---------------------------- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs | 48 ++++++++++++++++++++++++++++-------------------- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs | 23 +---------------------- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs | 23 +---------------------- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs | 30 ++++++++++++++++-------------- 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs | 15 +++++++++------ 美国版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts | 16 +++++++++++++--- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs | 12 ++++-------- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs | 33 +++++++++------------------------ 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs | 27 ++++----------------------- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs | 30 +++++++++++++++++++++++++++--- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs | 46 ++++++++++++++++++---------------------------- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs | 48 ++++++++++++++++++++++++++++-------------------- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs | 23 +---------------------- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs | 23 +---------------------- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs | 30 ++++++++++++++++-------------- 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs | 15 +++++++++------ 美国版/Food Labeling Management Platform/src/services/labelCategoryService.ts | 4 ++++ 29 files changed, 698 insertions(+), 348 deletions(-) create mode 100644 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs create mode 100644 泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs create mode 100644 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs create mode 100644 美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs diff --git a/泰额版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts b/泰额版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts index da000a3..fdda953 100644 --- a/泰额版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts +++ b/泰额版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts @@ -1,13 +1,23 @@ import type { UsAppMyProfileOutputDto } from '../services/usAppAuth' -/** 与后端 ReportsRoleHelper.IsAdminRole 对齐(App 管理员级联选店) */ +function isCompanyAdminProfile(profile: UsAppMyProfileOutputDto): boolean { + const code = (profile.primaryRoleCode ?? '').trim().toLowerCase() + if (code === 'companyadmin' || code.includes('partner')) return true + const display = (profile.roleDisplay ?? '').trim().toLowerCase() + if (!display) return false + if (display === 'company admin') return true + if (display.includes('partner admin')) return true + return false +} + +/** 平台管理员或 Company Admin(App 级联选店) */ export function isAppAdminUser(profile: UsAppMyProfileOutputDto | null | undefined): boolean { if (!profile) return false const code = (profile.primaryRoleCode ?? '').trim().toLowerCase() if (code === 'admin') return true const display = (profile.roleDisplay ?? '').trim().toLowerCase() - if (!display) return false + if (!display) return isCompanyAdminProfile(profile) if (display.includes('administrator')) return true if (display.includes('super admin')) return true - return false + return isCompanyAdminProfile(profile) } diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs index 4f08361..be7c640 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs @@ -277,14 +277,10 @@ public static class AuthScopeQueryHelper return; } - var lid = locationId.Trim(); - var userIdStr = currentUser.Id!.Value.ToString(); - var bound = await dbContext.SqlSugarClient.Queryable() - .AnyAsync(x => !x.IsDeleted && x.UserId == userIdStr && x.LocationId == lid); - if (!bound) - { - throw new UserFriendlyException("当前账号未绑定该门店,无法选择"); - } + await UsAppPrintLogScopeHelper.EnsureUserCanAccessLocationAsync( + currentUser, + dbContext.SqlSugarClient, + locationId); } private static async Task ResolveAndValidateSelectionAsync( diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs new file mode 100644 index 0000000..c53fee6 --- /dev/null +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs @@ -0,0 +1,67 @@ +using FoodLabeling.Domain.Shared; +using SqlSugar; + +namespace FoodLabeling.Application.Helpers; + +/// +/// 标签类型/分类/多选项等:列表 Region/Location 列展示(适用全部时分别为 All Region / All Location)。 +/// +public static class EntityLocationScopeDisplayHelper +{ + /// + /// 根据可用范围类型与已解析的 Region/Location Id、名称,生成列表展示文案。 + /// + public static async Task<(string Region, string Location)> BuildListDisplayAsync( + ISqlSugarClient db, + string? availabilityType, + IReadOnlyList regionIds, + IReadOnlyList locationIds, + IEnumerable regionNames, + IEnumerable locationNames, + IReadOnlyList? partnerIdsForContext) + { + if (AllScopeBindingHelper.IsDeclaredAll(availabilityType)) + { + return (AllScopeBindingHelper.AllRegionsDisplay, AllScopeBindingHelper.AllLocationsDisplay); + } + + var normRegionIds = LocationScopeBindingHelper.NormalizeIds(regionIds); + var normLocationIds = LocationScopeBindingHelper.NormalizeIds(locationIds); + var partnerContext = partnerIdsForContext is { Count: > 0 } ? partnerIdsForContext : null; + + var allRegionIds = await AllScopeBindingHelper.ResolveAllRegionIdsAsync(db, partnerContext); + var regionIsAll = normRegionIds.Count > 0 + && allRegionIds.Count > 0 + && AllScopeBindingHelper.IsFullIdSelection(normRegionIds, allRegionIds); + + var regionContextForLocations = regionIsAll ? null : normRegionIds.Count > 0 ? normRegionIds : null; + var allLocationIds = await AllScopeBindingHelper.ResolveAllLocationIdsAsync( + db, + partnerContext, + regionContextForLocations); + var locationIsAll = normLocationIds.Count > 0 + && allLocationIds.Count > 0 + && AllScopeBindingHelper.IsFullIdSelection(normLocationIds, allLocationIds); + + var regionDisplay = regionIsAll + ? AllScopeBindingHelper.AllRegionsDisplay + : JoinDistinctNames(regionNames); + + var locationDisplay = locationIsAll + ? AllScopeBindingHelper.AllLocationsDisplay + : JoinDistinctNames(locationNames); + + return (regionDisplay, locationDisplay); + } + + private static string JoinDistinctNames(IEnumerable names) + { + var ordered = names + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Select(x => x.Trim()) + .Distinct(StringComparer.OrdinalIgnoreCase) + .OrderBy(x => x, StringComparer.OrdinalIgnoreCase) + .ToList(); + return ordered.Count > 0 ? string.Join(", ", ordered) : FoodLabelingDisplayConsts.NotAvailable; + } +} diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs new file mode 100644 index 0000000..d8c8296 --- /dev/null +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs @@ -0,0 +1,88 @@ +using FoodLabeling.Application.Services.DbModels; +using SqlSugar; + +namespace FoodLabeling.Application.Helpers; + +/// +/// 标签类型/分类/多选项列表:非平台管理员仅可见其绑定 Company 范围内数据。 +/// +public static class LabelEntityListScopeHelper +{ + /// + /// 标签类型列表:按 Company + Region/Location 范围过滤(Company Admin 不可见 All Companies 数据)。 + /// + public static ISugarQueryable ApplyTypeLocationAvailabilityFilter( + ISugarQueryable query, + List? scopedLocationIds) + { + if (scopedLocationIds is null) + { + return query; + } + + if (scopedLocationIds.Count == 0) + { + return query.Where(_ => false); + } + + return query.Where(t => + (t.AvailabilityType == AllScopeBindingHelper.ScopeAll + && t.AppliedPartnerType == LabelEntityPartnerScopeHelper.ScopeSpecified) + || (t.AvailabilityType == AllScopeBindingHelper.ScopeSpecified + && SqlFunc.Subqueryable() + .Where(tl => tl.LabelTypeId == t.Id && scopedLocationIds.Contains(tl.LocationId)) + .Any())); + } + + /// + /// 标签分类列表:按 Company + Region/Location 范围过滤。 + /// + public static ISugarQueryable ApplyCategoryLocationAvailabilityFilter( + ISugarQueryable query, + List? scopedLocationIds) + { + if (scopedLocationIds is null) + { + return query; + } + + if (scopedLocationIds.Count == 0) + { + return query.Where(_ => false); + } + + return query.Where(c => + (c.AvailabilityType == AllScopeBindingHelper.ScopeAll + && c.AppliedPartnerType == LabelEntityPartnerScopeHelper.ScopeSpecified) + || (c.AvailabilityType == AllScopeBindingHelper.ScopeSpecified + && SqlFunc.Subqueryable() + .Where(cl => cl.CategoryId == c.Id && scopedLocationIds.Contains(cl.LocationId)) + .Any())); + } + + /// + /// 标签多选项列表:按 Company + Region/Location 范围过滤。 + /// + public static ISugarQueryable ApplyMultipleOptionLocationAvailabilityFilter( + ISugarQueryable query, + List? scopedLocationIds) + { + if (scopedLocationIds is null) + { + return query; + } + + if (scopedLocationIds.Count == 0) + { + return query.Where(_ => false); + } + + return query.Where(o => + (o.AvailabilityType == AllScopeBindingHelper.ScopeAll + && o.AppliedPartnerType == LabelEntityPartnerScopeHelper.ScopeSpecified) + || (o.AvailabilityType == AllScopeBindingHelper.ScopeSpecified + && SqlFunc.Subqueryable() + .Where(ol => ol.MultipleOptionId == o.Id && scopedLocationIds.Contains(ol.LocationId)) + .Any())); + } +} diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs index 57e580c..1bdbc25 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs @@ -348,17 +348,12 @@ public static class LabelEntityPartnerScopeHelper if (scopedPartnerIds.Count == 0) { - return query.Where(t => - !SqlFunc.Subqueryable() - .Where(p => p.LabelTypeId == t.Id) - .Any()); + return query.Where(_ => false); } return query.Where(t => - !SqlFunc.Subqueryable() - .Where(p => p.LabelTypeId == t.Id) - .Any() - || SqlFunc.Subqueryable() + t.AppliedPartnerType == ScopeSpecified + && SqlFunc.Subqueryable() .Where(p => p.LabelTypeId == t.Id && scopedPartnerIds.Contains(p.PartnerId)) .Any()); } @@ -384,17 +379,12 @@ public static class LabelEntityPartnerScopeHelper if (scopedPartnerIds.Count == 0) { - return query.Where(c => - !SqlFunc.Subqueryable() - .Where(p => p.CategoryId == c.Id) - .Any()); + return query.Where(_ => false); } return query.Where(c => - !SqlFunc.Subqueryable() - .Where(p => p.CategoryId == c.Id) - .Any() - || SqlFunc.Subqueryable() + c.AppliedPartnerType == ScopeSpecified + && SqlFunc.Subqueryable() .Where(p => p.CategoryId == c.Id && scopedPartnerIds.Contains(p.PartnerId)) .Any()); } @@ -420,17 +410,12 @@ public static class LabelEntityPartnerScopeHelper if (scopedPartnerIds.Count == 0) { - return query.Where(o => - !SqlFunc.Subqueryable() - .Where(p => p.MultipleOptionId == o.Id) - .Any()); + return query.Where(_ => false); } return query.Where(o => - !SqlFunc.Subqueryable() - .Where(p => p.MultipleOptionId == o.Id) - .Any() - || SqlFunc.Subqueryable() + o.AppliedPartnerType == ScopeSpecified + && SqlFunc.Subqueryable() .Where(p => p.MultipleOptionId == o.Id && scopedPartnerIds.Contains(p.PartnerId)) .Any()); } diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs index f7ae0ea..674a63b 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs @@ -437,23 +437,7 @@ public static class LabelTemplateScopeHelper if (scopedLocationIds.Count == 0) { - return hasExtendedScope - ? query.Where(t => - t.AppliedLocationType == ScopeAll - && !SqlFunc.Subqueryable() - .Where(l => l.TemplateId == t.Id) - .Any() - && !SqlFunc.Subqueryable() - .Where(p => p.TemplateId == t.Id) - .Any() - && !SqlFunc.Subqueryable() - .Where(r => r.TemplateId == t.Id) - .Any()) - : query.Where(t => - t.AppliedLocationType == ScopeAll - && !SqlFunc.Subqueryable() - .Where(l => l.TemplateId == t.Id) - .Any()); + return query.Where(_ => false); } if (!hasExtendedScope) @@ -470,12 +454,9 @@ public static class LabelTemplateScopeHelper db, scopedLocationIds); return query.Where(t => - (!SqlFunc.Subqueryable() - .Where(p => p.TemplateId == t.Id) - .Any() - || SqlFunc.Subqueryable() - .Where(p => p.TemplateId == t.Id && scopedPartnerIds.Contains(p.PartnerId)) - .Any()) + SqlFunc.Subqueryable() + .Where(p => p.TemplateId == t.Id && scopedPartnerIds.Contains(p.PartnerId)) + .Any() && (!SqlFunc.Subqueryable() .Where(r => r.TemplateId == t.Id) .Any() diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs index e9d0616..b0942ee 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs @@ -25,6 +25,7 @@ public static class LocationRegionScopeHelper /// /// 解析当前用户可查询的 Region(公司 + 组织名)集合。 + /// Company Admin 展开为绑定 Company 下全部 Region(与 一致)。 /// public static async Task ResolveLocationListScopeAsync( ICurrentUser currentUser, @@ -40,8 +41,15 @@ public static class LocationRegionScopeHelper return new LocationListScopeFilter(); } + var db = dbContext.SqlSugarClient; + + if (await TeamMemberRoleHelper.IsCompanyAdminUserAsync(db, currentUser)) + { + return await ResolveCompanyAdminLocationListScopeAsync(db, currentUser.Id.Value); + } + var userId = currentUser.Id.Value.ToString(); - var rows = await dbContext.SqlSugarClient.Queryable() + var rows = await db.Queryable() .InnerJoin((ul, loc) => !loc.IsDeleted && ul.LocationId == loc.Id.ToString()) .Where(ul => !ul.IsDeleted && ul.UserId == userId) @@ -57,6 +65,59 @@ public static class LocationRegionScopeHelper return new LocationListScopeFilter { RegionKeys = keys }; } + private static async Task ResolveCompanyAdminLocationListScopeAsync( + ISqlSugarClient db, + Guid userId) + { + var locationIds = await LocationScopeBindingHelper.ResolveBoundLocationIdsForUserAsync(db, userId); + if (locationIds.Count == 0) + { + return new LocationListScopeFilter(); + } + + var partnerIds = await LocationScopeBindingHelper.ResolvePartnerIdsFromLocationIdsAsync(db, locationIds); + if (partnerIds.Count == 0) + { + return new LocationListScopeFilter(); + } + + var partners = await db.Queryable() + .Where(p => !p.IsDeleted && partnerIds.Contains(p.Id)) + .Select(p => new { p.Id, p.PartnerName }) + .ToListAsync(); + + var groups = await db.Queryable() + .Where(g => !g.IsDeleted && partnerIds.Contains(g.PartnerId)) + .Select(g => new { g.PartnerId, g.GroupName }) + .ToListAsync(); + + var keys = new HashSet<(string Partner, string GroupName)>(); + foreach (var group in groups) + { + var groupName = group.GroupName?.Trim(); + if (string.IsNullOrEmpty(groupName)) + { + continue; + } + + var partner = partners.FirstOrDefault(p => + string.Equals(p.Id, group.PartnerId, StringComparison.OrdinalIgnoreCase)); + var partnerName = partner?.PartnerName?.Trim(); + if (!string.IsNullOrEmpty(partnerName)) + { + keys.Add((partnerName, groupName)); + } + + var partnerId = group.PartnerId?.Trim(); + if (!string.IsNullOrEmpty(partnerId)) + { + keys.Add((partnerId, groupName)); + } + } + + return new LocationListScopeFilter { RegionKeys = keys.ToList() }; + } + /// /// 将 Region 范围应用到 location 查询(须在其它 Where 之前或之后均可,建议在 IsDeleted 之后)。 /// diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs index 59661b7..f9f4c8c 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs @@ -19,7 +19,7 @@ public static class UsAppAuthScopeHelper { private const string CacheKeyPrefix = "FoodLabeling:UsAppAdminScope:"; - public static void EnsureAdminAppToken(ICurrentUser currentUser) + public static async Task EnsureAppScopeCallerAsync(ISqlSugarClient db, ICurrentUser currentUser) { if (currentUser.Id is null) { @@ -32,12 +32,30 @@ public static class UsAppAuthScopeHelper throw new UserFriendlyException("请使用 App 登录令牌调用该接口"); } - if (!ReportsRoleHelper.IsAdminRole(currentUser)) + if (!await CanUseAdminScopeApisAsync(db, currentUser)) { - throw new UserFriendlyException("仅管理员可使用公司/区域/门店筛选接口"); + throw new UserFriendlyException("仅管理员或 Company Admin 可使用公司/区域/门店筛选接口"); } } + /// + /// 平台管理员或 Company Admin 可使用 App 级联选店接口。 + /// + public static async Task CanUseAdminScopeApisAsync(ISqlSugarClient db, ICurrentUser currentUser) + { + if (currentUser.Id is null) + { + return false; + } + + if (ReportsRoleHelper.IsAdminRole(currentUser)) + { + return true; + } + + return await TeamMemberRoleHelper.IsCompanyAdminUserAsync(db, currentUser); + } + public static async Task> ListCompaniesAsync(ISqlSugarClient db) { return await db.Queryable() @@ -119,6 +137,7 @@ public static class UsAppAuthScopeHelper public static async Task SelectLocationAsync( ISqlSugarClient db, IDistributedCache cache, + ICurrentUser currentUser, Guid userId, UsAppSelectAdminScopeLocationInputVo input) { @@ -130,6 +149,11 @@ public static class UsAppAuthScopeHelper throw new UserFriendlyException("请选择公司、区域和门店"); } + if (!ReportsRoleHelper.IsAdminRole(currentUser)) + { + await UsAppPrintLogScopeHelper.EnsureUserCanAccessLocationAsync(currentUser, db, locationId); + } + var scopedIds = await LocationScopeBindingHelper.ResolveFilteredLocationIdsForListAsync( db, partnerId, diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs index cd4a368..d3adc88 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs @@ -62,38 +62,28 @@ public class LabelAppService : ApplicationService, ILabelAppService var db = _dbContext.SqlSugarClient; var regionSchema = await LabelRegionSchemaHelper.GetStatusAsync(db); - var scopedLocationIds = await LocationScopeBindingHelper.ResolveScopedLocationIdsAsync( - db, groupId, locationId); + var scopedLocationIds = await TeamMemberListScopeHelper.ResolveListLocationIdsAsync( + CurrentUser, + _dbContext, + partnerId, + groupId, + locationId); var filterGroupId = groupId?.Trim(); - if (!string.IsNullOrWhiteSpace(filterGroupId)) + if (scopedLocationIds is not null) { - labelIdsQuery = scopedLocationIds is { Count: 0 } - ? labelIdsQuery.Where(_ => false) - : LabelRegionScopeHelper.ApplyLabelRegionListFilter( + if (scopedLocationIds.Count == 0) + { + labelIdsQuery = labelIdsQuery.Where(_ => false); + } + else if (!string.IsNullOrWhiteSpace(filterGroupId)) + { + labelIdsQuery = LabelRegionScopeHelper.ApplyLabelRegionListFilter( db, labelIdsQuery, filterGroupId, scopedLocationIds, regionSchema); - } - else if (scopedLocationIds is not null) - { - labelIdsQuery = scopedLocationIds.Count == 0 - ? labelIdsQuery.Where(_ => false) - : LabelRegionScopeHelper.ApplyLabelLocationListFilter( - db, labelIdsQuery, scopedLocationIds, regionSchema); - } - else if (!string.IsNullOrWhiteSpace(groupId)) - { - labelIdsQuery = LabelRegionScopeHelper.ApplyGroupIdListFilter( - db, labelIdsQuery, groupId, regionSchema); - } - else if (!string.IsNullOrWhiteSpace(partnerId)) - { - var partnerLocationIds = await LocationScopeBindingHelper.ResolveFilteredLocationIdsForListAsync( - db, partnerId, null, null); - if (partnerLocationIds is not null) + } + else { - labelIdsQuery = partnerLocationIds.Count == 0 - ? labelIdsQuery.Where(_ => false) - : LabelRegionScopeHelper.ApplyLabelLocationListFilter( - db, labelIdsQuery, partnerLocationIds, regionSchema); + labelIdsQuery = LabelRegionScopeHelper.ApplyLabelLocationListFilter( + db, labelIdsQuery, scopedLocationIds, regionSchema); } } diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs index 9c9c71b..dd918a9 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs @@ -71,11 +71,11 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ var ids = entities.Select(x => x.Id).ToList(); var labelStatsMap = await BuildCategoryLabelStatsMapAsync(ids); - var scopeMap = await BuildCategoryScopeMapAsync(entities); var partnerScopeMap = await LabelEntityPartnerScopeHelper.BuildPartnerScopeDisplayMapAsync( _dbContext.SqlSugarClient, LabelEntityPartnerScopeHelper.LabelEntityPartnerKind.Category, ids); + var scopeMap = await BuildCategoryScopeMapAsync(entities, partnerScopeMap); var items = entities.Select(x => { @@ -370,16 +370,7 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ return query; } - if (scopedLocationIds.Count == 0) - { - return query.Where(c => c.AvailabilityType == "ALL"); - } - - return query.Where(c => - c.AvailabilityType == "ALL" || - SqlFunc.Subqueryable() - .Where(cl => cl.CategoryId == c.Id && scopedLocationIds.Contains(cl.LocationId)) - .Any()); + return LabelEntityListScopeHelper.ApplyCategoryLocationAvailabilityFilter(query, scopedLocationIds); } private async Task SaveCategoryPartnerScopeAsync( @@ -420,7 +411,8 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ private const string EmptyDisplay = FoodLabelingDisplayConsts.NotAvailable; private async Task> BuildCategoryScopeMapAsync( - List entities) + List entities, + Dictionary partnerScopeMap) { var result = new Dictionary(StringComparer.Ordinal); if (entities.Count == 0) @@ -428,8 +420,9 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ return result; } - foreach (var e in entities.Where(x => - !string.Equals(x.AvailabilityType, "SPECIFIED", StringComparison.OrdinalIgnoreCase))) + var entityById = entities.ToDictionary(x => x.Id, StringComparer.Ordinal); + + foreach (var e in entities.Where(x => AllScopeBindingHelper.IsDeclaredAll(x.AvailabilityType))) { result[e.Id] = new CategoryScopeData { @@ -525,14 +518,29 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ var regionIds = await LocationScopeBindingHelper.ResolveGroupIdsFromLocationIdsAsync( _dbContext.SqlSugarClient, locationIds); + entityById.TryGetValue(catId, out var entity); + partnerScopeMap.TryGetValue(catId, out var partnerScope); + var partnerContext = entity is not null + && string.Equals( + entity.AppliedPartnerType, + LabelEntityPartnerScopeHelper.ScopeSpecified, + StringComparison.OrdinalIgnoreCase) + ? partnerScope?.PartnerIds + : null; + + var (regionDisplay, locationDisplay) = await EntityLocationScopeDisplayHelper.BuildListDisplayAsync( + _dbContext.SqlSugarClient, + entity?.AvailabilityType, + regionIds, + locationIds, + regions, + locationNames, + partnerContext); + result[catId] = new CategoryScopeData { - Region = regions.Count > 0 - ? string.Join(", ", regions.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)) - : EmptyDisplay, - Location = locationNames.Count > 0 - ? string.Join(", ", locationNames.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)) - : EmptyDisplay, + Region = regionDisplay, + Location = locationDisplay, RegionIds = regionIds, LocationIds = locationIds }; diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs index 9f2e38e..67aa994 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs @@ -43,7 +43,7 @@ public class LabelMultipleOptionAppService : ApplicationService, ILabelMultipleO query = await LabelEntityPartnerScopeHelper.ApplyMultipleOptionPartnerListFilterAsync( _dbContext.SqlSugarClient, query, scopedPartnerIds); - query = ApplyMultipleOptionScopeFilter(query, scopedLocationIds); + query = LabelEntityListScopeHelper.ApplyMultipleOptionLocationAvailabilityFilter(query, scopedLocationIds); if (!string.IsNullOrWhiteSpace(input.Sorting)) { @@ -395,27 +395,6 @@ public class LabelMultipleOptionAppService : ApplicationService, ILabelMultipleO }; } - private static ISugarQueryable ApplyMultipleOptionScopeFilter( - ISugarQueryable query, - List? scopedLocationIds) - { - if (scopedLocationIds is null) - { - return query; - } - - if (scopedLocationIds.Count == 0) - { - return query.Where(o => o.AvailabilityType == "ALL"); - } - - return query.Where(o => - o.AvailabilityType == "ALL" || - SqlFunc.Subqueryable() - .Where(ol => ol.MultipleOptionId == o.Id && scopedLocationIds.Contains(ol.LocationId)) - .Any()); - } - private async Task> BuildMultipleOptionScopeMapAsync( List entities) { diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs index 1e96ce0..2a21745 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs @@ -43,7 +43,7 @@ public class LabelTypeAppService : ApplicationService, ILabelTypeAppService query = await LabelEntityPartnerScopeHelper.ApplyTypePartnerListFilterAsync( _dbContext.SqlSugarClient, query, scopedPartnerIds); - query = ApplyLabelTypeScopeFilter(query, scopedLocationIds); + query = LabelEntityListScopeHelper.ApplyTypeLocationAvailabilityFilter(query, scopedLocationIds); if (!string.IsNullOrWhiteSpace(input.Sorting)) { @@ -346,27 +346,6 @@ public class LabelTypeAppService : ApplicationService, ILabelTypeAppService return merged.OrderBy(x => x, StringComparer.Ordinal).ToList(); } - private static ISugarQueryable ApplyLabelTypeScopeFilter( - ISugarQueryable query, - List? scopedLocationIds) - { - if (scopedLocationIds is null) - { - return query; - } - - if (scopedLocationIds.Count == 0) - { - return query.Where(t => t.AvailabilityType == "ALL"); - } - - return query.Where(t => - t.AvailabilityType == "ALL" || - SqlFunc.Subqueryable() - .Where(tl => tl.LabelTypeId == t.Id && scopedLocationIds.Contains(tl.LocationId)) - .Any()); - } - private async Task SaveTypeLocationsAsync( string labelTypeId, string availabilityType, diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs index fe4aed5..0522fcb 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs @@ -170,7 +170,7 @@ public class UsAppAuthAppService : ApplicationService, IUsAppAuthAppService } var list = await LoadBoundLocationsAsync(CurrentUser.Id.Value); - if (ReportsRoleHelper.IsAdminRole(CurrentUser)) + if (await UsAppAuthScopeHelper.CanUseAdminScopeApisAsync(_dbContext.SqlSugarClient, CurrentUser)) { var cached = await UsAppAuthScopeHelper.GetAdminScopeCacheAsync( _distributedCache, @@ -189,39 +189,40 @@ public class UsAppAuthAppService : ApplicationService, IUsAppAuthAppService /// [Authorize] + [HttpGet("us-app-auth/admin-scope-companies")] public virtual async Task> GetAdminScopeCompaniesAsync() { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); - return await UsAppAuthScopeHelper.ListCompaniesAsync(_dbContext.SqlSugarClient); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); + return await AuthScopeQueryHelper.GetCompaniesAsync(CurrentUser, _dbContext); } /// [Authorize] - public virtual async Task> GetAdminScopeRegionsAsync(string partnerId) + [HttpGet("us-app-auth/admin-scope-regions")] + public virtual async Task> GetAdminScopeRegionsAsync([FromQuery] string partnerId) { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); - return await UsAppAuthScopeHelper.ListRegionsAsync(_dbContext.SqlSugarClient, partnerId); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); + return await AuthScopeQueryHelper.GetRegionsAsync(CurrentUser, _dbContext, partnerId); } /// [Authorize] + [HttpGet("us-app-auth/admin-scope-locations")] public virtual async Task> GetAdminScopeLocationsAsync( - string partnerId, - string groupId) + [FromQuery] string partnerId, + [FromQuery] string groupId) { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); - return await UsAppAuthScopeHelper.ListLocationsAsync( - _dbContext.SqlSugarClient, - partnerId, - groupId); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); + return await AuthScopeQueryHelper.GetLocationsAsync(CurrentUser, _dbContext, partnerId, groupId); } /// [Authorize] + [HttpPost("us-app-auth/select-admin-scope-location")] public virtual async Task SelectAdminScopeLocationAsync( AuthScopeSelectLocationInputVo input) { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); if (!CurrentUser.Id.HasValue) { throw new UserFriendlyException("用户未登录"); @@ -230,6 +231,7 @@ public class UsAppAuthAppService : ApplicationService, IUsAppAuthAppService return await UsAppAuthScopeHelper.SelectLocationAsync( _dbContext.SqlSugarClient, _distributedCache, + CurrentUser, CurrentUser.Id.Value, new UsAppSelectAdminScopeLocationInputVo { diff --git a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs index 273af31..2227bcf 100644 --- a/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs +++ b/泰额版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs @@ -364,11 +364,13 @@ public class UsAppLabelingAppService : ApplicationService, IUsAppLabelingAppServ } var labelRow = await _dbContext.SqlSugarClient - .Queryable( - (l, c, t, tpl) => l.LabelCategoryId == c.Id && l.LabelTypeId == t.Id && l.TemplateId == tpl.Id) + .Queryable() + .InnerJoin((l, c) => l.LabelCategoryId == c.Id) + .LeftJoin((l, c, t) => l.LabelTypeId == t.Id) + .InnerJoin((l, c, t, tpl) => l.TemplateId == tpl.Id) .Where((l, c, t, tpl) => !l.IsDeleted && l.State) .Where((l, c, t, tpl) => !c.IsDeleted && c.State) - .Where((l, c, t, tpl) => !t.IsDeleted && t.State) + .Where((l, c, t, tpl) => t.Id == null || (!t.IsDeleted && t.State)) .Where((l, c, t, tpl) => !tpl.IsDeleted) .Where((l, c, t, tpl) => l.LabelCode == labelCode) .Select((l, c, t, tpl) => new @@ -551,10 +553,11 @@ public class UsAppLabelingAppService : ApplicationService, IUsAppLabelingAppServ // 校验 label + location,并补齐一些顶部字段用于任务表落库 var labelRow = await _dbContext.SqlSugarClient - .Queryable( - (l, t, tpl) => l.LabelTypeId == t.Id && l.TemplateId == tpl.Id) + .Queryable() + .LeftJoin((l, t) => l.LabelTypeId == t.Id) + .InnerJoin((l, t, tpl) => l.TemplateId == tpl.Id) .Where((l, t, tpl) => !l.IsDeleted && l.State) - .Where((l, t, tpl) => !t.IsDeleted && t.State) + .Where((l, t, tpl) => t.Id == null || (!t.IsDeleted && t.State)) .Where((l, t, tpl) => !tpl.IsDeleted) .Where((l, t, tpl) => l.LabelCode == labelCode) .Select((l, t, tpl) => new diff --git a/美国版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts b/美国版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts index 1bfa47c..d8f34db 100644 --- a/美国版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts +++ b/美国版/Food Labeling Management App UniApp/src/utils/appAdminRole.ts @@ -1,6 +1,16 @@ import type { UsAppMyProfileOutputDto } from '../services/usAppAuth' -/** 与后端 ReportsRoleHelper.IsAdminRole 对齐(App 管理员级联选店) */ +function isCompanyAdminProfile(profile: UsAppMyProfileOutputDto): boolean { + const code = (profile.primaryRoleCode ?? '').trim().toLowerCase() + if (code === 'companyadmin' || code.includes('partner')) return true + const display = (profile.roleDisplay ?? '').trim().toLowerCase() + if (!display) return false + if (display === 'company admin') return true + if (display.includes('partner admin')) return true + return false +} + +/** 平台管理员或 Company Admin(App 级联选店) */ export function isAppAdminUser(profile: UsAppMyProfileOutputDto | null | undefined): boolean { if (!profile) return false const code = (profile.primaryRoleCode ?? '').trim().toLowerCase() @@ -8,9 +18,9 @@ export function isAppAdminUser(profile: UsAppMyProfileOutputDto | null | undefin if (code === 'admin') return true if (compactCode === 'companyadmin') return true const display = (profile.roleDisplay ?? '').trim().toLowerCase() - if (!display) return false + if (!display) return isCompanyAdminProfile(profile) if (display.includes('administrator')) return true if (display.includes('super admin')) return true if (display.includes('company admin')) return true - return false + return isCompanyAdminProfile(profile) } diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs index 4f08361..be7c640 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/AuthScopeQueryHelper.cs @@ -277,14 +277,10 @@ public static class AuthScopeQueryHelper return; } - var lid = locationId.Trim(); - var userIdStr = currentUser.Id!.Value.ToString(); - var bound = await dbContext.SqlSugarClient.Queryable() - .AnyAsync(x => !x.IsDeleted && x.UserId == userIdStr && x.LocationId == lid); - if (!bound) - { - throw new UserFriendlyException("当前账号未绑定该门店,无法选择"); - } + await UsAppPrintLogScopeHelper.EnsureUserCanAccessLocationAsync( + currentUser, + dbContext.SqlSugarClient, + locationId); } private static async Task ResolveAndValidateSelectionAsync( diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs new file mode 100644 index 0000000..c53fee6 --- /dev/null +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/EntityLocationScopeDisplayHelper.cs @@ -0,0 +1,67 @@ +using FoodLabeling.Domain.Shared; +using SqlSugar; + +namespace FoodLabeling.Application.Helpers; + +/// +/// 标签类型/分类/多选项等:列表 Region/Location 列展示(适用全部时分别为 All Region / All Location)。 +/// +public static class EntityLocationScopeDisplayHelper +{ + /// + /// 根据可用范围类型与已解析的 Region/Location Id、名称,生成列表展示文案。 + /// + public static async Task<(string Region, string Location)> BuildListDisplayAsync( + ISqlSugarClient db, + string? availabilityType, + IReadOnlyList regionIds, + IReadOnlyList locationIds, + IEnumerable regionNames, + IEnumerable locationNames, + IReadOnlyList? partnerIdsForContext) + { + if (AllScopeBindingHelper.IsDeclaredAll(availabilityType)) + { + return (AllScopeBindingHelper.AllRegionsDisplay, AllScopeBindingHelper.AllLocationsDisplay); + } + + var normRegionIds = LocationScopeBindingHelper.NormalizeIds(regionIds); + var normLocationIds = LocationScopeBindingHelper.NormalizeIds(locationIds); + var partnerContext = partnerIdsForContext is { Count: > 0 } ? partnerIdsForContext : null; + + var allRegionIds = await AllScopeBindingHelper.ResolveAllRegionIdsAsync(db, partnerContext); + var regionIsAll = normRegionIds.Count > 0 + && allRegionIds.Count > 0 + && AllScopeBindingHelper.IsFullIdSelection(normRegionIds, allRegionIds); + + var regionContextForLocations = regionIsAll ? null : normRegionIds.Count > 0 ? normRegionIds : null; + var allLocationIds = await AllScopeBindingHelper.ResolveAllLocationIdsAsync( + db, + partnerContext, + regionContextForLocations); + var locationIsAll = normLocationIds.Count > 0 + && allLocationIds.Count > 0 + && AllScopeBindingHelper.IsFullIdSelection(normLocationIds, allLocationIds); + + var regionDisplay = regionIsAll + ? AllScopeBindingHelper.AllRegionsDisplay + : JoinDistinctNames(regionNames); + + var locationDisplay = locationIsAll + ? AllScopeBindingHelper.AllLocationsDisplay + : JoinDistinctNames(locationNames); + + return (regionDisplay, locationDisplay); + } + + private static string JoinDistinctNames(IEnumerable names) + { + var ordered = names + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Select(x => x.Trim()) + .Distinct(StringComparer.OrdinalIgnoreCase) + .OrderBy(x => x, StringComparer.OrdinalIgnoreCase) + .ToList(); + return ordered.Count > 0 ? string.Join(", ", ordered) : FoodLabelingDisplayConsts.NotAvailable; + } +} diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs new file mode 100644 index 0000000..d8c8296 --- /dev/null +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityListScopeHelper.cs @@ -0,0 +1,88 @@ +using FoodLabeling.Application.Services.DbModels; +using SqlSugar; + +namespace FoodLabeling.Application.Helpers; + +/// +/// 标签类型/分类/多选项列表:非平台管理员仅可见其绑定 Company 范围内数据。 +/// +public static class LabelEntityListScopeHelper +{ + /// + /// 标签类型列表:按 Company + Region/Location 范围过滤(Company Admin 不可见 All Companies 数据)。 + /// + public static ISugarQueryable ApplyTypeLocationAvailabilityFilter( + ISugarQueryable query, + List? scopedLocationIds) + { + if (scopedLocationIds is null) + { + return query; + } + + if (scopedLocationIds.Count == 0) + { + return query.Where(_ => false); + } + + return query.Where(t => + (t.AvailabilityType == AllScopeBindingHelper.ScopeAll + && t.AppliedPartnerType == LabelEntityPartnerScopeHelper.ScopeSpecified) + || (t.AvailabilityType == AllScopeBindingHelper.ScopeSpecified + && SqlFunc.Subqueryable() + .Where(tl => tl.LabelTypeId == t.Id && scopedLocationIds.Contains(tl.LocationId)) + .Any())); + } + + /// + /// 标签分类列表:按 Company + Region/Location 范围过滤。 + /// + public static ISugarQueryable ApplyCategoryLocationAvailabilityFilter( + ISugarQueryable query, + List? scopedLocationIds) + { + if (scopedLocationIds is null) + { + return query; + } + + if (scopedLocationIds.Count == 0) + { + return query.Where(_ => false); + } + + return query.Where(c => + (c.AvailabilityType == AllScopeBindingHelper.ScopeAll + && c.AppliedPartnerType == LabelEntityPartnerScopeHelper.ScopeSpecified) + || (c.AvailabilityType == AllScopeBindingHelper.ScopeSpecified + && SqlFunc.Subqueryable() + .Where(cl => cl.CategoryId == c.Id && scopedLocationIds.Contains(cl.LocationId)) + .Any())); + } + + /// + /// 标签多选项列表:按 Company + Region/Location 范围过滤。 + /// + public static ISugarQueryable ApplyMultipleOptionLocationAvailabilityFilter( + ISugarQueryable query, + List? scopedLocationIds) + { + if (scopedLocationIds is null) + { + return query; + } + + if (scopedLocationIds.Count == 0) + { + return query.Where(_ => false); + } + + return query.Where(o => + (o.AvailabilityType == AllScopeBindingHelper.ScopeAll + && o.AppliedPartnerType == LabelEntityPartnerScopeHelper.ScopeSpecified) + || (o.AvailabilityType == AllScopeBindingHelper.ScopeSpecified + && SqlFunc.Subqueryable() + .Where(ol => ol.MultipleOptionId == o.Id && scopedLocationIds.Contains(ol.LocationId)) + .Any())); + } +} diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs index 57e580c..1bdbc25 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelEntityPartnerScopeHelper.cs @@ -348,17 +348,12 @@ public static class LabelEntityPartnerScopeHelper if (scopedPartnerIds.Count == 0) { - return query.Where(t => - !SqlFunc.Subqueryable() - .Where(p => p.LabelTypeId == t.Id) - .Any()); + return query.Where(_ => false); } return query.Where(t => - !SqlFunc.Subqueryable() - .Where(p => p.LabelTypeId == t.Id) - .Any() - || SqlFunc.Subqueryable() + t.AppliedPartnerType == ScopeSpecified + && SqlFunc.Subqueryable() .Where(p => p.LabelTypeId == t.Id && scopedPartnerIds.Contains(p.PartnerId)) .Any()); } @@ -384,17 +379,12 @@ public static class LabelEntityPartnerScopeHelper if (scopedPartnerIds.Count == 0) { - return query.Where(c => - !SqlFunc.Subqueryable() - .Where(p => p.CategoryId == c.Id) - .Any()); + return query.Where(_ => false); } return query.Where(c => - !SqlFunc.Subqueryable() - .Where(p => p.CategoryId == c.Id) - .Any() - || SqlFunc.Subqueryable() + c.AppliedPartnerType == ScopeSpecified + && SqlFunc.Subqueryable() .Where(p => p.CategoryId == c.Id && scopedPartnerIds.Contains(p.PartnerId)) .Any()); } @@ -420,17 +410,12 @@ public static class LabelEntityPartnerScopeHelper if (scopedPartnerIds.Count == 0) { - return query.Where(o => - !SqlFunc.Subqueryable() - .Where(p => p.MultipleOptionId == o.Id) - .Any()); + return query.Where(_ => false); } return query.Where(o => - !SqlFunc.Subqueryable() - .Where(p => p.MultipleOptionId == o.Id) - .Any() - || SqlFunc.Subqueryable() + o.AppliedPartnerType == ScopeSpecified + && SqlFunc.Subqueryable() .Where(p => p.MultipleOptionId == o.Id && scopedPartnerIds.Contains(p.PartnerId)) .Any()); } diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs index f7ae0ea..674a63b 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LabelTemplateScopeHelper.cs @@ -437,23 +437,7 @@ public static class LabelTemplateScopeHelper if (scopedLocationIds.Count == 0) { - return hasExtendedScope - ? query.Where(t => - t.AppliedLocationType == ScopeAll - && !SqlFunc.Subqueryable() - .Where(l => l.TemplateId == t.Id) - .Any() - && !SqlFunc.Subqueryable() - .Where(p => p.TemplateId == t.Id) - .Any() - && !SqlFunc.Subqueryable() - .Where(r => r.TemplateId == t.Id) - .Any()) - : query.Where(t => - t.AppliedLocationType == ScopeAll - && !SqlFunc.Subqueryable() - .Where(l => l.TemplateId == t.Id) - .Any()); + return query.Where(_ => false); } if (!hasExtendedScope) @@ -470,12 +454,9 @@ public static class LabelTemplateScopeHelper db, scopedLocationIds); return query.Where(t => - (!SqlFunc.Subqueryable() - .Where(p => p.TemplateId == t.Id) - .Any() - || SqlFunc.Subqueryable() - .Where(p => p.TemplateId == t.Id && scopedPartnerIds.Contains(p.PartnerId)) - .Any()) + SqlFunc.Subqueryable() + .Where(p => p.TemplateId == t.Id && scopedPartnerIds.Contains(p.PartnerId)) + .Any() && (!SqlFunc.Subqueryable() .Where(r => r.TemplateId == t.Id) .Any() diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs index e9d0616..b0942ee 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/LocationRegionScopeHelper.cs @@ -25,6 +25,7 @@ public static class LocationRegionScopeHelper /// /// 解析当前用户可查询的 Region(公司 + 组织名)集合。 + /// Company Admin 展开为绑定 Company 下全部 Region(与 一致)。 /// public static async Task ResolveLocationListScopeAsync( ICurrentUser currentUser, @@ -40,8 +41,15 @@ public static class LocationRegionScopeHelper return new LocationListScopeFilter(); } + var db = dbContext.SqlSugarClient; + + if (await TeamMemberRoleHelper.IsCompanyAdminUserAsync(db, currentUser)) + { + return await ResolveCompanyAdminLocationListScopeAsync(db, currentUser.Id.Value); + } + var userId = currentUser.Id.Value.ToString(); - var rows = await dbContext.SqlSugarClient.Queryable() + var rows = await db.Queryable() .InnerJoin((ul, loc) => !loc.IsDeleted && ul.LocationId == loc.Id.ToString()) .Where(ul => !ul.IsDeleted && ul.UserId == userId) @@ -57,6 +65,59 @@ public static class LocationRegionScopeHelper return new LocationListScopeFilter { RegionKeys = keys }; } + private static async Task ResolveCompanyAdminLocationListScopeAsync( + ISqlSugarClient db, + Guid userId) + { + var locationIds = await LocationScopeBindingHelper.ResolveBoundLocationIdsForUserAsync(db, userId); + if (locationIds.Count == 0) + { + return new LocationListScopeFilter(); + } + + var partnerIds = await LocationScopeBindingHelper.ResolvePartnerIdsFromLocationIdsAsync(db, locationIds); + if (partnerIds.Count == 0) + { + return new LocationListScopeFilter(); + } + + var partners = await db.Queryable() + .Where(p => !p.IsDeleted && partnerIds.Contains(p.Id)) + .Select(p => new { p.Id, p.PartnerName }) + .ToListAsync(); + + var groups = await db.Queryable() + .Where(g => !g.IsDeleted && partnerIds.Contains(g.PartnerId)) + .Select(g => new { g.PartnerId, g.GroupName }) + .ToListAsync(); + + var keys = new HashSet<(string Partner, string GroupName)>(); + foreach (var group in groups) + { + var groupName = group.GroupName?.Trim(); + if (string.IsNullOrEmpty(groupName)) + { + continue; + } + + var partner = partners.FirstOrDefault(p => + string.Equals(p.Id, group.PartnerId, StringComparison.OrdinalIgnoreCase)); + var partnerName = partner?.PartnerName?.Trim(); + if (!string.IsNullOrEmpty(partnerName)) + { + keys.Add((partnerName, groupName)); + } + + var partnerId = group.PartnerId?.Trim(); + if (!string.IsNullOrEmpty(partnerId)) + { + keys.Add((partnerId, groupName)); + } + } + + return new LocationListScopeFilter { RegionKeys = keys.ToList() }; + } + /// /// 将 Region 范围应用到 location 查询(须在其它 Where 之前或之后均可,建议在 IsDeleted 之后)。 /// diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs index 59661b7..f9f4c8c 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Helpers/UsAppAuthScopeHelper.cs @@ -19,7 +19,7 @@ public static class UsAppAuthScopeHelper { private const string CacheKeyPrefix = "FoodLabeling:UsAppAdminScope:"; - public static void EnsureAdminAppToken(ICurrentUser currentUser) + public static async Task EnsureAppScopeCallerAsync(ISqlSugarClient db, ICurrentUser currentUser) { if (currentUser.Id is null) { @@ -32,12 +32,30 @@ public static class UsAppAuthScopeHelper throw new UserFriendlyException("请使用 App 登录令牌调用该接口"); } - if (!ReportsRoleHelper.IsAdminRole(currentUser)) + if (!await CanUseAdminScopeApisAsync(db, currentUser)) { - throw new UserFriendlyException("仅管理员可使用公司/区域/门店筛选接口"); + throw new UserFriendlyException("仅管理员或 Company Admin 可使用公司/区域/门店筛选接口"); } } + /// + /// 平台管理员或 Company Admin 可使用 App 级联选店接口。 + /// + public static async Task CanUseAdminScopeApisAsync(ISqlSugarClient db, ICurrentUser currentUser) + { + if (currentUser.Id is null) + { + return false; + } + + if (ReportsRoleHelper.IsAdminRole(currentUser)) + { + return true; + } + + return await TeamMemberRoleHelper.IsCompanyAdminUserAsync(db, currentUser); + } + public static async Task> ListCompaniesAsync(ISqlSugarClient db) { return await db.Queryable() @@ -119,6 +137,7 @@ public static class UsAppAuthScopeHelper public static async Task SelectLocationAsync( ISqlSugarClient db, IDistributedCache cache, + ICurrentUser currentUser, Guid userId, UsAppSelectAdminScopeLocationInputVo input) { @@ -130,6 +149,11 @@ public static class UsAppAuthScopeHelper throw new UserFriendlyException("请选择公司、区域和门店"); } + if (!ReportsRoleHelper.IsAdminRole(currentUser)) + { + await UsAppPrintLogScopeHelper.EnsureUserCanAccessLocationAsync(currentUser, db, locationId); + } + var scopedIds = await LocationScopeBindingHelper.ResolveFilteredLocationIdsForListAsync( db, partnerId, diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs index cd4a368..d3adc88 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelAppService.cs @@ -62,38 +62,28 @@ public class LabelAppService : ApplicationService, ILabelAppService var db = _dbContext.SqlSugarClient; var regionSchema = await LabelRegionSchemaHelper.GetStatusAsync(db); - var scopedLocationIds = await LocationScopeBindingHelper.ResolveScopedLocationIdsAsync( - db, groupId, locationId); + var scopedLocationIds = await TeamMemberListScopeHelper.ResolveListLocationIdsAsync( + CurrentUser, + _dbContext, + partnerId, + groupId, + locationId); var filterGroupId = groupId?.Trim(); - if (!string.IsNullOrWhiteSpace(filterGroupId)) + if (scopedLocationIds is not null) { - labelIdsQuery = scopedLocationIds is { Count: 0 } - ? labelIdsQuery.Where(_ => false) - : LabelRegionScopeHelper.ApplyLabelRegionListFilter( + if (scopedLocationIds.Count == 0) + { + labelIdsQuery = labelIdsQuery.Where(_ => false); + } + else if (!string.IsNullOrWhiteSpace(filterGroupId)) + { + labelIdsQuery = LabelRegionScopeHelper.ApplyLabelRegionListFilter( db, labelIdsQuery, filterGroupId, scopedLocationIds, regionSchema); - } - else if (scopedLocationIds is not null) - { - labelIdsQuery = scopedLocationIds.Count == 0 - ? labelIdsQuery.Where(_ => false) - : LabelRegionScopeHelper.ApplyLabelLocationListFilter( - db, labelIdsQuery, scopedLocationIds, regionSchema); - } - else if (!string.IsNullOrWhiteSpace(groupId)) - { - labelIdsQuery = LabelRegionScopeHelper.ApplyGroupIdListFilter( - db, labelIdsQuery, groupId, regionSchema); - } - else if (!string.IsNullOrWhiteSpace(partnerId)) - { - var partnerLocationIds = await LocationScopeBindingHelper.ResolveFilteredLocationIdsForListAsync( - db, partnerId, null, null); - if (partnerLocationIds is not null) + } + else { - labelIdsQuery = partnerLocationIds.Count == 0 - ? labelIdsQuery.Where(_ => false) - : LabelRegionScopeHelper.ApplyLabelLocationListFilter( - db, labelIdsQuery, partnerLocationIds, regionSchema); + labelIdsQuery = LabelRegionScopeHelper.ApplyLabelLocationListFilter( + db, labelIdsQuery, scopedLocationIds, regionSchema); } } diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs index 9c9c71b..dd918a9 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelCategoryAppService.cs @@ -71,11 +71,11 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ var ids = entities.Select(x => x.Id).ToList(); var labelStatsMap = await BuildCategoryLabelStatsMapAsync(ids); - var scopeMap = await BuildCategoryScopeMapAsync(entities); var partnerScopeMap = await LabelEntityPartnerScopeHelper.BuildPartnerScopeDisplayMapAsync( _dbContext.SqlSugarClient, LabelEntityPartnerScopeHelper.LabelEntityPartnerKind.Category, ids); + var scopeMap = await BuildCategoryScopeMapAsync(entities, partnerScopeMap); var items = entities.Select(x => { @@ -370,16 +370,7 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ return query; } - if (scopedLocationIds.Count == 0) - { - return query.Where(c => c.AvailabilityType == "ALL"); - } - - return query.Where(c => - c.AvailabilityType == "ALL" || - SqlFunc.Subqueryable() - .Where(cl => cl.CategoryId == c.Id && scopedLocationIds.Contains(cl.LocationId)) - .Any()); + return LabelEntityListScopeHelper.ApplyCategoryLocationAvailabilityFilter(query, scopedLocationIds); } private async Task SaveCategoryPartnerScopeAsync( @@ -420,7 +411,8 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ private const string EmptyDisplay = FoodLabelingDisplayConsts.NotAvailable; private async Task> BuildCategoryScopeMapAsync( - List entities) + List entities, + Dictionary partnerScopeMap) { var result = new Dictionary(StringComparer.Ordinal); if (entities.Count == 0) @@ -428,8 +420,9 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ return result; } - foreach (var e in entities.Where(x => - !string.Equals(x.AvailabilityType, "SPECIFIED", StringComparison.OrdinalIgnoreCase))) + var entityById = entities.ToDictionary(x => x.Id, StringComparer.Ordinal); + + foreach (var e in entities.Where(x => AllScopeBindingHelper.IsDeclaredAll(x.AvailabilityType))) { result[e.Id] = new CategoryScopeData { @@ -525,14 +518,29 @@ public class LabelCategoryAppService : ApplicationService, ILabelCategoryAppServ var regionIds = await LocationScopeBindingHelper.ResolveGroupIdsFromLocationIdsAsync( _dbContext.SqlSugarClient, locationIds); + entityById.TryGetValue(catId, out var entity); + partnerScopeMap.TryGetValue(catId, out var partnerScope); + var partnerContext = entity is not null + && string.Equals( + entity.AppliedPartnerType, + LabelEntityPartnerScopeHelper.ScopeSpecified, + StringComparison.OrdinalIgnoreCase) + ? partnerScope?.PartnerIds + : null; + + var (regionDisplay, locationDisplay) = await EntityLocationScopeDisplayHelper.BuildListDisplayAsync( + _dbContext.SqlSugarClient, + entity?.AvailabilityType, + regionIds, + locationIds, + regions, + locationNames, + partnerContext); + result[catId] = new CategoryScopeData { - Region = regions.Count > 0 - ? string.Join(", ", regions.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)) - : EmptyDisplay, - Location = locationNames.Count > 0 - ? string.Join(", ", locationNames.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)) - : EmptyDisplay, + Region = regionDisplay, + Location = locationDisplay, RegionIds = regionIds, LocationIds = locationIds }; diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs index 9f2e38e..67aa994 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelMultipleOptionAppService.cs @@ -43,7 +43,7 @@ public class LabelMultipleOptionAppService : ApplicationService, ILabelMultipleO query = await LabelEntityPartnerScopeHelper.ApplyMultipleOptionPartnerListFilterAsync( _dbContext.SqlSugarClient, query, scopedPartnerIds); - query = ApplyMultipleOptionScopeFilter(query, scopedLocationIds); + query = LabelEntityListScopeHelper.ApplyMultipleOptionLocationAvailabilityFilter(query, scopedLocationIds); if (!string.IsNullOrWhiteSpace(input.Sorting)) { @@ -395,27 +395,6 @@ public class LabelMultipleOptionAppService : ApplicationService, ILabelMultipleO }; } - private static ISugarQueryable ApplyMultipleOptionScopeFilter( - ISugarQueryable query, - List? scopedLocationIds) - { - if (scopedLocationIds is null) - { - return query; - } - - if (scopedLocationIds.Count == 0) - { - return query.Where(o => o.AvailabilityType == "ALL"); - } - - return query.Where(o => - o.AvailabilityType == "ALL" || - SqlFunc.Subqueryable() - .Where(ol => ol.MultipleOptionId == o.Id && scopedLocationIds.Contains(ol.LocationId)) - .Any()); - } - private async Task> BuildMultipleOptionScopeMapAsync( List entities) { diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs index 1e96ce0..2a21745 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/LabelTypeAppService.cs @@ -43,7 +43,7 @@ public class LabelTypeAppService : ApplicationService, ILabelTypeAppService query = await LabelEntityPartnerScopeHelper.ApplyTypePartnerListFilterAsync( _dbContext.SqlSugarClient, query, scopedPartnerIds); - query = ApplyLabelTypeScopeFilter(query, scopedLocationIds); + query = LabelEntityListScopeHelper.ApplyTypeLocationAvailabilityFilter(query, scopedLocationIds); if (!string.IsNullOrWhiteSpace(input.Sorting)) { @@ -346,27 +346,6 @@ public class LabelTypeAppService : ApplicationService, ILabelTypeAppService return merged.OrderBy(x => x, StringComparer.Ordinal).ToList(); } - private static ISugarQueryable ApplyLabelTypeScopeFilter( - ISugarQueryable query, - List? scopedLocationIds) - { - if (scopedLocationIds is null) - { - return query; - } - - if (scopedLocationIds.Count == 0) - { - return query.Where(t => t.AvailabilityType == "ALL"); - } - - return query.Where(t => - t.AvailabilityType == "ALL" || - SqlFunc.Subqueryable() - .Where(tl => tl.LabelTypeId == t.Id && scopedLocationIds.Contains(tl.LocationId)) - .Any()); - } - private async Task SaveTypeLocationsAsync( string labelTypeId, string availabilityType, diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs index b7e76ab..08d3c64 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppAuthAppService.cs @@ -161,7 +161,7 @@ public class UsAppAuthAppService : ApplicationService, IUsAppAuthAppService } var list = await LoadBoundLocationsAsync(CurrentUser.Id.Value); - if (ReportsRoleHelper.IsAdminRole(CurrentUser)) + if (await UsAppAuthScopeHelper.CanUseAdminScopeApisAsync(_dbContext.SqlSugarClient, CurrentUser)) { var cached = await UsAppAuthScopeHelper.GetAdminScopeCacheAsync( _distributedCache, @@ -180,39 +180,40 @@ public class UsAppAuthAppService : ApplicationService, IUsAppAuthAppService /// [Authorize] + [HttpGet("us-app-auth/admin-scope-companies")] public virtual async Task> GetAdminScopeCompaniesAsync() { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); - return await UsAppAuthScopeHelper.ListCompaniesAsync(_dbContext.SqlSugarClient); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); + return await AuthScopeQueryHelper.GetCompaniesAsync(CurrentUser, _dbContext); } /// [Authorize] - public virtual async Task> GetAdminScopeRegionsAsync(string partnerId) + [HttpGet("us-app-auth/admin-scope-regions")] + public virtual async Task> GetAdminScopeRegionsAsync([FromQuery] string partnerId) { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); - return await UsAppAuthScopeHelper.ListRegionsAsync(_dbContext.SqlSugarClient, partnerId); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); + return await AuthScopeQueryHelper.GetRegionsAsync(CurrentUser, _dbContext, partnerId); } /// [Authorize] + [HttpGet("us-app-auth/admin-scope-locations")] public virtual async Task> GetAdminScopeLocationsAsync( - string partnerId, - string groupId) + [FromQuery] string partnerId, + [FromQuery] string groupId) { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); - return await UsAppAuthScopeHelper.ListLocationsAsync( - _dbContext.SqlSugarClient, - partnerId, - groupId); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); + return await AuthScopeQueryHelper.GetLocationsAsync(CurrentUser, _dbContext, partnerId, groupId); } /// [Authorize] + [HttpPost("us-app-auth/select-admin-scope-location")] public virtual async Task SelectAdminScopeLocationAsync( AuthScopeSelectLocationInputVo input) { - UsAppAuthScopeHelper.EnsureAdminAppToken(CurrentUser); + await UsAppAuthScopeHelper.EnsureAppScopeCallerAsync(_dbContext.SqlSugarClient, CurrentUser); if (!CurrentUser.Id.HasValue) { throw new UserFriendlyException("用户未登录"); @@ -221,6 +222,7 @@ public class UsAppAuthAppService : ApplicationService, IUsAppAuthAppService return await UsAppAuthScopeHelper.SelectLocationAsync( _dbContext.SqlSugarClient, _distributedCache, + CurrentUser, CurrentUser.Id.Value, new UsAppSelectAdminScopeLocationInputVo { diff --git a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs index 273af31..2227bcf 100644 --- a/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs +++ b/美国版/Food Labeling Management Code/Yi.Abp.Net8/module/food-labeling-us/FoodLabeling.Application/Services/UsAppLabelingAppService.cs @@ -364,11 +364,13 @@ public class UsAppLabelingAppService : ApplicationService, IUsAppLabelingAppServ } var labelRow = await _dbContext.SqlSugarClient - .Queryable( - (l, c, t, tpl) => l.LabelCategoryId == c.Id && l.LabelTypeId == t.Id && l.TemplateId == tpl.Id) + .Queryable() + .InnerJoin((l, c) => l.LabelCategoryId == c.Id) + .LeftJoin((l, c, t) => l.LabelTypeId == t.Id) + .InnerJoin((l, c, t, tpl) => l.TemplateId == tpl.Id) .Where((l, c, t, tpl) => !l.IsDeleted && l.State) .Where((l, c, t, tpl) => !c.IsDeleted && c.State) - .Where((l, c, t, tpl) => !t.IsDeleted && t.State) + .Where((l, c, t, tpl) => t.Id == null || (!t.IsDeleted && t.State)) .Where((l, c, t, tpl) => !tpl.IsDeleted) .Where((l, c, t, tpl) => l.LabelCode == labelCode) .Select((l, c, t, tpl) => new @@ -551,10 +553,11 @@ public class UsAppLabelingAppService : ApplicationService, IUsAppLabelingAppServ // 校验 label + location,并补齐一些顶部字段用于任务表落库 var labelRow = await _dbContext.SqlSugarClient - .Queryable( - (l, t, tpl) => l.LabelTypeId == t.Id && l.TemplateId == tpl.Id) + .Queryable() + .LeftJoin((l, t) => l.LabelTypeId == t.Id) + .InnerJoin((l, t, tpl) => l.TemplateId == tpl.Id) .Where((l, t, tpl) => !l.IsDeleted && l.State) - .Where((l, t, tpl) => !t.IsDeleted && t.State) + .Where((l, t, tpl) => t.Id == null || (!t.IsDeleted && t.State)) .Where((l, t, tpl) => !tpl.IsDeleted) .Where((l, t, tpl) => l.LabelCode == labelCode) .Select((l, t, tpl) => new diff --git a/美国版/Food Labeling Management Platform/src/services/labelCategoryService.ts b/美国版/Food Labeling Management Platform/src/services/labelCategoryService.ts index 64149d2..c5c5abc 100644 --- a/美国版/Food Labeling Management Platform/src/services/labelCategoryService.ts +++ b/美国版/Food Labeling Management Platform/src/services/labelCategoryService.ts @@ -49,6 +49,8 @@ function normalizeLabelCategoryDto(raw: unknown): LabelCategoryDto { ? Number(orderRaw) : null; const companyRaw = r.company ?? r.Company; + const regionRaw = r.region ?? r.Region; + const locationRaw = r.location ?? r.Location; return { ...(r as object), id: String(r.id ?? r.Id ?? ""), @@ -60,6 +62,8 @@ function normalizeLabelCategoryDto(raw: unknown): LabelCategoryDto { regionIds: groupIds, locationIds, company: typeof companyRaw === "string" ? companyRaw : null, + region: typeof regionRaw === "string" ? regionRaw : null, + location: typeof locationRaw === "string" ? locationRaw : null, noOfLabels, orderNum, } as LabelCategoryDto; -- libgit2 0.21.4