diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantCategoriesController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantCategoriesController.cs index 497cc87..6358aac 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantCategoriesController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantCategoriesController.cs @@ -1,3 +1,4 @@ +using System.ComponentModel.DataAnnotations; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -22,15 +23,18 @@ public sealed class MerchantCategoriesController(IMediator mediator) : BaseApiCo /// /// 列出所有类目。 /// + /// 租户 ID。 /// 取消标记。 /// 类目列表。 [HttpGet] [PermissionAuthorize("merchant_category:read")] [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - public async Task>> List(CancellationToken cancellationToken) + public async Task>> List( + [FromQuery, Range(1, long.MaxValue)] long tenantId, + CancellationToken cancellationToken) { // 1. 查询所有类目 - var result = await mediator.Send(new ListMerchantCategoriesQuery(), cancellationToken); + var result = await mediator.Send(new ListMerchantCategoriesQuery { TenantId = tenantId }, cancellationToken); // 2. 返回类目列表 return ApiResponse>.Ok(result); @@ -39,15 +43,20 @@ public sealed class MerchantCategoriesController(IMediator mediator) : BaseApiCo /// /// 新增类目。 /// + /// 租户 ID。 /// 创建命令。 /// 取消标记。 /// 创建的类目。 [HttpPost] [PermissionAuthorize("merchant_category:create")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> Create([FromBody] CreateMerchantCategoryCommand command, CancellationToken cancellationToken) + public async Task> Create( + [FromQuery, Range(1, long.MaxValue)] long tenantId, + [FromBody] CreateMerchantCategoryCommand command, + CancellationToken cancellationToken) { // 1. 创建类目 + command = command with { TenantId = tenantId }; var result = await mediator.Send(command, cancellationToken); // 2. 返回创建结果 @@ -57,6 +66,7 @@ public sealed class MerchantCategoriesController(IMediator mediator) : BaseApiCo /// /// 删除类目。 /// + /// 租户 ID。 /// 类目 ID。 /// 取消标记。 /// 删除结果,未找到则返回错误。 @@ -64,10 +74,13 @@ public sealed class MerchantCategoriesController(IMediator mediator) : BaseApiCo [PermissionAuthorize("merchant_category:delete")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> Delete(long categoryId, CancellationToken cancellationToken) + public async Task> Delete( + [FromQuery, Range(1, long.MaxValue)] long tenantId, + long categoryId, + CancellationToken cancellationToken) { // 1. 执行删除 - var success = await mediator.Send(new DeleteMerchantCategoryCommand(categoryId), cancellationToken); + var success = await mediator.Send(new DeleteMerchantCategoryCommand(tenantId, categoryId), cancellationToken); // 2. 返回删除结果或 404 return success @@ -78,15 +91,20 @@ public sealed class MerchantCategoriesController(IMediator mediator) : BaseApiCo /// /// 批量调整类目排序。 /// + /// 租户 ID。 /// 排序命令。 /// 取消标记。 /// 执行结果。 [HttpPost("reorder")] [PermissionAuthorize("merchant_category:update")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> Reorder([FromBody] ReorderMerchantCategoriesCommand command, CancellationToken cancellationToken) + public async Task> Reorder( + [FromQuery, Range(1, long.MaxValue)] long tenantId, + [FromBody] ReorderMerchantCategoriesCommand command, + CancellationToken cancellationToken) { // 1. 执行排序调整 + command = command with { TenantId = tenantId }; await mediator.Send(command, cancellationToken); // 2. 返回成功结果 diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs index 98125ac..8f756d2 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs @@ -2,6 +2,7 @@ using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; +using System.ComponentModel.DataAnnotations; using TakeoutSaaS.Application.App.Merchants.Commands; using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; @@ -436,10 +437,12 @@ public sealed class MerchantsController(IMediator mediator) : BaseApiController [HttpGet("categories")] [PermissionAuthorize("merchant:read")] [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - public async Task>> Categories(CancellationToken cancellationToken) + public async Task>> Categories( + [FromQuery, Range(1, long.MaxValue)] long tenantId, + CancellationToken cancellationToken) { // 1. 查询可选类目 - var result = await mediator.Send(new GetMerchantCategoriesQuery(), cancellationToken); + var result = await mediator.Send(new GetMerchantCategoriesQuery(tenantId), cancellationToken); // 2. 返回类目列表 return ApiResponse>.Ok(result); diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCategoryCommand.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCategoryCommand.cs index fe01142..290812f 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCategoryCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCategoryCommand.cs @@ -7,7 +7,27 @@ namespace TakeoutSaaS.Application.App.Merchants.Commands; /// /// 新增商户类目。 /// -public sealed record CreateMerchantCategoryCommand( - [property: Required, MaxLength(64)] string Name, - int? DisplayOrder, - bool IsActive = true) : IRequest; +public sealed record CreateMerchantCategoryCommand : IRequest +{ + /// + /// 租户 ID。 + /// + [Range(1, long.MaxValue)] + public long TenantId { get; init; } + + /// + /// 类目名称。 + /// + [Required, MaxLength(64)] + public string Name { get; init; } = string.Empty; + + /// + /// 排序(为空则自动追加到末尾)。 + /// + public int? DisplayOrder { get; init; } + + /// + /// 是否启用。 + /// + public bool IsActive { get; init; } = true; +} diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCommand.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCommand.cs index ba98a8c..1491760 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/CreateMerchantCommand.cs @@ -10,6 +10,12 @@ namespace TakeoutSaaS.Application.App.Merchants.Commands; /// public sealed class CreateMerchantCommand : IRequest { + /// + /// 所属租户 ID。 + /// + [Range(1, long.MaxValue)] + public long TenantId { get; init; } + /// /// 品牌名称。 /// diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/DeleteMerchantCategoryCommand.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/DeleteMerchantCategoryCommand.cs index 98cfd21..b86f861 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/DeleteMerchantCategoryCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/DeleteMerchantCategoryCommand.cs @@ -6,4 +6,6 @@ namespace TakeoutSaaS.Application.App.Merchants.Commands; /// /// 删除商户类目。 /// -public sealed record DeleteMerchantCategoryCommand([property: Required] long CategoryId) : IRequest; +public sealed record DeleteMerchantCategoryCommand( + [property: Range(1, long.MaxValue)] long TenantId, + [property: Required] long CategoryId) : IRequest; diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/ReorderMerchantCategoriesCommand.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/ReorderMerchantCategoriesCommand.cs index 542e6aa..983a450 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/ReorderMerchantCategoriesCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/ReorderMerchantCategoriesCommand.cs @@ -6,8 +6,20 @@ namespace TakeoutSaaS.Application.App.Merchants.Commands; /// /// 调整类目排序。 /// -public sealed record ReorderMerchantCategoriesCommand( - [property: Required, MinLength(1)] IReadOnlyList Items) : IRequest; +public sealed record ReorderMerchantCategoriesCommand : IRequest +{ + /// + /// 租户 ID。 + /// + [Range(1, long.MaxValue)] + public long TenantId { get; init; } + + /// + /// 排序条目。 + /// + [Required, MinLength(1)] + public IReadOnlyList Items { get; init; } = []; +} /// /// 类目排序条目。 diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/AddMerchantDocumentCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/AddMerchantDocumentCommandHandler.cs index 1ca8cf1..f254c16 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/AddMerchantDocumentCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/AddMerchantDocumentCommandHandler.cs @@ -8,7 +8,6 @@ using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Ids; using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -17,7 +16,6 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// public sealed class AddMerchantDocumentCommandHandler( IMerchantRepository merchantRepository, - ITenantProvider tenantProvider, IIdGenerator idGenerator, ICurrentUserAccessor currentUserAccessor) : IRequestHandler @@ -30,15 +28,16 @@ public sealed class AddMerchantDocumentCommandHandler( /// 证照 DTO。 public async Task Handle(AddMerchantDocumentCommand request, CancellationToken cancellationToken) { - // 1. 获取租户并查询商户 - var tenantId = tenantProvider.GetCurrentTenantId(); - var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken) + // 1. 查询商户并解析租户 + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); + var tenantId = merchant.TenantId; - // 2. 构建证照记录 + // 2. (空行后) 构建证照记录并写入租户 var document = new MerchantDocument { Id = idGenerator.NextId(), + TenantId = tenantId, MerchantId = merchant.Id, DocumentType = request.DocumentType, Status = MerchantDocumentStatus.Pending, @@ -48,7 +47,7 @@ public sealed class AddMerchantDocumentCommandHandler( ExpiresAt = request.ExpiresAt }; - // 3. 持久化与审计 + // 3. (空行后) 持久化与审计 await merchantRepository.AddDocumentAsync(document, cancellationToken); await merchantRepository.AddAuditLogAsync(new MerchantAuditLog { diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCategoryCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCategoryCommandHandler.cs index 917bfaa..e91a62b 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCategoryCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCategoryCommandHandler.cs @@ -5,7 +5,6 @@ using TakeoutSaaS.Domain.Merchants.Entities; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -13,8 +12,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 创建类目处理器。 /// public sealed class CreateMerchantCategoryCommandHandler( - IMerchantCategoryRepository categoryRepository, - ITenantProvider tenantProvider) + IMerchantCategoryRepository categoryRepository) : IRequestHandler { /// @@ -25,29 +23,30 @@ public sealed class CreateMerchantCategoryCommandHandler( /// 类目 DTO。 public async Task Handle(CreateMerchantCategoryCommand request, CancellationToken cancellationToken) { - // 1. 获取租户上下文 - var tenantId = tenantProvider.GetCurrentTenantId(); + // 1. 解析租户与规范化名称 + var tenantId = request.TenantId; var normalizedName = request.Name.Trim(); - // 2. 检查重名 + // 2. (空行后) 检查重名 if (await categoryRepository.ExistsAsync(normalizedName, tenantId, cancellationToken)) { throw new BusinessException(ErrorCodes.Conflict, $"类目“{normalizedName}”已存在"); } - // 3. 计算排序 + // 3. (空行后) 计算排序 var categories = await categoryRepository.ListAsync(tenantId, cancellationToken); var targetOrder = request.DisplayOrder ?? (categories.Count == 0 ? 1 : categories.Max(x => x.DisplayOrder) + 1); - // 4. 构建实体 + // 4. (空行后) 构建实体并写入租户 var entity = new MerchantCategory { + TenantId = tenantId, Name = normalizedName, DisplayOrder = targetOrder, IsActive = request.IsActive }; - // 5. 持久化并返回 + // 5. (空行后) 持久化并返回 await categoryRepository.AddAsync(entity, cancellationToken); await categoryRepository.SaveChangesAsync(cancellationToken); diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCommandHandler.cs index d6a52e0..fe5eeb4 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantCommandHandler.cs @@ -20,6 +20,7 @@ public sealed class CreateMerchantCommandHandler(IMerchantRepository merchantRep // 1. 构建商户实体 var merchant = new Merchant { + TenantId = request.TenantId, BrandName = request.BrandName.Trim(), BrandAlias = request.BrandAlias?.Trim(), LogoUrl = request.LogoUrl?.Trim(), diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantContractCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantContractCommandHandler.cs index 4d1a658..ee17233 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantContractCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/CreateMerchantContractCommandHandler.cs @@ -8,7 +8,6 @@ using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Ids; using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -17,7 +16,6 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// public sealed class CreateMerchantContractCommandHandler( IMerchantRepository merchantRepository, - ITenantProvider tenantProvider, IIdGenerator idGenerator, ICurrentUserAccessor currentUserAccessor) : IRequestHandler @@ -36,15 +34,16 @@ public sealed class CreateMerchantContractCommandHandler( throw new BusinessException(ErrorCodes.BadRequest, "合同结束时间必须晚于开始时间"); } - // 2. 查询商户 - var tenantId = tenantProvider.GetCurrentTenantId(); - var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken) + // 2. 查询商户并解析租户 + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); + var tenantId = merchant.TenantId; - // 3. 构建合同 + // 3. (空行后) 构建合同并写入租户 var contract = new MerchantContract { Id = idGenerator.NextId(), + TenantId = tenantId, MerchantId = merchant.Id, ContractNumber = request.ContractNumber.Trim(), StartDate = request.StartDate, @@ -52,7 +51,7 @@ public sealed class CreateMerchantContractCommandHandler( FileUrl = request.FileUrl.Trim() }; - // 4. 持久化与审计 + // 4. (空行后) 持久化与审计 await merchantRepository.AddContractAsync(contract, cancellationToken); await merchantRepository.AddAuditLogAsync(new MerchantAuditLog { diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCategoryCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCategoryCommandHandler.cs index 316214e..0066575 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCategoryCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCategoryCommandHandler.cs @@ -1,7 +1,6 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Commands; using TakeoutSaaS.Domain.Merchants.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -9,8 +8,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 删除类目处理器。 /// public sealed class DeleteMerchantCategoryCommandHandler( - IMerchantCategoryRepository categoryRepository, - ITenantProvider tenantProvider) + IMerchantCategoryRepository categoryRepository) : IRequestHandler { /// @@ -21,16 +19,15 @@ public sealed class DeleteMerchantCategoryCommandHandler( /// 执行结果。 public async Task Handle(DeleteMerchantCategoryCommand request, CancellationToken cancellationToken) { - // 1. 获取租户上下文 - var tenantId = tenantProvider.GetCurrentTenantId(); - var existing = await categoryRepository.FindByIdAsync(request.CategoryId, tenantId, cancellationToken); + // 1. 查询类目 + var existing = await categoryRepository.FindByIdAsync(request.CategoryId, request.TenantId, cancellationToken); if (existing == null) { return false; } - // 2. 删除并保存 + // 2. (空行后) 删除并保存 await categoryRepository.RemoveAsync(existing, cancellationToken); await categoryRepository.SaveChangesAsync(cancellationToken); return true; diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCommandHandler.cs index c79f74f..eb33414 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/DeleteMerchantCommandHandler.cs @@ -2,7 +2,6 @@ using MediatR; using Microsoft.Extensions.Logging; using TakeoutSaaS.Application.App.Merchants.Commands; using TakeoutSaaS.Domain.Merchants.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -11,23 +10,21 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// public sealed class DeleteMerchantCommandHandler( IMerchantRepository merchantRepository, - ITenantProvider tenantProvider, ILogger logger) : IRequestHandler { /// public async Task Handle(DeleteMerchantCommand request, CancellationToken cancellationToken) { - // 1. 校验存在性 - var tenantId = tenantProvider.GetCurrentTenantId(); - var existing = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken); + // 1. 校验存在性(跨租户) + var existing = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); if (existing == null) { return false; } - // 2. 删除 - await merchantRepository.DeleteMerchantAsync(request.MerchantId, tenantId, cancellationToken); + // 2. (空行后) 删除 + await merchantRepository.DeleteMerchantAsync(request.MerchantId, existing.TenantId, cancellationToken); await merchantRepository.SaveChangesAsync(cancellationToken); logger.LogInformation("删除商户 {MerchantId}", request.MerchantId); diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ExportMerchantPdfQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ExportMerchantPdfQueryHandler.cs index 4519892..83b2cfa 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ExportMerchantPdfQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ExportMerchantPdfQueryHandler.cs @@ -1,15 +1,11 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Queries; -using TakeoutSaaS.Application.Identity; -using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Domain.Merchants.Services; using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -20,36 +16,24 @@ public sealed class ExportMerchantPdfQueryHandler( IMerchantRepository merchantRepository, IStoreRepository storeRepository, ITenantRepository tenantRepository, - IMerchantExportService exportService, - ITenantProvider tenantProvider, - ICurrentUserAccessor currentUserAccessor, - IAdminAuthService adminAuthService) + IMerchantExportService exportService) : IRequestHandler { public async Task Handle(ExportMerchantPdfQuery request, CancellationToken cancellationToken) { - var currentTenantId = tenantProvider.GetCurrentTenantId(); - var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken); - var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile); - - var merchant = isSuperAdmin - ? await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) - : await merchantRepository.FindByIdAsync(request.MerchantId, currentTenantId, cancellationToken); - + // 1. 查询商户(跨租户) + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); if (merchant == null) { throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); } - if (!isSuperAdmin && merchant.TenantId != currentTenantId) - { - throw new BusinessException(ErrorCodes.Forbidden, "禁止导出其他租户商户"); - } - + // 2. (空行后) 查询关联数据 var stores = await storeRepository.GetByMerchantIdAsync(merchant.Id, merchant.TenantId, cancellationToken); var auditLogs = await merchantRepository.GetAuditLogsAsync(merchant.Id, merchant.TenantId, cancellationToken); var tenant = await tenantRepository.FindByIdAsync(merchant.TenantId, cancellationToken); + // 3. (空行后) 导出 PDF return await exportService.ExportToPdfAsync(merchant, tenant?.Name, stores, auditLogs, cancellationToken); } } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditHistoryQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditHistoryQueryHandler.cs index 905cb54..01ab3b3 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditHistoryQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditHistoryQueryHandler.cs @@ -1,13 +1,9 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; -using TakeoutSaaS.Application.Identity; -using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -15,10 +11,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 商户审核历史处理器。 /// public sealed class GetMerchantAuditHistoryQueryHandler( - IMerchantRepository merchantRepository, - ITenantProvider tenantProvider, - ICurrentUserAccessor currentUserAccessor, - IAdminAuthService adminAuthService) + IMerchantRepository merchantRepository) : IRequestHandler> { /// @@ -26,24 +19,14 @@ public sealed class GetMerchantAuditHistoryQueryHandler( GetMerchantAuditHistoryQuery request, CancellationToken cancellationToken) { - var currentTenantId = tenantProvider.GetCurrentTenantId(); - var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken); - var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile); - - var merchant = isSuperAdmin - ? await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) - : await merchantRepository.FindByIdAsync(request.MerchantId, currentTenantId, cancellationToken); - + // 1. 查询商户(跨租户) + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); if (merchant == null) { throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); } - if (!isSuperAdmin && merchant.TenantId != currentTenantId) - { - throw new BusinessException(ErrorCodes.Forbidden, "禁止访问其他租户的商户审核历史"); - } - + // 2. (空行后) 查询审核历史 var logs = await merchantRepository.GetAuditLogsAsync(merchant.Id, merchant.TenantId, cancellationToken); return logs.Select(MerchantMapping.ToDto).ToList(); } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditLogsQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditLogsQueryHandler.cs index c14a842..dd53cb2 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditLogsQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantAuditLogsQueryHandler.cs @@ -3,7 +3,6 @@ using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -11,8 +10,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 读取商户审核日志。 /// public sealed class GetMerchantAuditLogsQueryHandler( - IMerchantRepository merchantRepository, - ITenantProvider tenantProvider) + IMerchantRepository merchantRepository) : IRequestHandler> { /// @@ -23,19 +21,25 @@ public sealed class GetMerchantAuditLogsQueryHandler( /// 分页结果。 public async Task> Handle(GetMerchantAuditLogsQuery request, CancellationToken cancellationToken) { - // 1. 获取租户上下文并查询日志 - var tenantId = tenantProvider.GetCurrentTenantId(); - var logs = await merchantRepository.GetAuditLogsAsync(request.MerchantId, tenantId, cancellationToken); + // 1. 查询商户并解析租户 + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); + if (merchant is null) + { + return new PagedResult([], request.Page, request.PageSize, 0); + } + + // 2. (空行后) 查询日志 + var logs = await merchantRepository.GetAuditLogsAsync(request.MerchantId, merchant.TenantId, cancellationToken); var total = logs.Count; - // 2. 分页映射 + // 3. (空行后) 分页映射 var paged = logs .Skip((request.Page - 1) * request.PageSize) .Take(request.PageSize) .Select(MerchantMapping.ToDto) .ToList(); - // 3. 返回结果 + // 4. (空行后) 返回结果 return new PagedResult(paged, request.Page, request.PageSize, total); } } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantByIdQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantByIdQueryHandler.cs index 8272c6c..4611d9c 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantByIdQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantByIdQueryHandler.cs @@ -2,28 +2,26 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; using TakeoutSaaS.Domain.Merchants.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// /// 获取商户详情查询处理器。 /// -public sealed class GetMerchantByIdQueryHandler(IMerchantRepository merchantRepository, ITenantProvider tenantProvider) +public sealed class GetMerchantByIdQueryHandler(IMerchantRepository merchantRepository) : IRequestHandler { /// public async Task Handle(GetMerchantByIdQuery request, CancellationToken cancellationToken) { - // 1. 获取租户上下文 - var tenantId = tenantProvider.GetCurrentTenantId(); - var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken); + // 1. 查询商户(跨租户) + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); if (merchant == null) { return null; } - // 2. 返回 DTO + // 2. (空行后) 返回 DTO return new MerchantDto { Id = merchant.Id, diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantCategoriesQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantCategoriesQueryHandler.cs index 4cadf78..d999f1f 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantCategoriesQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantCategoriesQueryHandler.cs @@ -1,7 +1,6 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Queries; using TakeoutSaaS.Domain.Merchants.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -9,8 +8,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 读取可选类目。 /// public sealed class GetMerchantCategoriesQueryHandler( - IMerchantCategoryRepository categoryRepository, - ITenantProvider tenantProvider) + IMerchantCategoryRepository categoryRepository) : IRequestHandler> { /// @@ -21,11 +19,10 @@ public sealed class GetMerchantCategoriesQueryHandler( /// 类目名称集合。 public async Task> Handle(GetMerchantCategoriesQuery request, CancellationToken cancellationToken) { - // 1. 获取租户上下文并读取类目 - var tenantId = tenantProvider.GetCurrentTenantId(); - var categories = await categoryRepository.ListAsync(tenantId, cancellationToken); + // 1. 读取类目列表 + var categories = await categoryRepository.ListAsync(request.TenantId, cancellationToken); - // 2. 过滤启用类目并去重 + // 2. (空行后) 过滤启用类目并去重 return categories .Where(x => x.IsActive) .Select(x => x.Name.Trim()) diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantChangeHistoryQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantChangeHistoryQueryHandler.cs index 35d3be5..e2605fb 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantChangeHistoryQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantChangeHistoryQueryHandler.cs @@ -1,13 +1,9 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; -using TakeoutSaaS.Application.Identity; -using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -15,10 +11,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 商户变更历史处理器。 /// public sealed class GetMerchantChangeHistoryQueryHandler( - IMerchantRepository merchantRepository, - ITenantProvider tenantProvider, - ICurrentUserAccessor currentUserAccessor, - IAdminAuthService adminAuthService) + IMerchantRepository merchantRepository) : IRequestHandler> { /// @@ -26,24 +19,14 @@ public sealed class GetMerchantChangeHistoryQueryHandler( GetMerchantChangeHistoryQuery request, CancellationToken cancellationToken) { - var currentTenantId = tenantProvider.GetCurrentTenantId(); - var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken); - var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile); - - var merchant = isSuperAdmin - ? await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) - : await merchantRepository.FindByIdAsync(request.MerchantId, currentTenantId, cancellationToken); - + // 1. 查询商户(跨租户) + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); if (merchant == null) { throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); } - if (!isSuperAdmin && merchant.TenantId != currentTenantId) - { - throw new BusinessException(ErrorCodes.Forbidden, "禁止访问其他租户的商户变更历史"); - } - + // 2. (空行后) 查询变更历史 var logs = await merchantRepository.GetChangeLogsAsync(merchant.Id, merchant.TenantId, request.FieldName, cancellationToken); return logs.Select(MerchantMapping.ToDto).ToList(); } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantContractsQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantContractsQueryHandler.cs index d4aab9d..2360300 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantContractsQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantContractsQueryHandler.cs @@ -4,7 +4,6 @@ using TakeoutSaaS.Application.App.Merchants.Queries; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -12,8 +11,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 查询合同列表。 /// public sealed class GetMerchantContractsQueryHandler( - IMerchantRepository merchantRepository, - ITenantProvider tenantProvider) + IMerchantRepository merchantRepository) : IRequestHandler> { /// @@ -24,13 +22,12 @@ public sealed class GetMerchantContractsQueryHandler( /// 合同 DTO 列表。 public async Task> Handle(GetMerchantContractsQuery request, CancellationToken cancellationToken) { - // 1. 获取租户上下文并校验商户存在 - var tenantId = tenantProvider.GetCurrentTenantId(); - _ = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken) + // 1. 校验商户存在并解析租户 + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); - // 2. 查询合同列表 - var contracts = await merchantRepository.GetContractsAsync(request.MerchantId, tenantId, cancellationToken); + // 2. (空行后) 查询合同列表 + var contracts = await merchantRepository.GetContractsAsync(request.MerchantId, merchant.TenantId, cancellationToken); return MerchantMapping.ToContractDtos(contracts); } } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDetailQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDetailQueryHandler.cs index 69a6bcf..3f46b53 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDetailQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDetailQueryHandler.cs @@ -1,15 +1,11 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; -using TakeoutSaaS.Application.Identity; -using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -19,10 +15,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; public sealed class GetMerchantDetailQueryHandler( IMerchantRepository merchantRepository, IStoreRepository storeRepository, - ITenantRepository tenantRepository, - ITenantProvider tenantProvider, - ICurrentUserAccessor currentUserAccessor, - IAdminAuthService adminAuthService) + ITenantRepository tenantRepository) : IRequestHandler { /// @@ -33,31 +26,19 @@ public sealed class GetMerchantDetailQueryHandler( /// 商户详情 DTO。 public async Task Handle(GetMerchantDetailQuery request, CancellationToken cancellationToken) { - // 1. 获取权限与商户 - var currentTenantId = tenantProvider.GetCurrentTenantId(); - var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken); - var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile); - - var merchant = isSuperAdmin - ? await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) - : await merchantRepository.FindByIdAsync(request.MerchantId, currentTenantId, cancellationToken); - + // 1. 查询商户(跨租户) + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); if (merchant == null) { throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); } - if (!isSuperAdmin && merchant.TenantId != currentTenantId) - { - throw new BusinessException(ErrorCodes.Forbidden, "禁止访问其他租户的商户"); - } - - // 2. 查询门店与租户信息 + // 2. (空行后) 查询门店与租户信息 var stores = await storeRepository.GetByMerchantIdAsync(merchant.Id, merchant.TenantId, cancellationToken); var storeDtos = MerchantMapping.ToStoreDtos(stores); var tenant = await tenantRepository.FindByIdAsync(merchant.TenantId, cancellationToken); - // 3. 返回明细 DTO + // 3. (空行后) 返回明细 DTO return MerchantMapping.ToDetailDto(merchant, tenant?.Name, storeDtos); } } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDocumentsQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDocumentsQueryHandler.cs index df32509..ad4e21b 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDocumentsQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantDocumentsQueryHandler.cs @@ -4,7 +4,6 @@ using TakeoutSaaS.Application.App.Merchants.Queries; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -12,8 +11,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 查询证照列表。 /// public sealed class GetMerchantDocumentsQueryHandler( - IMerchantRepository merchantRepository, - ITenantProvider tenantProvider) + IMerchantRepository merchantRepository) : IRequestHandler> { /// @@ -24,13 +22,12 @@ public sealed class GetMerchantDocumentsQueryHandler( /// 证照 DTO 列表。 public async Task> Handle(GetMerchantDocumentsQuery request, CancellationToken cancellationToken) { - // 1. 获取租户上下文并校验商户存在 - var tenantId = tenantProvider.GetCurrentTenantId(); - _ = await merchantRepository.FindByIdAsync(request.MerchantId, tenantId, cancellationToken) + // 1. 校验商户存在并解析租户 + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); - // 2. 查询证照列表 - var documents = await merchantRepository.GetDocumentsAsync(request.MerchantId, tenantId, cancellationToken); + // 2. (空行后) 查询证照列表 + var documents = await merchantRepository.GetDocumentsAsync(request.MerchantId, merchant.TenantId, cancellationToken); return MerchantMapping.ToDocumentDtos(documents); } } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantListQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantListQueryHandler.cs index 4d0018e..3374f23 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantListQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/GetMerchantListQueryHandler.cs @@ -1,16 +1,10 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; -using TakeoutSaaS.Application.Identity; -using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Domain.Stores.Repositories; using TakeoutSaaS.Domain.Tenants.Repositories; -using TakeoutSaaS.Shared.Abstractions.Constants; -using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -20,10 +14,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; public sealed class GetMerchantListQueryHandler( IMerchantRepository merchantRepository, IStoreRepository storeRepository, - ITenantRepository tenantRepository, - ITenantProvider tenantProvider, - ICurrentUserAccessor currentUserAccessor, - IAdminAuthService adminAuthService) + ITenantRepository tenantRepository) : IRequestHandler> { /// @@ -31,21 +22,9 @@ public sealed class GetMerchantListQueryHandler( GetMerchantListQuery request, CancellationToken cancellationToken) { - // 1. 校验跨租户访问权限 - var currentTenantId = tenantProvider.GetCurrentTenantId(); - var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken); - var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile); - - if (!isSuperAdmin && request.TenantId.HasValue && request.TenantId.Value != currentTenantId) - { - throw new BusinessException(ErrorCodes.Forbidden, "禁止跨租户查询商户"); - } - - var effectiveTenantId = isSuperAdmin ? request.TenantId : currentTenantId; - - // 2. 查询商户列表 + // 1. 查询商户列表 var merchants = await merchantRepository.SearchAsync( - effectiveTenantId, + request.TenantId, request.Status, request.OperatingMode, request.Keyword, @@ -56,7 +35,7 @@ public sealed class GetMerchantListQueryHandler( return new PagedResult(Array.Empty(), request.Page, request.PageSize, 0); } - // 3. 排序 & 分页 + // 2. (空行后) 排序 & 分页 var sorted = ApplySorting(merchants, request.SortBy, request.SortOrder); var total = sorted.Count; var paged = sorted @@ -69,16 +48,16 @@ public sealed class GetMerchantListQueryHandler( return new PagedResult(Array.Empty(), request.Page, request.PageSize, total); } - // 4. 批量查询租户名称 + // 3. (空行后) 批量查询租户名称 var tenantIds = paged.Select(x => x.TenantId).Distinct().ToArray(); var tenants = await tenantRepository.FindByIdsAsync(tenantIds, cancellationToken); var tenantLookup = tenants.ToDictionary(x => x.Id, x => x.Name); - // 5. 批量查询门店数量 + // 4. (空行后) 批量查询门店数量 var merchantIds = paged.Select(x => x.Id).ToArray(); - var storeCounts = await storeRepository.GetStoreCountsAsync(effectiveTenantId, merchantIds, cancellationToken); + var storeCounts = await storeRepository.GetStoreCountsAsync(request.TenantId, merchantIds, cancellationToken); - // 6. 组装 DTO + // 5. (空行后) 组装 DTO var items = paged.Select(merchant => { var tenantName = tenantLookup.TryGetValue(merchant.TenantId, out var name) ? name : null; diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ListMerchantCategoriesQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ListMerchantCategoriesQueryHandler.cs index 04c46ac..0e93148 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ListMerchantCategoriesQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ListMerchantCategoriesQueryHandler.cs @@ -2,7 +2,6 @@ using MediatR; using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; using TakeoutSaaS.Domain.Merchants.Repositories; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -10,8 +9,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 列出类目。 /// public sealed class ListMerchantCategoriesQueryHandler( - IMerchantCategoryRepository categoryRepository, - ITenantProvider tenantProvider) + IMerchantCategoryRepository categoryRepository) : IRequestHandler> { /// @@ -22,11 +20,10 @@ public sealed class ListMerchantCategoriesQueryHandler( /// 类目 DTO 列表。 public async Task> Handle(ListMerchantCategoriesQuery request, CancellationToken cancellationToken) { - // 1. 获取租户上下文 - var tenantId = tenantProvider.GetCurrentTenantId(); - var categories = await categoryRepository.ListAsync(tenantId, cancellationToken); + // 1. 查询类目列表 + var categories = await categoryRepository.ListAsync(request.TenantId, cancellationToken); - // 2. 映射 DTO + // 2. (空行后) 映射 DTO return MerchantMapping.ToCategoryDtos(categories); } } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReorderMerchantCategoriesCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReorderMerchantCategoriesCommandHandler.cs index acd0242..574a32c 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReorderMerchantCategoriesCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReorderMerchantCategoriesCommandHandler.cs @@ -3,7 +3,6 @@ using TakeoutSaaS.Application.App.Merchants.Commands; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -11,8 +10,7 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 类目排序处理器。 /// public sealed class ReorderMerchantCategoriesCommandHandler( - IMerchantCategoryRepository categoryRepository, - ITenantProvider tenantProvider) + IMerchantCategoryRepository categoryRepository) : IRequestHandler { /// @@ -23,12 +21,11 @@ public sealed class ReorderMerchantCategoriesCommandHandler( /// 执行结果。 public async Task Handle(ReorderMerchantCategoriesCommand request, CancellationToken cancellationToken) { - // 1. 获取租户并查询类目 - var tenantId = tenantProvider.GetCurrentTenantId(); - var categories = await categoryRepository.ListAsync(tenantId, cancellationToken); + // 1. 查询类目列表 + var categories = await categoryRepository.ListAsync(request.TenantId, cancellationToken); var map = categories.ToDictionary(x => x.Id); - // 2. 更新排序 + // 2. (空行后) 更新排序 foreach (var item in request.Items) { if (!map.TryGetValue(item.CategoryId, out var category)) @@ -39,7 +36,7 @@ public sealed class ReorderMerchantCategoriesCommandHandler( category.DisplayOrder = item.DisplayOrder; } - // 3. 持久化 + // 3. (空行后) 持久化 await categoryRepository.UpdateRangeAsync(map.Values, cancellationToken); await categoryRepository.SaveChangesAsync(cancellationToken); return true; diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReviewMerchantDocumentCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReviewMerchantDocumentCommandHandler.cs index a8a037f..9f70ab0 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReviewMerchantDocumentCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/ReviewMerchantDocumentCommandHandler.cs @@ -7,7 +7,6 @@ using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -16,7 +15,6 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// public sealed class ReviewMerchantDocumentCommandHandler( IMerchantRepository merchantRepository, - ITenantProvider tenantProvider, ICurrentUserAccessor currentUserAccessor) : IRequestHandler { @@ -28,23 +26,27 @@ public sealed class ReviewMerchantDocumentCommandHandler( /// 证照 DTO。 public async Task Handle(ReviewMerchantDocumentCommand request, CancellationToken cancellationToken) { - // 1. 读取证照 - var tenantId = tenantProvider.GetCurrentTenantId(); + // 1. 查询商户并解析租户 + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) + ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); + var tenantId = merchant.TenantId; + + // 2. (空行后) 读取证照 var document = await merchantRepository.FindDocumentByIdAsync(request.MerchantId, tenantId, request.DocumentId, cancellationToken) ?? throw new BusinessException(ErrorCodes.NotFound, "证照不存在"); - // 2. 若状态无变化且备注相同,直接返回 + // 3. (空行后) 若状态无变化且备注相同,直接返回 var targetStatus = request.Approve ? MerchantDocumentStatus.Approved : MerchantDocumentStatus.Rejected; if (document.Status == targetStatus && document.Remarks == request.Remarks) { return MerchantMapping.ToDto(document); } - // 3. 更新状态 + // 4. (空行后) 更新状态 document.Status = targetStatus; document.Remarks = request.Remarks; - // 4. 持久化与审计 + // 5. (空行后) 持久化与审计 await merchantRepository.UpdateDocumentAsync(document, cancellationToken); await merchantRepository.AddAuditLogAsync(new MerchantAuditLog { @@ -58,7 +60,7 @@ public sealed class ReviewMerchantDocumentCommandHandler( }, cancellationToken); await merchantRepository.SaveChangesAsync(cancellationToken); - // 5. 返回 DTO + // 6. (空行后) 返回 DTO return MerchantMapping.ToDto(document); } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/SearchMerchantsQueryHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/SearchMerchantsQueryHandler.cs index b545129..9ea6300 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/SearchMerchantsQueryHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/SearchMerchantsQueryHandler.cs @@ -3,7 +3,6 @@ using TakeoutSaaS.Application.App.Merchants.Dto; using TakeoutSaaS.Application.App.Merchants.Queries; using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -11,25 +10,28 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// 商户列表查询处理器。 /// public sealed class SearchMerchantsQueryHandler( - IMerchantRepository merchantRepository, - ITenantProvider tenantProvider) + IMerchantRepository merchantRepository) : IRequestHandler> { /// public async Task> Handle(SearchMerchantsQuery request, CancellationToken cancellationToken) { - // 1. 获取租户并查询商户 - var tenantId = tenantProvider.GetCurrentTenantId(); - var merchants = await merchantRepository.SearchAsync(tenantId, request.Status, cancellationToken); + // 1. 查询商户列表(可选租户过滤) + var merchants = await merchantRepository.SearchAsync( + request.TenantId, + request.Status, + operatingMode: null, + keyword: null, + cancellationToken); - // 2. 排序与分页 + // 2. (空行后) 排序与分页 var sorted = ApplySorting(merchants, request.SortBy, request.SortDescending); var paged = sorted .Skip((request.Page - 1) * request.PageSize) .Take(request.PageSize) .ToList(); - // 3. 映射 DTO + // 3. (空行后) 映射 DTO var items = paged.Select(merchant => new MerchantDto { Id = merchant.Id, @@ -45,7 +47,7 @@ public sealed class SearchMerchantsQueryHandler( CreatedAt = merchant.CreatedAt }).ToList(); - // 4. 返回分页结果 + // 4. (空行后) 返回分页结果 return new PagedResult(items, request.Page, request.PageSize, merchants.Count); } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantCommandHandler.cs index 4626003..3657c69 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantCommandHandler.cs @@ -2,8 +2,6 @@ using MediatR; using Microsoft.Extensions.Logging; using TakeoutSaaS.Application.App.Merchants.Commands; using TakeoutSaaS.Application.App.Merchants.Dto; -using TakeoutSaaS.Application.Identity; -using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Domain.Merchants.Entities; using TakeoutSaaS.Domain.Merchants.Enums; using TakeoutSaaS.Domain.Merchants.Repositories; @@ -12,7 +10,6 @@ using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -23,9 +20,7 @@ public sealed class UpdateMerchantCommandHandler( IMerchantRepository merchantRepository, IStoreRepository storeRepository, ITenantRepository tenantRepository, - ITenantProvider tenantProvider, ICurrentUserAccessor currentUserAccessor, - IAdminAuthService adminAuthService, ILogger logger) : IRequestHandler { @@ -37,27 +32,15 @@ public sealed class UpdateMerchantCommandHandler( throw new BusinessException(ErrorCodes.ValidationFailed, "RowVersion 不能为空"); } - // 1. 获取操作者权限 - var currentTenantId = tenantProvider.GetCurrentTenantId(); - var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken); - var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile); - - // 2. 读取商户信息 - var merchant = isSuperAdmin - ? await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) - : await merchantRepository.FindByIdAsync(request.MerchantId, currentTenantId, cancellationToken); + // 1. 读取商户信息(跨租户) + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken); if (merchant == null) { return null; } - if (!isSuperAdmin && merchant.TenantId != currentTenantId) - { - return null; - } - - // 3. 规范化输入 + // 2. (空行后) 规范化输入 var name = NormalizeRequired(request.Name, "商户名称"); var contactPhone = NormalizeRequired(request.ContactPhone, "联系电话"); var licenseNumber = NormalizeOptional(request.LicenseNumber); @@ -78,7 +61,7 @@ public sealed class UpdateMerchantCommandHandler( TrackChange("contactPhone", merchant.ContactPhone, contactPhone, isCritical: false); TrackChange("contactEmail", merchant.ContactEmail, contactEmail, isCritical: false); - // 4. 写入字段 + // 3. (空行后) 写入字段 merchant.BrandName = name; merchant.BusinessLicenseNumber = licenseNumber; merchant.LegalPerson = legalRepresentative; @@ -103,7 +86,7 @@ public sealed class UpdateMerchantCommandHandler( merchant.FrozenAt = null; } - // 5. 持久化日志与数据 + // 4. (空行后) 持久化日志与数据 await merchantRepository.UpdateMerchantAsync(merchant, cancellationToken); foreach (var log in changes) { @@ -135,7 +118,7 @@ public sealed class UpdateMerchantCommandHandler( logger.LogInformation("更新商户 {MerchantId} - {Name}", merchant.Id, merchant.BrandName); - // 6. 返回更新结果 + // 5. (空行后) 返回更新结果 var stores = await storeRepository.GetByMerchantIdAsync(merchant.Id, merchant.TenantId, cancellationToken); var tenant = await tenantRepository.FindByIdAsync(merchant.TenantId, cancellationToken); var detail = MerchantMapping.ToDetailDto(merchant, tenant?.Name, MerchantMapping.ToStoreDtos(stores)); diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantContractStatusCommandHandler.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantContractStatusCommandHandler.cs index 1fc4707..533aeb0 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantContractStatusCommandHandler.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Handlers/UpdateMerchantContractStatusCommandHandler.cs @@ -7,7 +7,6 @@ using TakeoutSaaS.Domain.Merchants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Merchants.Handlers; @@ -16,7 +15,6 @@ namespace TakeoutSaaS.Application.App.Merchants.Handlers; /// public sealed class UpdateMerchantContractStatusCommandHandler( IMerchantRepository merchantRepository, - ITenantProvider tenantProvider, ICurrentUserAccessor currentUserAccessor) : IRequestHandler { @@ -28,12 +26,16 @@ public sealed class UpdateMerchantContractStatusCommandHandler( /// 合同 DTO。 public async Task Handle(UpdateMerchantContractStatusCommand request, CancellationToken cancellationToken) { - // 1. 查询合同 - var tenantId = tenantProvider.GetCurrentTenantId(); + // 1. 查询商户并解析租户 + var merchant = await merchantRepository.FindByIdAsync(request.MerchantId, cancellationToken) + ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在"); + var tenantId = merchant.TenantId; + + // 2. (空行后) 查询合同 var contract = await merchantRepository.FindContractByIdAsync(request.MerchantId, tenantId, request.ContractId, cancellationToken) ?? throw new BusinessException(ErrorCodes.NotFound, "合同不存在"); - // 2. 更新状态 + // 3. (空行后) 更新状态 if (request.Status == ContractStatus.Active) { contract.Status = ContractStatus.Active; @@ -50,7 +52,7 @@ public sealed class UpdateMerchantContractStatusCommandHandler( contract.Status = request.Status; } - // 3. 持久化与审计 + // 4. (空行后) 持久化与审计 await merchantRepository.UpdateContractAsync(contract, cancellationToken); await merchantRepository.AddAuditLogAsync(new MerchantAuditLog { diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/GetMerchantCategoriesQuery.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/GetMerchantCategoriesQuery.cs index 558bcc6..fd89f6b 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/GetMerchantCategoriesQuery.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/GetMerchantCategoriesQuery.cs @@ -5,4 +5,4 @@ namespace TakeoutSaaS.Application.App.Merchants.Queries; /// /// 获取商户可选类目。 /// -public sealed record GetMerchantCategoriesQuery() : IRequest>; +public sealed record GetMerchantCategoriesQuery(long TenantId) : IRequest>; diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/ListMerchantCategoriesQuery.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/ListMerchantCategoriesQuery.cs index 5fa29e9..4f5e9c9 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/ListMerchantCategoriesQuery.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/ListMerchantCategoriesQuery.cs @@ -6,4 +6,10 @@ namespace TakeoutSaaS.Application.App.Merchants.Queries; /// /// 管理端获取完整类目列表。 /// -public sealed record ListMerchantCategoriesQuery() : IRequest>; +public sealed record ListMerchantCategoriesQuery : IRequest> +{ + /// + /// 租户 ID。 + /// + public long TenantId { get; init; } +} diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/SearchMerchantsQuery.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/SearchMerchantsQuery.cs index b3ca969..edd0045 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/SearchMerchantsQuery.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Queries/SearchMerchantsQuery.cs @@ -10,6 +10,11 @@ namespace TakeoutSaaS.Application.App.Merchants.Queries; /// public sealed class SearchMerchantsQuery : IRequest> { + /// + /// 租户过滤(为空表示跨租户查询)。 + /// + public long? TenantId { get; init; } + /// /// 按状态过滤。 ///