using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Tiku.Api.Contracts; using Tiku.Application.PlatformAdmin; using Tiku.Application.Security; using Tiku.Domain.Platform; namespace Tiku.Api.Controllers; [ApiController] [Authorize(Policy = BackendPermissions.PlatformDashboardView)] [Produces("application/json")] [Route("api/platform-admin")] public sealed class PlatformAdminController( IPlatformAdminService platformAdminService, ICurrentUser currentUser) : ControllerBase { [HttpGet("overview")] [EndpointSummary("查询平台经营概览")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Overview(CancellationToken cancellationToken) { return Ok(await platformAdminService.GetOverviewAsync(ResolveActor(), cancellationToken)); } [HttpGet("tenants")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("查询平台租户列表")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Tenants( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetTenantsAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpPost("tenants")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("创建平台租户")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> CreateTenant( CreatePlatformTenantDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.CreateTenantAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("tenants/detail")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("查询平台租户详情")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> TenantDetail( [FromQuery] Guid tenantId, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetTenantDetailAsync(ResolveActor(), tenantId, cancellationToken)); } [HttpPatch("tenants/status")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("更新租户业务与账务状态")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> TenantStatus( UpdatePlatformTenantStatusDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpdateTenantStatusAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpPut("tenants/billing-profile")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("保存租户账务与开票资料")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> BillingProfile( UpsertPlatformTenantBillingProfileDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpsertTenantBillingProfileAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("plans")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("查询平台 SaaS 套餐")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Plans( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetPlansAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpPut("plans/{planCode}/modules")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("替换 SaaS 套餐模块权益")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> ReplacePlanModules( string planCode, ReplacePlatformPlanModulesDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.ReplacePlanModulesAsync( ResolveActor(), request.ToCommand(planCode), cancellationToken)); } [HttpPost("subscriptions")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("创建或调整租户订阅")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertSubscription( UpsertPlatformSubscriptionDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpsertSubscriptionAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpPut("tenants/{tenantId:guid}/module-overrides/{moduleCode}")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("设置租户模块覆盖")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertTenantModuleOverride( Guid tenantId, string moduleCode, UpsertPlatformTenantModuleOverrideDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpsertTenantModuleOverrideAsync( ResolveActor(), request.ToCommand(tenantId, moduleCode), cancellationToken)); } [HttpGet("domains")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("查询租户域名状态")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Domains( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetDomainsAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpPost("domains/{domainId:guid}/recheck")] [Authorize(Policy = BackendPermissions.PlatformTenantManage)] [EndpointSummary("重新触发租户域名 DNS/TLS 验证")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> RecheckDomain( Guid domainId, CancellationToken cancellationToken) { return Ok(await platformAdminService.RecheckDomainAsync(ResolveActor(), domainId, cancellationToken)); } [HttpGet("staff")] [Authorize(Policy = BackendPermissions.PlatformStaffManage)] [EndpointSummary("查询平台员工列表")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> Staff( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetStaffAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpPut("staff")] [Authorize(Policy = BackendPermissions.PlatformStaffManage)] [EndpointSummary("创建或更新平台员工")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertStaff( UpsertPlatformStaffDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpsertStaffAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpPatch("staff/status")] [Authorize(Policy = BackendPermissions.PlatformStaffManage)] [EndpointSummary("启用或禁用平台员工")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> StaffStatus( UpdatePlatformStaffStatusDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpdateStaffStatusAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("audit-logs")] [Authorize(Policy = BackendPermissions.PlatformAuditView)] [EndpointSummary("查询平台审计日志")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> AuditLogs( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetAuditLogsAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpGet("audit-alerts")] [Authorize(Policy = BackendPermissions.PlatformAuditView)] [EndpointSummary("查询平台审计告警")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> AuditAlerts( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetAuditAlertsAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpPost("audit-alerts/status")] [Authorize(Policy = BackendPermissions.PlatformAuditView)] [EndpointSummary("更新平台审计告警状态")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> AuditAlertStatus( UpdatePlatformAuditAlertStatusDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpdateAuditAlertStatusAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("dunning-notification-channels")] [Authorize(Policy = BackendPermissions.PlatformBillingNotification)] [EndpointSummary("查询平台催缴通知渠道")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> DunningChannels( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetDunningChannelsAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpPut("dunning-notification-channels")] [Authorize(Policy = BackendPermissions.PlatformBillingNotification)] [EndpointSummary("创建或更新平台催缴通知渠道")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> UpsertDunningChannel( UpsertPlatformDunningChannelDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.UpsertDunningChannelAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpPost("dunning-notification-channels/disable")] [Authorize(Policy = BackendPermissions.PlatformBillingNotification)] [EndpointSummary("禁用平台催缴通知渠道")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> DisableDunningChannel( DisablePlatformDunningChannelDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.DisableDunningChannelAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } [HttpGet("dunning-notification-events")] [Authorize(Policy = BackendPermissions.PlatformBillingNotification)] [EndpointSummary("查询平台催缴通知事件")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> DunningEvents( [FromQuery] PlatformAdminQueryDto query, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetDunningEventsAsync(ResolveActor(), query.ToQuery(), cancellationToken)); } [HttpGet("dunning-notification-events/detail")] [Authorize(Policy = BackendPermissions.PlatformBillingNotification)] [EndpointSummary("查询平台催缴通知事件详情")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> DunningEventDetail( [FromQuery] Guid eventId, CancellationToken cancellationToken) { return Ok(await platformAdminService.GetDunningEventDetailAsync(ResolveActor(), eventId, cancellationToken)); } [HttpPost("dunning-notification-events/retry")] [Authorize(Policy = BackendPermissions.PlatformBillingNotification)] [EndpointSummary("重新标记平台催缴通知事件待发送")] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> RetryDunningEvent( RetryPlatformDunningEventDto request, CancellationToken cancellationToken) { return Ok(await platformAdminService.RetryDunningEventAsync(ResolveActor(), request.ToCommand(), cancellationToken)); } private PlatformAdminActor ResolveActor() { if (currentUser.UserId is not { } userId) { throw new PlatformAdminException("Platform admin actor was not resolved.", "platform_access_denied"); } return new PlatformAdminActor(userId); } }