using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.ComponentModel.DataAnnotations; 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] SearchTenantBillsQuery query, CancellationToken cancellationToken) { // 1. 绑定租户标识 query = query with { TenantId = tenantId }; // 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); } }