From b2678a27bac045888a7a655464baeef4c82ceeb3 Mon Sep 17 00:00:00 2001 From: MSuMshk <2039814060@qq.com> Date: Fri, 30 Jan 2026 01:13:43 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E7=A7=9F?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E6=8E=A7=E5=88=B6=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DictionaryLabelOverridesController.cs | 83 +-------- .../DictionaryOverridesController.cs | 150 ---------------- .../Controllers/TenantBillingsController.cs | 107 ----------- .../TenantNotificationsController.cs | 58 ------ .../Controllers/TenantRolesController.cs | 168 ------------------ 5 files changed, 1 insertion(+), 565 deletions(-) delete mode 100644 src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryOverridesController.cs delete mode 100644 src/Api/TakeoutSaaS.AdminApi/Controllers/TenantBillingsController.cs delete mode 100644 src/Api/TakeoutSaaS.AdminApi/Controllers/TenantNotificationsController.cs delete mode 100644 src/Api/TakeoutSaaS.AdminApi/Controllers/TenantRolesController.cs diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryLabelOverridesController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryLabelOverridesController.cs index 2f50743..fbc6669 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryLabelOverridesController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryLabelOverridesController.cs @@ -12,7 +12,7 @@ using TakeoutSaaS.Shared.Web.Api; namespace TakeoutSaaS.AdminApi.Controllers; /// -/// 字典标签覆盖管理。 +/// 字典标签覆盖管理(平台端)。 /// [ApiVersion("1.0")] [Authorize] @@ -22,85 +22,6 @@ public sealed class DictionaryLabelOverridesController( ICurrentUserAccessor currentUserAccessor) : BaseApiController { - #region 租户端 API(租户覆盖系统字典) - - /// - /// 获取当前租户的标签覆盖列表。 - /// - [HttpGet("~/api/admin/v{version:apiVersion}/tenants/{tenantId:long}/dictionary/label-overrides")] - [PermissionAuthorize("dictionary:override:read")] - [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - public async Task>> ListTenantOverrides( - long tenantId, - [FromQuery] OverrideType? overrideType, - CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse>.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 查询租户覆盖列表 - var result = await labelOverrideService.GetOverridesAsync(tenantId, overrideType, cancellationToken); - return ApiResponse>.Ok(result); - } - - /// - /// 租户覆盖系统字典项的标签。 - /// - [HttpPost("~/api/admin/v{version:apiVersion}/tenants/{tenantId:long}/dictionary/label-overrides")] - [PermissionAuthorize("dictionary:override:update")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> CreateTenantOverride( - long tenantId, - [FromBody] UpsertLabelOverrideRequest request, - CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 执行租户覆盖 - var operatorId = currentUserAccessor.UserId; - var result = await labelOverrideService.UpsertTenantOverrideAsync(tenantId, request, operatorId, cancellationToken); - return ApiResponse.Ok(result); - } - - /// - /// 租户删除自己的标签覆盖。 - /// - [HttpDelete("~/api/admin/v{version:apiVersion}/tenants/{tenantId:long}/dictionary/label-overrides/{dictionaryItemId:long}")] - [PermissionAuthorize("dictionary:override:delete")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> DeleteTenantOverride(long tenantId, long dictionaryItemId, CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 执行删除 - var operatorId = currentUserAccessor.UserId; - var success = await labelOverrideService.DeleteOverrideAsync( - tenantId, - dictionaryItemId, - operatorId, - allowPlatformEnforcement: false, - cancellationToken); - return success - ? ApiResponse.Success() - : ApiResponse.Error(ErrorCodes.NotFound, "覆盖配置不存在"); - } - - #endregion - - #region 平台端 API(平台管理所有租户的覆盖) - /// /// 获取指定租户的所有标签覆盖(平台管理员用)。 /// @@ -154,6 +75,4 @@ public sealed class DictionaryLabelOverridesController( ? ApiResponse.Success() : ApiResponse.Error(ErrorCodes.NotFound, "覆盖配置不存在"); } - - #endregion } diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryOverridesController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryOverridesController.cs deleted file mode 100644 index 93c8d96..0000000 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryOverridesController.cs +++ /dev/null @@ -1,150 +0,0 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using TakeoutSaaS.Application.Dictionary.Contracts; -using TakeoutSaaS.Application.Dictionary.Models; -using TakeoutSaaS.Application.Dictionary.Services; -using TakeoutSaaS.Module.Authorization.Attributes; -using TakeoutSaaS.Shared.Abstractions.Constants; -using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Web.Api; - -namespace TakeoutSaaS.AdminApi.Controllers; - -/// -/// 租户字典覆盖配置管理。 -/// -[ApiVersion("1.0")] -[Authorize] -[Route("api/admin/v{version:apiVersion}/tenants/{tenantId:long}/dictionary/overrides")] -public sealed class DictionaryOverridesController( - DictionaryOverrideService overrideService) - : BaseApiController -{ - /// - /// 获取当前租户的覆盖配置列表。 - /// - [HttpGet] - [PermissionAuthorize("dictionary:override:read")] - [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - public async Task>> List(long tenantId, CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse>.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 查询覆盖配置 - var result = await overrideService.GetOverridesAsync(tenantId, cancellationToken); - return ApiResponse>.Ok(result); - } - - /// - /// 获取指定字典分组的覆盖配置。 - /// - [HttpGet("{groupCode}")] - [PermissionAuthorize("dictionary:override:read")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> Detail(long tenantId, string groupCode, CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 查询覆盖配置 - var result = await overrideService.GetOverrideAsync(tenantId, groupCode, cancellationToken); - return result == null - ? ApiResponse.Error(ErrorCodes.NotFound, "覆盖配置不存在") - : ApiResponse.Ok(result); - } - - /// - /// 启用覆盖模式。 - /// - [HttpPost("{groupCode}/enable")] - [PermissionAuthorize("dictionary:override:update")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> Enable(long tenantId, string groupCode, CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 启用覆盖模式 - var result = await overrideService.EnableOverrideAsync(tenantId, groupCode, cancellationToken); - return ApiResponse.Ok(result); - } - - /// - /// 禁用覆盖模式。 - /// - [HttpPost("{groupCode}/disable")] - [PermissionAuthorize("dictionary:override:update")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> Disable(long tenantId, string groupCode, CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 禁用覆盖模式 - var success = await overrideService.DisableOverrideAsync(tenantId, groupCode, cancellationToken); - return success - ? ApiResponse.Success() - : ApiResponse.Error(ErrorCodes.NotFound, "覆盖配置不存在"); - } - - /// - /// 更新隐藏的系统字典项。 - /// - [HttpPut("{groupCode}/hidden-items")] - [PermissionAuthorize("dictionary:override:update")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> UpdateHiddenItems( - long tenantId, - string groupCode, - [FromBody] DictionaryOverrideHiddenItemsRequest request, - CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 更新隐藏项 - var result = await overrideService.UpdateHiddenItemsAsync(tenantId, groupCode, request.HiddenItemIds, cancellationToken); - return ApiResponse.Ok(result); - } - - /// - /// 更新自定义排序。 - /// - [HttpPut("{groupCode}/sort-order")] - [PermissionAuthorize("dictionary:override:update")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> UpdateSortOrder( - long tenantId, - string groupCode, - [FromBody] DictionaryOverrideSortOrderRequest request, - CancellationToken cancellationToken) - { - // 1. 校验租户标识 - if (tenantId <= 0) - { - return ApiResponse.Error(StatusCodes.Status400BadRequest, "租户标识无效"); - } - - // 2. (空行后) 更新自定义排序 - var result = await overrideService.UpdateCustomSortOrderAsync(tenantId, groupCode, request.SortOrder, cancellationToken); - return ApiResponse.Ok(result); - } -} diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantBillingsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantBillingsController.cs deleted file mode 100644 index 722e6fe..0000000 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantBillingsController.cs +++ /dev/null @@ -1,107 +0,0 @@ -using MediatR; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System.ComponentModel.DataAnnotations; -using TakeoutSaaS.AdminApi.Contracts.Requests; -using TakeoutSaaS.Application.App.Tenants.Commands; -using TakeoutSaaS.Application.App.Tenants.Dto; -using TakeoutSaaS.Application.App.Tenants.Queries; -using TakeoutSaaS.Module.Authorization.Attributes; -using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Web.Api; - -namespace TakeoutSaaS.AdminApi.Controllers; - -/// -/// 租户账单管理。 -/// -[ApiVersion("1.0")] -[Authorize] -[Route("api/admin/v{version:apiVersion}/tenants/{tenantId:long}/billings")] -public sealed class TenantBillingsController(IMediator mediator) : BaseApiController -{ - /// - /// 分页查询账单。 - /// - /// 租户账单分页结果。 - [HttpGet] - [PermissionAuthorize("tenant-bill:read")] - [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - public async Task>> Search(long tenantId, [FromQuery] SearchTenantBillsRequest request, CancellationToken cancellationToken) - { - // 1. 组装查询对象(TenantId 仅来自路由,避免与 QueryString 重复) - var query = new SearchTenantBillsQuery - { - TenantId = tenantId, - Status = request.Status, - From = request.From, - To = request.To, - Page = request.Page, - PageSize = request.PageSize, - }; - - // 2. 查询账单列表 - var result = await mediator.Send(query, cancellationToken); - - // 3. 返回分页结果 - return ApiResponse>.Ok(result); - } - - /// - /// 账单详情。 - /// - /// 租户账单详情。 - [HttpGet("{billingId:long}")] - [PermissionAuthorize("tenant-bill:read")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> Detail(long tenantId, long billingId, CancellationToken cancellationToken) - { - // 1. 查询账单详情 - var result = await mediator.Send(new GetTenantBillQuery { TenantId = tenantId, BillingId = billingId }, cancellationToken); - - // 2. 返回详情或 404 - return result is null - ? ApiResponse.Error(StatusCodes.Status404NotFound, "账单不存在") - : ApiResponse.Ok(result); - } - - /// - /// 创建账单。 - /// - /// 创建的账单信息。 - [HttpPost] - [PermissionAuthorize("tenant-bill:create")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> Create(long tenantId, [FromBody, Required] CreateTenantBillingCommand command, CancellationToken cancellationToken) - { - // 1. 绑定租户标识 - command = command with { TenantId = tenantId }; - - // 2. 创建账单 - var result = await mediator.Send(command, cancellationToken); - return ApiResponse.Ok(result); - } - - /// - /// 标记账单已支付。 - /// - /// 标记支付后的账单信息。 - [HttpPost("{billingId:long}/pay")] - [PermissionAuthorize("tenant-bill:pay")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> MarkPaid(long tenantId, long billingId, [FromBody, Required] MarkTenantBillingPaidCommand command, CancellationToken cancellationToken) - { - // 1. 绑定租户与账单标识 - command = command with { TenantId = tenantId, BillingId = billingId }; - - // 2. 标记支付状态 - var result = await mediator.Send(command, cancellationToken); - - // 3. 返回结果或 404 - return result is null - ? ApiResponse.Error(StatusCodes.Status404NotFound, "账单不存在") - : ApiResponse.Ok(result); - } -} diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantNotificationsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantNotificationsController.cs deleted file mode 100644 index 18c78ce..0000000 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantNotificationsController.cs +++ /dev/null @@ -1,58 +0,0 @@ -using MediatR; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using TakeoutSaaS.Application.App.Tenants.Commands; -using TakeoutSaaS.Application.App.Tenants.Dto; -using TakeoutSaaS.Application.App.Tenants.Queries; -using TakeoutSaaS.Module.Authorization.Attributes; -using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Web.Api; - -namespace TakeoutSaaS.AdminApi.Controllers; - -/// -/// 租户通知接口。 -/// -[ApiVersion("1.0")] -[Authorize] -[Route("api/admin/v{version:apiVersion}/tenants/{tenantId:long}/notifications")] -public sealed class TenantNotificationsController(IMediator mediator) : BaseApiController -{ - /// - /// 分页查询通知。 - /// - /// 租户通知分页结果。 - [HttpGet] - [PermissionAuthorize("tenant-notification:read")] - [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - public async Task>> Search(long tenantId, [FromQuery] SearchTenantNotificationsQuery query, CancellationToken cancellationToken) - { - // 1. 绑定租户标识 - query = query with { TenantId = tenantId }; - - // 2. 查询通知列表 - var result = await mediator.Send(query, cancellationToken); - - // 3. 返回分页结果 - return ApiResponse>.Ok(result); - } - - /// - /// 标记通知已读。 - /// - /// 标记已读后的通知信息。 - [HttpPost("{notificationId:long}/read")] - [PermissionAuthorize("tenant-notification:update")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> MarkRead(long tenantId, long notificationId, CancellationToken cancellationToken) - { - // 1. 标记通知为已读 - var result = await mediator.Send(new MarkTenantNotificationReadCommand { TenantId = tenantId, NotificationId = notificationId }, cancellationToken); - - // 2. 返回结果或 404 - return result is null - ? ApiResponse.Error(StatusCodes.Status404NotFound, "通知不存在") - : ApiResponse.Ok(result); - } -} diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantRolesController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantRolesController.cs deleted file mode 100644 index d171ab6..0000000 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/TenantRolesController.cs +++ /dev/null @@ -1,168 +0,0 @@ -using MediatR; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using System.ComponentModel.DataAnnotations; -using TakeoutSaaS.Application.Identity.Commands; -using TakeoutSaaS.Application.Identity.Contracts; -using TakeoutSaaS.Application.Identity.Queries; -using TakeoutSaaS.Module.Authorization.Attributes; -using TakeoutSaaS.Shared.Abstractions.Results; -using TakeoutSaaS.Shared.Web.Api; - -namespace TakeoutSaaS.AdminApi.Controllers; - -/// -/// 租户角色管理(实例层)。 -/// -[ApiVersion("1.0")] -[Authorize] -[Route("api/admin/v{version:apiVersion}/tenants/{tenantId:long}/roles")] -public sealed class TenantRolesController(IMediator mediator) : BaseApiController -{ - /// - /// 租户角色分页。 - /// - [HttpGet] - [PermissionAuthorize("identity:role:read")] - [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - public async Task>> List( - long tenantId, - [FromQuery] SearchRolesQuery query, - CancellationToken cancellationToken) - { - // 1. 绑定租户并查询角色分页 - var request = new SearchRolesQuery - { - TenantId = tenantId, - Keyword = query.Keyword, - Page = query.Page, - PageSize = query.PageSize, - SortBy = query.SortBy, - SortDescending = query.SortDescending - }; - var result = await mediator.Send(request, cancellationToken); - - // 2. 返回分页数据 - return ApiResponse>.Ok(result); - } - - /// - /// 角色详情(含权限)。 - /// - [HttpGet("{roleId:long}")] - [PermissionAuthorize("identity:role:read")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> Detail(long tenantId, long roleId, CancellationToken cancellationToken) - { - // 1. 查询角色详情 - var result = await mediator.Send(new RoleDetailQuery { RoleId = roleId, TenantId = tenantId }, cancellationToken); - - // 2. 返回数据或 404 - return result is null - ? ApiResponse.Error(StatusCodes.Status404NotFound, "角色不存在") - : ApiResponse.Ok(result); - } - - /// - /// 创建角色。 - /// - [HttpPost] - [PermissionAuthorize("identity:role:create")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> Create( - long tenantId, - [FromBody, Required] CreateRoleCommand command, - CancellationToken cancellationToken) - { - // 1. 创建角色 - var result = await mediator.Send(command with { TenantId = tenantId }, cancellationToken); - - // 2. 返回创建结果 - return ApiResponse.Ok(result); - } - - /// - /// 更新角色。 - /// - [HttpPut("{roleId:long}")] - [PermissionAuthorize("identity:role:update")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] - public async Task> Update( - long tenantId, - long roleId, - [FromBody, Required] UpdateRoleCommand command, - CancellationToken cancellationToken) - { - // 1. 绑定角色 ID - command = command with { RoleId = roleId, TenantId = tenantId }; - - // 2. 执行更新 - var result = await mediator.Send(command, cancellationToken); - - // 3. 返回结果或 404 - return result is null - ? ApiResponse.Error(StatusCodes.Status404NotFound, "角色不存在") - : ApiResponse.Ok(result); - } - - /// - /// 删除角色。 - /// - [HttpDelete("{roleId:long}")] - [PermissionAuthorize("identity:role:delete")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> Delete(long tenantId, long roleId, CancellationToken cancellationToken) - { - // 1. 执行删除 - var command = new DeleteRoleCommand { RoleId = roleId, TenantId = tenantId }; - var result = await mediator.Send(command, cancellationToken); - - // 2. 返回结果 - return ApiResponse.Ok(result); - } - - /// - /// 获取角色权限列表。 - /// - [HttpGet("{roleId:long}/permissions")] - [PermissionAuthorize("identity:role:read")] - [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status404NotFound)] - public async Task>> GetPermissions( - long tenantId, - long roleId, - CancellationToken cancellationToken) - { - // 1. 查询角色详情并提取权限 - var detail = await mediator.Send(new RoleDetailQuery { RoleId = roleId, TenantId = tenantId }, cancellationToken); - if (detail is null) - { - return ApiResponse>.Error(StatusCodes.Status404NotFound, "角色不存在"); - } - - // 2. 返回权限集合 - return ApiResponse>.Ok(detail.Permissions); - } - - /// - /// 覆盖角色权限。 - /// - [HttpPut("{roleId:long}/permissions")] - [PermissionAuthorize("identity:role:bind-permission")] - [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] - public async Task> BindPermissions( - long tenantId, - long roleId, - [FromBody, Required] BindRolePermissionsCommand command, - CancellationToken cancellationToken) - { - // 1. 绑定角色 ID - command = command with { RoleId = roleId, TenantId = tenantId }; - - // 2. 覆盖授权 - var result = await mediator.Send(command, cancellationToken); - return ApiResponse.Ok(result); - } -}