forked from xiongyuxing/tiku-backend.net
feat: Add tags and endpoint summaries to various controllers for better API documentation
- Added tags to BrowserAuthController for browser authentication endpoints. - Added tags to CatalogController for public catalog access. - Added tags to CommerceController for student transaction operations. - Added tags to CommissionController for tenant commission management. - Added tags to CrmController for tenant CRM functionalities. - Added tags to HealthController for system health checks. - Added tags to LearningController for student learning resources. - Added tags to MeController for current user information. - Added tags to PlatformAdminController for platform management. - Introduced PlatformBackofficeController for backend permissions management. - Added tags to PlatformBillingCallbackController for billing callbacks. - Added tags to PlatformPaymentSettingsController for payment settings management. - Added tags to PlatformSaasController for SaaS package management. - Added tags to PlatformTenantCapabilitiesController for tenant capabilities. - Added tags to PointsController for student points management. - Added tags to ProfileController for student profile management. - Added tags to QuestionVideosController for question video resources. - Added tags to ReferralController for referral growth management. - Added tags to RuntimeController for runtime configurations. - Added tags to ScorelineController for scoreline management. - Added tags to TaxonomyController for category management. - Added tags to TenantAdminDirectController for tenant operations management. - Introduced TenantBackofficeController for tenant backend permissions. - Added tags to TenantBillingController for tenant billing operations. - Added tags to TenantCommerceController for tenant commerce operations. - Added tags to TenantContentController for tenant content management. - Added tags to TenantContentDirectController for direct content management. - Added tags to TenantFrontendConfigController for frontend configurations. - Added tags to TenantOnboardingController for onboarding guidance. - Added tags to TenantPublicController for public tenant configurations. - Added tags to TenantsController for current tenant information. - Added tags to VideosController for student video resources.
This commit is contained in:
@@ -8,166 +8,397 @@ using Tiku.Domain.Tenancy;
|
||||
|
||||
namespace Tiku.Api.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// 平台租户能力通用查询参数。
|
||||
/// </summary>
|
||||
public class PlatformCapabilityQueryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 租户 ID。
|
||||
/// </summary>
|
||||
public Guid? TenantId { get; set; }
|
||||
/// <summary>
|
||||
/// 状态。
|
||||
/// </summary>
|
||||
[StringLength(50)]
|
||||
public string? Status { get; set; }
|
||||
/// <summary>
|
||||
/// 返回数量上限。
|
||||
/// </summary>
|
||||
[Range(1, 500)]
|
||||
public int Limit { get; set; } = 100;
|
||||
|
||||
public PlatformCapabilityQuery ToQuery() => new(TenantId, Status, Limit);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或更新租户 CRM 配置请求。
|
||||
/// </summary>
|
||||
public sealed class UpsertPlatformCrmConfigDto
|
||||
{
|
||||
/// <summary>
|
||||
/// ID。
|
||||
/// </summary>
|
||||
public Guid? Id { get; set; }
|
||||
/// <summary>
|
||||
/// 租户 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid TenantId { get; set; }
|
||||
/// <summary>
|
||||
/// 是否启用。
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; }
|
||||
/// <summary>
|
||||
/// 回调地址。
|
||||
/// </summary>
|
||||
[StringLength(2048)]
|
||||
public string? Url { get; set; }
|
||||
/// <summary>
|
||||
/// 密钥引用。
|
||||
/// </summary>
|
||||
[StringLength(300)]
|
||||
public string? SecretRef { get; set; }
|
||||
/// <summary>
|
||||
/// 表单名称。
|
||||
/// </summary>
|
||||
[StringLength(200)]
|
||||
public string? FormName { get; set; }
|
||||
/// <summary>
|
||||
/// 考试类型。
|
||||
/// </summary>
|
||||
[StringLength(100)]
|
||||
public string? ExamType { get; set; }
|
||||
/// <summary>
|
||||
/// 超时时长,单位为秒。
|
||||
/// </summary>
|
||||
[Range(1, 120)]
|
||||
public int? TimeoutSeconds { get; set; }
|
||||
/// <summary>
|
||||
/// 延迟秒数。
|
||||
/// </summary>
|
||||
[Range(0, 86400)]
|
||||
public int? DelaySeconds { get; set; }
|
||||
/// <summary>
|
||||
/// 分配模式。
|
||||
/// </summary>
|
||||
[StringLength(50)]
|
||||
public string? AssignmentMode { get; set; }
|
||||
/// <summary>
|
||||
/// 分配池。
|
||||
/// </summary>
|
||||
public JsonElement? AssignmentPool { get; set; }
|
||||
/// <summary>
|
||||
/// 分配配置。
|
||||
/// </summary>
|
||||
public JsonElement? AssignmentConfig { get; set; }
|
||||
|
||||
public UpsertPlatformCrmConfigCommand ToCommand() =>
|
||||
new(Id, TenantId, Enabled, Url, SecretRef, FormName, ExamType, TimeoutSeconds, DelaySeconds, AssignmentMode, AssignmentPool, AssignmentConfig);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重试租户 CRM 线索推送请求。
|
||||
/// </summary>
|
||||
public sealed class RetryPlatformCrmLeadDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 队列任务 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid QueueId { get; set; }
|
||||
/// <summary>
|
||||
/// 备注。
|
||||
/// </summary>
|
||||
[StringLength(500)]
|
||||
public string? Note { get; set; }
|
||||
|
||||
public PlatformCrmLeadRetryCommand ToCommand() => new(QueueId, Note);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 平台租户 CRM 日志查询参数。
|
||||
/// </summary>
|
||||
public sealed class PlatformCrmLogQueryDto : PlatformCapabilityQueryDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 队列任务 ID。
|
||||
/// </summary>
|
||||
public Guid? QueueId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或更新租户短信渠道请求。
|
||||
/// </summary>
|
||||
public sealed class UpsertPlatformSmsChannelDto
|
||||
{
|
||||
/// <summary>
|
||||
/// ID。
|
||||
/// </summary>
|
||||
public Guid? Id { get; set; }
|
||||
/// <summary>
|
||||
/// 租户 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid TenantId { get; set; }
|
||||
/// <summary>
|
||||
/// 服务提供方。
|
||||
/// </summary>
|
||||
[Required, StringLength(80)]
|
||||
public string Provider { get; set; } = "generic";
|
||||
/// <summary>
|
||||
/// 名称。
|
||||
/// </summary>
|
||||
[Required, StringLength(200)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 短信签名。
|
||||
/// </summary>
|
||||
[Required, StringLength(100)]
|
||||
public string Signature { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 使用场景。
|
||||
/// </summary>
|
||||
[Required, StringLength(100)]
|
||||
public string Scene { get; set; } = "login";
|
||||
/// <summary>
|
||||
/// 状态。
|
||||
/// </summary>
|
||||
public TenantExternalProviderStatus Status { get; set; } = TenantExternalProviderStatus.Disabled;
|
||||
/// <summary>
|
||||
/// 密钥引用。
|
||||
/// </summary>
|
||||
[StringLength(300)]
|
||||
public string? SecretRef { get; set; }
|
||||
/// <summary>
|
||||
/// 优先级。
|
||||
/// </summary>
|
||||
public int? Priority { get; set; }
|
||||
/// <summary>
|
||||
/// 月度配额。
|
||||
/// </summary>
|
||||
[Range(0, int.MaxValue)]
|
||||
public int? MonthlyQuota { get; set; }
|
||||
/// <summary>
|
||||
/// 公开配置内容。
|
||||
/// </summary>
|
||||
public JsonElement ConfigPublic { get; set; } = JsonDefaults.Object();
|
||||
/// <summary>
|
||||
/// 扩展元数据。
|
||||
/// </summary>
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public UpsertPlatformSmsChannelCommand ToCommand() =>
|
||||
new(Id, TenantId, Provider, Name, Signature, Scene, Status, SecretRef, Priority, MonthlyQuota, ConfigPublic, Metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或更新租户短信模板请求。
|
||||
/// </summary>
|
||||
public sealed class UpsertPlatformSmsTemplateDto
|
||||
{
|
||||
/// <summary>
|
||||
/// ID。
|
||||
/// </summary>
|
||||
public Guid? Id { get; set; }
|
||||
/// <summary>
|
||||
/// 租户 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid TenantId { get; set; }
|
||||
/// <summary>
|
||||
/// 短信渠道 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid ChannelId { get; set; }
|
||||
/// <summary>
|
||||
/// 编码。
|
||||
/// </summary>
|
||||
[Required, StringLength(120)]
|
||||
public string Code { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 名称。
|
||||
/// </summary>
|
||||
[Required, StringLength(200)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 类型。
|
||||
/// </summary>
|
||||
public SmsTemplateType Type { get; set; } = SmsTemplateType.Notification;
|
||||
/// <summary>
|
||||
/// 审核状态。
|
||||
/// </summary>
|
||||
public SmsTemplateAuditStatus AuditStatus { get; set; } = SmsTemplateAuditStatus.Draft;
|
||||
/// <summary>
|
||||
/// 状态。
|
||||
/// </summary>
|
||||
public SmsTemplateStatus Status { get; set; } = SmsTemplateStatus.Active;
|
||||
/// <summary>
|
||||
/// 渠道模板编码。
|
||||
/// </summary>
|
||||
[StringLength(120)]
|
||||
public string? ProviderTemplateCode { get; set; }
|
||||
/// <summary>
|
||||
/// 模板内容。
|
||||
/// </summary>
|
||||
[Required, StringLength(1000)]
|
||||
public string Content { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// Remark。
|
||||
/// </summary>
|
||||
[StringLength(500)]
|
||||
public string? Remark { get; set; }
|
||||
/// <summary>
|
||||
/// 扩展元数据。
|
||||
/// </summary>
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public UpsertPlatformSmsTemplateCommand ToCommand() =>
|
||||
new(Id, TenantId, ChannelId, Code, Name, Type, AuditStatus, Status, ProviderTemplateCode, Content, Remark, Metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或更新平台支付应用请求。
|
||||
/// </summary>
|
||||
public sealed class UpsertPlatformPaymentAppDto
|
||||
{
|
||||
/// <summary>
|
||||
/// ID。
|
||||
/// </summary>
|
||||
public Guid? Id { get; set; }
|
||||
/// <summary>
|
||||
/// 支付应用编码。
|
||||
/// </summary>
|
||||
[Required, StringLength(100)]
|
||||
public string AppCode { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 支付应用名称。
|
||||
/// </summary>
|
||||
[Required, StringLength(200)]
|
||||
public string AppName { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 状态。
|
||||
/// </summary>
|
||||
public PlatformPaymentAppStatus Status { get; set; } = PlatformPaymentAppStatus.Disabled;
|
||||
/// <summary>
|
||||
/// 结算模式。
|
||||
/// </summary>
|
||||
[StringLength(100)]
|
||||
public string SettlementMode { get; set; } = "PlatformCollect";
|
||||
/// <summary>
|
||||
/// 说明。
|
||||
/// </summary>
|
||||
[StringLength(500)]
|
||||
public string? Description { get; set; }
|
||||
/// <summary>
|
||||
/// 扩展元数据。
|
||||
/// </summary>
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public UpsertPlatformPaymentAppCommand ToCommand() =>
|
||||
new(Id, AppCode, AppName, Status, SettlementMode, Description, Metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或更新平台支付渠道请求。
|
||||
/// </summary>
|
||||
public sealed class UpsertPlatformPaymentChannelDto
|
||||
{
|
||||
/// <summary>
|
||||
/// ID。
|
||||
/// </summary>
|
||||
public Guid? Id { get; set; }
|
||||
/// <summary>
|
||||
/// 支付应用 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid AppId { get; set; }
|
||||
/// <summary>
|
||||
/// 服务提供方。
|
||||
/// </summary>
|
||||
[Required, StringLength(80)]
|
||||
public string Provider { get; set; } = "manual";
|
||||
/// <summary>
|
||||
/// 模式。
|
||||
/// </summary>
|
||||
[StringLength(100)]
|
||||
public string Mode { get; set; } = "PlatformCollect";
|
||||
/// <summary>
|
||||
/// 状态。
|
||||
/// </summary>
|
||||
public PlatformPaymentChannelStatus Status { get; set; } = PlatformPaymentChannelStatus.Disabled;
|
||||
/// <summary>
|
||||
/// 显示名称。
|
||||
/// </summary>
|
||||
[Required, StringLength(200)]
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// 密钥引用。
|
||||
/// </summary>
|
||||
[StringLength(300)]
|
||||
public string? SecretRef { get; set; }
|
||||
/// <summary>
|
||||
/// 回调路径。
|
||||
/// </summary>
|
||||
[StringLength(500)]
|
||||
public string? CallbackPath { get; set; }
|
||||
/// <summary>
|
||||
/// 优先级。
|
||||
/// </summary>
|
||||
public int? Priority { get; set; }
|
||||
/// <summary>
|
||||
/// 公开配置内容。
|
||||
/// </summary>
|
||||
public JsonElement ConfigPublic { get; set; } = JsonDefaults.Object();
|
||||
/// <summary>
|
||||
/// 扩展元数据。
|
||||
/// </summary>
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public UpsertPlatformPaymentChannelCommand ToCommand() =>
|
||||
new(Id, AppId, Provider, Mode, Status, DisplayName, SecretRef, CallbackPath, Priority, ConfigPublic, Metadata);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或更新租户支付应用请求。
|
||||
/// </summary>
|
||||
public sealed class UpsertPlatformTenantPaymentAppDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 租户 ID。
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Guid TenantId { get; set; }
|
||||
/// <summary>
|
||||
/// 服务提供方。
|
||||
/// </summary>
|
||||
[Required, StringLength(80)]
|
||||
public string Provider { get; set; } = "manual";
|
||||
/// <summary>
|
||||
/// 状态。
|
||||
/// </summary>
|
||||
public TenantExternalProviderStatus Status { get; set; } = TenantExternalProviderStatus.Disabled;
|
||||
/// <summary>
|
||||
/// 显示名称。
|
||||
/// </summary>
|
||||
[StringLength(200)]
|
||||
public string? DisplayName { get; set; }
|
||||
/// <summary>
|
||||
/// 密钥引用。
|
||||
/// </summary>
|
||||
[StringLength(300)]
|
||||
public string? SecretRef { get; set; }
|
||||
/// <summary>
|
||||
/// 优先级。
|
||||
/// </summary>
|
||||
public int? Priority { get; set; }
|
||||
/// <summary>
|
||||
/// 公开配置内容。
|
||||
/// </summary>
|
||||
public JsonElement ConfigPublic { get; set; } = JsonDefaults.Object();
|
||||
/// <summary>
|
||||
/// 扩展元数据。
|
||||
/// </summary>
|
||||
public JsonElement Metadata { get; set; } = JsonDefaults.Object();
|
||||
|
||||
public UpsertTenantExternalProviderCommand ToCommand() =>
|
||||
|
||||
@@ -10,6 +10,7 @@ using Tiku.Infrastructure.Persistence;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-资源访问")]
|
||||
[AllowAnonymous]
|
||||
[Produces("application/json")]
|
||||
[Route("api/assets")]
|
||||
|
||||
@@ -13,6 +13,7 @@ using Tiku.Domain.Tenancy;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-认证")]
|
||||
[Route("api/auth")]
|
||||
[Produces("application/json")]
|
||||
public sealed class AuthController(
|
||||
|
||||
@@ -7,6 +7,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-后台任务")]
|
||||
[Route("api/backoffice/tenant/jobs")]
|
||||
[Authorize(Policy = BackendPermissions.TenantJobManage)]
|
||||
public sealed class BackgroundJobsController(
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Tiku.Api.Contracts;
|
||||
using Tiku.Application.Backoffice;
|
||||
using Tiku.Application.Security;
|
||||
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/backoffice")]
|
||||
public sealed class BackofficeController(
|
||||
IBackofficeService backofficeService,
|
||||
ICurrentAccessContext currentAccessContext) : ControllerBase
|
||||
{
|
||||
[HttpGet("tenant/ui-bootstrap")]
|
||||
[Authorize(Policy = TikuPolicies.TenantBackofficeBootstrap)]
|
||||
[EndpointSummary("查询租户后台菜单与权限")]
|
||||
[EndpointDescription("返回当前租户管理员可见的后台菜单、权限和模块启用状态。")]
|
||||
[ProducesResponseType<BackofficeUiBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeUiBootstrap>> GetTenantUiBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetTenantUiBootstrapAsync(
|
||||
await currentAccessContext.GetAsync(cancellationToken),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("tenant/bootstrap")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("查询租户角色管理初始化数据")]
|
||||
[ProducesResponseType<BackofficeBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeBootstrap>> GetTenantBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetTenantBootstrapAsync(await ResolveTenantActorAsync(cancellationToken), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("platform/ui-bootstrap")]
|
||||
[Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)]
|
||||
[EndpointSummary("查询平台后台菜单与权限")]
|
||||
[EndpointDescription("返回当前平台管理员可见的后台菜单、权限和模块启用状态。")]
|
||||
[ProducesResponseType<BackofficeUiBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeUiBootstrap>> GetPlatformUiBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetPlatformUiBootstrapAsync(
|
||||
await currentAccessContext.GetAsync(cancellationToken),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("tenant/roles")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("创建或更新租户后台角色")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> UpsertTenantRole(
|
||||
UpsertBackofficeRoleDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.UpsertTenantRoleAsync(await ResolveTenantActorAsync(cancellationToken), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("tenant/roles/{roleId:guid}/bindings")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("替换租户后台角色权限绑定")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> ReplaceTenantRoleBindings(
|
||||
Guid roleId,
|
||||
ReplaceRoleBindingsDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.ReplaceTenantRoleBindingsAsync(await ResolveTenantActorAsync(cancellationToken), request.ToCommand(roleId), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("tenant/users/{userId:guid}/roles")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("替换租户用户后台角色")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> ReplaceTenantUserRoles(
|
||||
Guid userId,
|
||||
ReplaceUserRolesDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
await backofficeService.ReplaceTenantUserRolesAsync(await ResolveTenantActorAsync(cancellationToken), request.ToCommand(userId), cancellationToken);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpGet("platform/bootstrap")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("查询平台角色管理初始化数据")]
|
||||
[ProducesResponseType<BackofficeBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeBootstrap>> GetPlatformBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetPlatformBootstrapAsync(await ResolvePlatformActorAsync(cancellationToken), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("platform/roles")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("创建或更新平台后台角色")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> UpsertPlatformRole(
|
||||
UpsertBackofficeRoleDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.UpsertPlatformRoleAsync(await ResolvePlatformActorAsync(cancellationToken), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("platform/roles/{roleId:guid}/bindings")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("替换平台后台角色权限绑定")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> ReplacePlatformRoleBindings(
|
||||
Guid roleId,
|
||||
ReplaceRoleBindingsDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.ReplacePlatformRoleBindingsAsync(await ResolvePlatformActorAsync(cancellationToken), request.ToCommand(roleId), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("platform/users/{userId:guid}/roles")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("替换平台用户后台角色")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> ReplacePlatformUserRoles(
|
||||
Guid userId,
|
||||
ReplaceUserRolesDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
await backofficeService.ReplacePlatformUserRolesAsync(await ResolvePlatformActorAsync(cancellationToken), request.ToCommand(userId), cancellationToken);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
private async Task<BackofficeActor> ResolveTenantActorAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return BackofficeActor.FromTenantAccess(await currentAccessContext.GetAsync(cancellationToken));
|
||||
}
|
||||
|
||||
private async Task<BackofficeActor> ResolvePlatformActorAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return BackofficeActor.FromPlatformAccess(await currentAccessContext.GetAsync(cancellationToken));
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using Tiku.Infrastructure.Content;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-浏览器认证")]
|
||||
[Route("api/browser-auth")]
|
||||
[Produces("application/json")]
|
||||
public sealed class BrowserAuthController(
|
||||
@@ -28,6 +29,7 @@ public sealed class BrowserAuthController(
|
||||
[AllowAnonymous]
|
||||
[EnableRateLimiting(AuthRateLimitPolicies.Sms)]
|
||||
[HttpPost("sms/send")]
|
||||
[EndpointSummary("发送浏览器短信验证码")]
|
||||
public async Task<ActionResult<SmsSendResult>> SendSmsCode(
|
||||
[FromBody] SendSmsCodeDto request,
|
||||
CancellationToken cancellationToken)
|
||||
@@ -52,6 +54,7 @@ public sealed class BrowserAuthController(
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login/password")]
|
||||
[EndpointSummary("浏览器手机号密码登录")]
|
||||
public async Task<ActionResult<object>> LoginWithPassword(
|
||||
[FromBody] PasswordLoginDto request,
|
||||
CancellationToken cancellationToken)
|
||||
@@ -73,6 +76,7 @@ public sealed class BrowserAuthController(
|
||||
[AllowAnonymous]
|
||||
[EnableRateLimiting(AuthRateLimitPolicies.Sms)]
|
||||
[HttpPost("login/sms")]
|
||||
[EndpointSummary("浏览器短信验证码登录")]
|
||||
public async Task<ActionResult<object>> LoginWithSms(
|
||||
[FromBody] SmsLoginDto request,
|
||||
CancellationToken cancellationToken)
|
||||
@@ -91,6 +95,7 @@ public sealed class BrowserAuthController(
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("oauth/wechat")]
|
||||
[EndpointSummary("浏览器微信网页 OAuth 登录")]
|
||||
public async Task<ActionResult<object>> LoginWithWechatWeb(
|
||||
[FromBody] OAuthCodeDto request,
|
||||
CancellationToken cancellationToken)
|
||||
@@ -108,6 +113,7 @@ public sealed class BrowserAuthController(
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("oauth/wechat-miniapp")]
|
||||
[EndpointSummary("浏览器微信小程序登录")]
|
||||
public async Task<ActionResult<object>> LoginWithWechatMiniApp(
|
||||
[FromBody] OAuthCodeDto request,
|
||||
CancellationToken cancellationToken)
|
||||
@@ -125,6 +131,8 @@ public sealed class BrowserAuthController(
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("refresh")]
|
||||
[EndpointSummary("刷新浏览器登录会话")]
|
||||
[EndpointDescription("读取浏览器 refresh cookie,轮换会话并重新写入认证 cookie。")]
|
||||
public async Task<ActionResult<object>> Refresh(CancellationToken cancellationToken)
|
||||
{
|
||||
var refreshToken = Request.Cookies[BrowserAuthOptions.RefreshCookie];
|
||||
@@ -139,6 +147,8 @@ public sealed class BrowserAuthController(
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("logout")]
|
||||
[EndpointSummary("退出浏览器登录")]
|
||||
[EndpointDescription("撤销浏览器 refresh cookie 对应会话,并清理 access、refresh 与 CSRF cookie。")]
|
||||
public async Task<IActionResult> Logout(CancellationToken cancellationToken)
|
||||
{
|
||||
var refreshToken = Request.Cookies[BrowserAuthOptions.RefreshCookie];
|
||||
@@ -152,6 +162,7 @@ public sealed class BrowserAuthController(
|
||||
|
||||
[Authorize]
|
||||
[HttpPost("logout-all")]
|
||||
[EndpointSummary("退出全部浏览器登录会话")]
|
||||
public async Task<IActionResult> LogoutAll(CancellationToken cancellationToken)
|
||||
{
|
||||
if (currentUser.UserId is not { } userId) return Unauthorized();
|
||||
|
||||
@@ -14,6 +14,7 @@ using Tiku.Infrastructure.Persistence;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-公开目录")]
|
||||
[AllowAnonymous]
|
||||
[Produces("application/json")]
|
||||
[Route("api/catalog")]
|
||||
|
||||
@@ -12,6 +12,7 @@ using Tiku.Domain.Commerce;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-交易")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.StudentStore)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -7,6 +7,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-佣金")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCommissionManage)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.ReferralCommission)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -7,6 +7,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-CRM")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.Crm)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -11,6 +11,7 @@ using Tiku.Infrastructure.Messaging;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-系统健康")]
|
||||
[AllowAnonymous]
|
||||
[Produces("application/json")]
|
||||
[Route("api/health")]
|
||||
|
||||
@@ -7,6 +7,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-学习")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.Practice)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -8,6 +8,7 @@ using Tiku.Infrastructure.Persistence;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-当前用户")]
|
||||
[Authorize(Policy = TikuPolicies.AuthenticatedUser)]
|
||||
[Route("api/me")]
|
||||
public sealed class MeController(
|
||||
|
||||
@@ -8,6 +8,7 @@ using Tiku.Domain.Platform;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-平台管理")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformDashboardView)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/platform-admin")]
|
||||
|
||||
77
Tiku.Api/Controllers/PlatformBackofficeController.cs
Normal file
77
Tiku.Api/Controllers/PlatformBackofficeController.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Tiku.Api.Contracts;
|
||||
using Tiku.Application.Backoffice;
|
||||
using Tiku.Application.Security;
|
||||
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-后台权限")]
|
||||
[Route("api/backoffice/platform")]
|
||||
public sealed class PlatformBackofficeController(
|
||||
IBackofficeService backofficeService,
|
||||
ICurrentAccessContext currentAccessContext) : ControllerBase
|
||||
{
|
||||
[HttpGet("ui-bootstrap")]
|
||||
[Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)]
|
||||
[EndpointSummary("查询平台后台菜单与权限")]
|
||||
[EndpointDescription("返回当前平台管理员可见的后台菜单、权限和模块启用状态。")]
|
||||
[ProducesResponseType<BackofficeUiBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeUiBootstrap>> GetUiBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetPlatformUiBootstrapAsync(
|
||||
await currentAccessContext.GetAsync(cancellationToken),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("bootstrap")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("查询平台角色管理初始化数据")]
|
||||
[ProducesResponseType<BackofficeBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeBootstrap>> GetBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetPlatformBootstrapAsync(await ResolveActorAsync(cancellationToken), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("roles")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("创建或更新平台后台角色")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> UpsertRole(
|
||||
UpsertBackofficeRoleDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.UpsertPlatformRoleAsync(await ResolveActorAsync(cancellationToken), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("roles/{roleId:guid}/bindings")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("替换平台后台角色权限绑定")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> ReplaceRoleBindings(
|
||||
Guid roleId,
|
||||
ReplaceRoleBindingsDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.ReplacePlatformRoleBindingsAsync(await ResolveActorAsync(cancellationToken), request.ToCommand(roleId), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("users/{userId:guid}/roles")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformRoleManage)]
|
||||
[EndpointSummary("替换平台用户后台角色")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> ReplaceUserRoles(
|
||||
Guid userId,
|
||||
ReplaceUserRolesDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
await backofficeService.ReplacePlatformUserRolesAsync(await ResolveActorAsync(cancellationToken), request.ToCommand(userId), cancellationToken);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
private async Task<BackofficeActor> ResolveActorAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return BackofficeActor.FromPlatformAccess(await currentAccessContext.GetAsync(cancellationToken));
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,15 @@ using Tiku.Application.PlatformBilling;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-账务回调")]
|
||||
[Route("api/platform-billing/callbacks")]
|
||||
public sealed class PlatformBillingCallbackController(
|
||||
IPlatformBillingNotificationService notificationService) : ControllerBase
|
||||
{
|
||||
[AllowAnonymous]
|
||||
[HttpPost("{provider}")]
|
||||
[EndpointSummary("处理平台账务支付回调")]
|
||||
[EndpointDescription("接收平台账务支付渠道回调,按 provider 归一化后写入通知处理流程。")]
|
||||
public async Task<IActionResult> Notify(string provider, CancellationToken cancellationToken)
|
||||
{
|
||||
Request.EnableBuffering();
|
||||
|
||||
@@ -8,6 +8,7 @@ using Tiku.Domain.Platform;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-支付设置")]
|
||||
[Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/platform-admin/payment-settings")]
|
||||
@@ -16,36 +17,43 @@ public sealed class PlatformPaymentSettingsController(
|
||||
ICurrentUser currentUser) : ControllerBase
|
||||
{
|
||||
[HttpGet("apps")]
|
||||
[EndpointSummary("查询平台支付应用")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentRead)]
|
||||
public Task<IReadOnlyCollection<PlatformPaymentApp>> Apps(string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
paymentSettingsService.GetAppsAsync(Actor(), status, limit, cancellationToken);
|
||||
|
||||
[HttpPut("apps")]
|
||||
[EndpointSummary("新增或更新平台支付应用")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentWrite)]
|
||||
public Task<PlatformPaymentApp> UpsertApp(UpsertPlatformPaymentAppDto request, CancellationToken cancellationToken) =>
|
||||
paymentSettingsService.UpsertAppAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpGet("channels")]
|
||||
[EndpointSummary("查询平台支付渠道")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentRead)]
|
||||
public Task<IReadOnlyCollection<PlatformPaymentChannel>> Channels(Guid? appId, string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
paymentSettingsService.GetChannelsAsync(Actor(), appId, status, limit, cancellationToken);
|
||||
|
||||
[HttpPut("channels")]
|
||||
[EndpointSummary("新增或更新平台支付渠道")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentWrite)]
|
||||
public Task<PlatformPaymentChannel> UpsertChannel(UpsertPlatformPaymentChannelDto request, CancellationToken cancellationToken) =>
|
||||
paymentSettingsService.UpsertChannelAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPost("channels/{id:guid}/disable")]
|
||||
[EndpointSummary("禁用平台支付渠道")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentWrite)]
|
||||
public Task<PlatformPaymentChannel> DisableChannel(Guid id, CancellationToken cancellationToken) =>
|
||||
paymentSettingsService.DisableChannelAsync(Actor(), id, cancellationToken);
|
||||
|
||||
[HttpGet("events")]
|
||||
[EndpointSummary("查询平台支付事件")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentRead)]
|
||||
public Task<IReadOnlyCollection<PlatformBillingPaymentEvent>> Events(string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
paymentSettingsService.GetEventsAsync(Actor(), status, limit, cancellationToken);
|
||||
|
||||
[HttpGet("rebates/summary")]
|
||||
[EndpointSummary("查询平台返佣汇总")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentRead)]
|
||||
public Task<PlatformRebateSummary> RebateSummary(CancellationToken cancellationToken) =>
|
||||
paymentSettingsService.GetRebateSummaryAsync(Actor(), cancellationToken);
|
||||
|
||||
@@ -8,6 +8,7 @@ using Tiku.Domain.Platform;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-SaaS 套餐")]
|
||||
[Route("api/platform-admin/saas")]
|
||||
[Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)]
|
||||
public sealed class PlatformSaasController(
|
||||
@@ -16,16 +17,19 @@ public sealed class PlatformSaasController(
|
||||
ICurrentUser currentUser) : ControllerBase
|
||||
{
|
||||
[HttpGet("catalog")]
|
||||
[EndpointSummary("查询平台 SaaS 商品目录")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasCatalogSnapshot> Catalog(CancellationToken cancellationToken) =>
|
||||
catalogService.GetCatalogAsync(Actor(), cancellationToken);
|
||||
|
||||
[HttpPut("features")]
|
||||
[EndpointSummary("新增或更新 SaaS 功能")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasFeature> UpsertFeature(UpsertSaasFeatureDto request, CancellationToken cancellationToken) =>
|
||||
catalogService.UpsertFeatureAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPut("feature-limits")]
|
||||
[EndpointSummary("新增或更新 SaaS 功能限额")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasFeatureLimitDefinition> UpsertFeatureLimit(
|
||||
UpsertSaasFeatureLimitDto request,
|
||||
@@ -33,61 +37,73 @@ public sealed class PlatformSaasController(
|
||||
catalogService.UpsertLimitDefinitionAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPut("offerings")]
|
||||
[EndpointSummary("新增或更新 SaaS 套餐")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasOffering> UpsertOffering(UpsertSaasOfferingDto request, CancellationToken cancellationToken) =>
|
||||
catalogService.UpsertOfferingAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPut("offering-versions")]
|
||||
[EndpointSummary("新增或更新 SaaS 套餐版本草稿")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasOfferingVersionItem> UpsertVersion(UpsertSaasOfferingVersionDto request, CancellationToken cancellationToken) =>
|
||||
catalogService.UpsertDraftVersionAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPost("offering-versions/{versionId:guid}/publish")]
|
||||
[EndpointSummary("发布 SaaS 套餐版本")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasOfferingVersionItem> PublishVersion(Guid versionId, CancellationToken cancellationToken) =>
|
||||
catalogService.PublishVersionAsync(Actor(), versionId, cancellationToken);
|
||||
|
||||
[HttpPost("offering-versions/{versionId:guid}/clone")]
|
||||
[EndpointSummary("克隆 SaaS 套餐版本")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasOfferingVersionItem> CloneVersion(Guid versionId, CancellationToken cancellationToken) =>
|
||||
catalogService.CloneVersionAsync(Actor(), versionId, cancellationToken);
|
||||
|
||||
[HttpPost("offering-versions/{versionId:guid}/retire")]
|
||||
[EndpointSummary("下架 SaaS 套餐版本")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasCatalogManage)]
|
||||
public Task<SaasOfferingVersionItem> RetireVersion(Guid versionId, CancellationToken cancellationToken) =>
|
||||
catalogService.RetireVersionAsync(Actor(), versionId, cancellationToken);
|
||||
|
||||
[HttpGet("orders")]
|
||||
[EndpointSummary("查询平台 SaaS 订单")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)]
|
||||
public Task<IReadOnlyCollection<PlatformBillingOrder>> Orders(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
billingService.GetOrdersAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken);
|
||||
|
||||
[HttpGet("payments")]
|
||||
[EndpointSummary("查询平台 SaaS 支付记录")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)]
|
||||
public Task<IReadOnlyCollection<PlatformBillingPayment>> Payments(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
billingService.GetPaymentsAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken);
|
||||
|
||||
[HttpGet("refunds")]
|
||||
[EndpointSummary("查询平台 SaaS 退款记录")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)]
|
||||
public Task<IReadOnlyCollection<PlatformBillingRefund>> Refunds(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
billingService.GetRefundsAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken);
|
||||
|
||||
[HttpGet("invoices")]
|
||||
[EndpointSummary("查询平台 SaaS 发票")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)]
|
||||
public Task<IReadOnlyCollection<PlatformBillingInvoice>> Invoices(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
billingService.GetInvoicesAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken);
|
||||
|
||||
[HttpGet("subscriptions")]
|
||||
[EndpointSummary("查询租户 SaaS 订阅")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)]
|
||||
public Task<IReadOnlyCollection<TenantSaasSubscription>> Subscriptions(Guid? tenantId, string? status, int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
billingService.GetSubscriptionsAsync(Actor(), new PlatformBillingAdminQuery(tenantId, status, limit), cancellationToken);
|
||||
|
||||
[HttpPost("payments/manual/confirm")]
|
||||
[EndpointSummary("确认平台手工支付")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)]
|
||||
public Task<PlatformBillingPayment> ConfirmManualPayment(ConfirmManualPlatformPaymentDto request, CancellationToken cancellationToken) =>
|
||||
billingService.ConfirmManualPaymentAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPut("tenant-feature-overrides")]
|
||||
[EndpointSummary("新增或更新租户功能覆盖规则")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSaasBillingManage)]
|
||||
public Task<TenantFeatureOverride> UpsertFeatureOverride(UpsertTenantFeatureOverrideDto request, CancellationToken cancellationToken) =>
|
||||
billingService.UpsertFeatureOverrideAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
@@ -10,6 +10,7 @@ using Tiku.Domain.Tenancy;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-租户 CRM 能力")]
|
||||
[Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/platform-admin/tenant-capabilities/crm")]
|
||||
@@ -18,26 +19,31 @@ public sealed class PlatformAdminCrmController(
|
||||
ICurrentUser currentUser) : ControllerBase
|
||||
{
|
||||
[HttpGet("configs")]
|
||||
[EndpointSummary("查询租户 CRM 配置")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformCrmRead)]
|
||||
public Task<PlatformTenantCapabilityList<PlatformCrmConfigItem>> Configs([FromQuery] PlatformCapabilityQueryDto query, CancellationToken cancellationToken) =>
|
||||
crmService.GetConfigsAsync(Actor(), query.ToQuery(), cancellationToken);
|
||||
|
||||
[HttpPut("configs")]
|
||||
[EndpointSummary("新增或更新租户 CRM 配置")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformCrmWrite)]
|
||||
public Task<PlatformCrmConfigItem> UpsertConfig(UpsertPlatformCrmConfigDto request, CancellationToken cancellationToken) =>
|
||||
crmService.UpsertConfigAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpGet("leads")]
|
||||
[EndpointSummary("查询租户 CRM 线索队列")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformCrmRead)]
|
||||
public Task<PlatformTenantCapabilityList<CrmWebhookQueueItem>> Leads([FromQuery] PlatformCapabilityQueryDto query, CancellationToken cancellationToken) =>
|
||||
crmService.GetLeadsAsync(Actor(), query.ToQuery(), cancellationToken);
|
||||
|
||||
[HttpPost("leads/retry")]
|
||||
[EndpointSummary("重试租户 CRM 线索推送")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformCrmWrite)]
|
||||
public Task<CrmWebhookQueueItem> RetryLead(RetryPlatformCrmLeadDto request, CancellationToken cancellationToken) =>
|
||||
crmService.RetryLeadAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpGet("logs")]
|
||||
[EndpointSummary("查询租户 CRM 推送日志")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformCrmRead)]
|
||||
public Task<PlatformTenantCapabilityList<CrmWebhookLog>> Logs([FromQuery] PlatformCrmLogQueryDto query, CancellationToken cancellationToken) =>
|
||||
crmService.GetLogsAsync(Actor(), query.TenantId, query.QueueId, query.Limit, cancellationToken);
|
||||
@@ -48,6 +54,7 @@ public sealed class PlatformAdminCrmController(
|
||||
}
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-租户短信能力")]
|
||||
[Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/platform-admin/tenant-capabilities/sms")]
|
||||
@@ -56,41 +63,49 @@ public sealed class PlatformAdminSmsController(
|
||||
ICurrentUser currentUser) : ControllerBase
|
||||
{
|
||||
[HttpGet("channels")]
|
||||
[EndpointSummary("查询租户短信渠道")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsRead)]
|
||||
public Task<PlatformTenantCapabilityList<PlatformSmsChannelItem>> Channels([FromQuery] PlatformCapabilityQueryDto query, CancellationToken cancellationToken) =>
|
||||
smsService.GetChannelsAsync(Actor(), query.ToQuery(), cancellationToken);
|
||||
|
||||
[HttpPut("channels")]
|
||||
[EndpointSummary("新增或更新租户短信渠道")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsWrite)]
|
||||
public Task<PlatformSmsChannelItem> UpsertChannel(UpsertPlatformSmsChannelDto request, CancellationToken cancellationToken) =>
|
||||
smsService.UpsertChannelAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPost("channels/{id:guid}/disable")]
|
||||
[EndpointSummary("禁用租户短信渠道")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsWrite)]
|
||||
public Task<PlatformSmsChannelItem> DisableChannel(Guid id, CancellationToken cancellationToken) =>
|
||||
smsService.DisableChannelAsync(Actor(), id, cancellationToken);
|
||||
|
||||
[HttpGet("templates")]
|
||||
[EndpointSummary("查询租户短信模板")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsRead)]
|
||||
public Task<PlatformTenantCapabilityList<PlatformSmsTemplateItem>> Templates([FromQuery] PlatformCapabilityQueryDto query, CancellationToken cancellationToken) =>
|
||||
smsService.GetTemplatesAsync(Actor(), query.ToQuery(), cancellationToken);
|
||||
|
||||
[HttpPut("templates")]
|
||||
[EndpointSummary("新增或更新租户短信模板")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsWrite)]
|
||||
public Task<PlatformSmsTemplateItem> UpsertTemplate(UpsertPlatformSmsTemplateDto request, CancellationToken cancellationToken) =>
|
||||
smsService.UpsertTemplateAsync(Actor(), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPost("templates/{id:guid}/submit-review")]
|
||||
[EndpointSummary("提交租户短信模板审核")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsWrite)]
|
||||
public Task<PlatformSmsTemplateItem> SubmitTemplateReview(Guid id, CancellationToken cancellationToken) =>
|
||||
smsService.SubmitTemplateReviewAsync(Actor(), id, cancellationToken);
|
||||
|
||||
[HttpPost("templates/{id:guid}/disable")]
|
||||
[EndpointSummary("禁用租户短信模板")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsWrite)]
|
||||
public Task<PlatformSmsTemplateItem> DisableTemplate(Guid id, CancellationToken cancellationToken) =>
|
||||
smsService.DisableTemplateAsync(Actor(), id, cancellationToken);
|
||||
|
||||
[HttpGet("logs")]
|
||||
[EndpointSummary("查询租户短信发送日志")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformSmsRead)]
|
||||
public Task<PlatformTenantCapabilityList<SmsSendLog>> Logs([FromQuery] PlatformCapabilityQueryDto query, CancellationToken cancellationToken) =>
|
||||
smsService.GetLogsAsync(Actor(), query.ToQuery(), cancellationToken);
|
||||
@@ -101,6 +116,7 @@ public sealed class PlatformAdminSmsController(
|
||||
}
|
||||
|
||||
[ApiController]
|
||||
[Tags("平台端-租户支付能力")]
|
||||
[Authorize(Policy = TikuPolicies.PlatformBackofficeBootstrap)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/platform-admin/tenant-capabilities/payments")]
|
||||
@@ -109,16 +125,19 @@ public sealed class PlatformAdminTenantPaymentSettingsController(
|
||||
ICurrentUser currentUser) : ControllerBase
|
||||
{
|
||||
[HttpGet("apps")]
|
||||
[EndpointSummary("查询租户支付应用")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentRead)]
|
||||
public Task<PlatformTenantCapabilityList<TenantExternalProviderItem>> Apps([FromQuery] PlatformCapabilityQueryDto query, CancellationToken cancellationToken) =>
|
||||
paymentService.GetAppsAsync(Actor(), query.ToQuery(), cancellationToken);
|
||||
|
||||
[HttpPut("apps")]
|
||||
[EndpointSummary("新增或更新租户支付应用")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentWrite)]
|
||||
public Task<TenantExternalProviderItem> UpsertApp(UpsertPlatformTenantPaymentAppDto request, CancellationToken cancellationToken) =>
|
||||
paymentService.UpsertAppAsync(Actor(), request.TenantId, request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpGet("events")]
|
||||
[EndpointSummary("查询租户支付事件")]
|
||||
[Authorize(Policy = BackendPermissions.PlatformPaymentRead)]
|
||||
public Task<PlatformTenantCapabilityList<object>> Events([FromQuery] PlatformCapabilityQueryDto query, CancellationToken cancellationToken) =>
|
||||
paymentService.GetEventsAsync(Actor(), query.ToQuery(), cancellationToken);
|
||||
|
||||
@@ -7,6 +7,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-积分")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.StudentStore)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -8,6 +8,7 @@ using Tiku.Infrastructure.Profile;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-个人中心")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/profile")]
|
||||
|
||||
@@ -8,6 +8,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-题目视频")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.Video)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -11,6 +11,7 @@ using Tiku.Infrastructure.Persistence;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-推荐增长")]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.ReferralCommission)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/referral")]
|
||||
@@ -96,6 +97,7 @@ public sealed class ReferralController(
|
||||
}
|
||||
|
||||
[HttpGet("stats")]
|
||||
[Tags("租户端-推荐增长")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[EndpointSummary("查询推荐人个人统计")]
|
||||
[ProducesResponseType<ReferralStatsItem>(StatusCodes.Status200OK)]
|
||||
@@ -110,6 +112,7 @@ public sealed class ReferralController(
|
||||
}
|
||||
|
||||
[HttpGet("sales-stats")]
|
||||
[Tags("租户端-推荐增长")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[EndpointSummary("查询销售推荐统计排行")]
|
||||
[ProducesResponseType<ReferralList<ReferralStatsItem>>(StatusCodes.Status200OK)]
|
||||
@@ -124,6 +127,7 @@ public sealed class ReferralController(
|
||||
}
|
||||
|
||||
[HttpGet("conversion-report")]
|
||||
[Tags("租户端-推荐增长")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[EndpointSummary("查询推荐转化报告")]
|
||||
[ProducesResponseType<ReferralConversionReport>(StatusCodes.Status200OK)]
|
||||
@@ -138,6 +142,7 @@ public sealed class ReferralController(
|
||||
}
|
||||
|
||||
[HttpGet("sales-clients")]
|
||||
[Tags("租户端-推荐增长")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[EndpointSummary("查询推荐人名下客户")]
|
||||
[ProducesResponseType<ReferralList<ReferralLeadItem>>(StatusCodes.Status200OK)]
|
||||
@@ -152,6 +157,7 @@ public sealed class ReferralController(
|
||||
}
|
||||
|
||||
[HttpPost("manual-bind")]
|
||||
[Tags("租户端-推荐增长")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[EndpointSummary("人工调整学生推荐归属")]
|
||||
[ProducesResponseType<ReferralBindResult>(StatusCodes.Status200OK)]
|
||||
@@ -166,6 +172,7 @@ public sealed class ReferralController(
|
||||
}
|
||||
|
||||
[HttpGet("team")]
|
||||
[Tags("租户端-推荐增长")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[EndpointSummary("查询推荐团队成员")]
|
||||
[ProducesResponseType<ReferralList<ReferralTeamItem>>(StatusCodes.Status200OK)]
|
||||
@@ -180,6 +187,7 @@ public sealed class ReferralController(
|
||||
}
|
||||
|
||||
[HttpPut("team")]
|
||||
[Tags("租户端-推荐增长")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCrmManage)]
|
||||
[EndpointSummary("新增或更新推荐团队关系")]
|
||||
[ProducesResponseType<ReferralTeamItem>(StatusCodes.Status200OK)]
|
||||
|
||||
@@ -6,6 +6,7 @@ using Tiku.Application.Tenancy;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-运行时配置")]
|
||||
[AllowAnonymous]
|
||||
[Produces("application/json")]
|
||||
[Route("api/runtime")]
|
||||
|
||||
@@ -11,6 +11,7 @@ using Tiku.Infrastructure.Persistence;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-分数线")]
|
||||
[AllowAnonymous]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.Scoreline)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -7,6 +7,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-分类管理")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/taxonomy/nodes")]
|
||||
|
||||
@@ -10,6 +10,7 @@ using Tiku.Domain.Tenancy;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-运营管理")]
|
||||
[Produces("application/json")]
|
||||
[Route("api/tenant-admin")]
|
||||
public sealed class TenantAdminDirectController(
|
||||
|
||||
77
Tiku.Api/Controllers/TenantBackofficeController.cs
Normal file
77
Tiku.Api/Controllers/TenantBackofficeController.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Tiku.Api.Contracts;
|
||||
using Tiku.Application.Backoffice;
|
||||
using Tiku.Application.Security;
|
||||
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-后台权限")]
|
||||
[Route("api/backoffice/tenant")]
|
||||
public sealed class TenantBackofficeController(
|
||||
IBackofficeService backofficeService,
|
||||
ICurrentAccessContext currentAccessContext) : ControllerBase
|
||||
{
|
||||
[HttpGet("ui-bootstrap")]
|
||||
[Authorize(Policy = TikuPolicies.TenantBackofficeBootstrap)]
|
||||
[EndpointSummary("查询租户后台菜单与权限")]
|
||||
[EndpointDescription("返回当前租户管理员可见的后台菜单、权限和模块启用状态。")]
|
||||
[ProducesResponseType<BackofficeUiBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeUiBootstrap>> GetUiBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetTenantUiBootstrapAsync(
|
||||
await currentAccessContext.GetAsync(cancellationToken),
|
||||
cancellationToken));
|
||||
}
|
||||
|
||||
[HttpGet("bootstrap")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("查询租户角色管理初始化数据")]
|
||||
[ProducesResponseType<BackofficeBootstrap>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeBootstrap>> GetBootstrap(CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.GetTenantBootstrapAsync(await ResolveActorAsync(cancellationToken), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPost("roles")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("创建或更新租户后台角色")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> UpsertRole(
|
||||
UpsertBackofficeRoleDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.UpsertTenantRoleAsync(await ResolveActorAsync(cancellationToken), request.ToCommand(), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("roles/{roleId:guid}/bindings")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("替换租户后台角色权限绑定")]
|
||||
[ProducesResponseType<BackofficeRoleItem>(StatusCodes.Status200OK)]
|
||||
public async Task<ActionResult<BackofficeRoleItem>> ReplaceRoleBindings(
|
||||
Guid roleId,
|
||||
ReplaceRoleBindingsDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return Ok(await backofficeService.ReplaceTenantRoleBindingsAsync(await ResolveActorAsync(cancellationToken), request.ToCommand(roleId), cancellationToken));
|
||||
}
|
||||
|
||||
[HttpPut("users/{userId:guid}/roles")]
|
||||
[Authorize(Policy = BackendPermissions.TenantRoleManage)]
|
||||
[EndpointSummary("替换租户用户后台角色")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> ReplaceUserRoles(
|
||||
Guid userId,
|
||||
ReplaceUserRolesDto request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
await backofficeService.ReplaceTenantUserRolesAsync(await ResolveActorAsync(cancellationToken), request.ToCommand(userId), cancellationToken);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
private async Task<BackofficeActor> ResolveActorAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return BackofficeActor.FromTenantAccess(await currentAccessContext.GetAsync(cancellationToken));
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Tiku.Domain.Platform;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-账务")]
|
||||
[Route("api/tenant-billing")]
|
||||
[Authorize(Policy = BackendPermissions.TenantBillingManage)]
|
||||
public sealed class TenantBillingController(
|
||||
@@ -15,50 +16,62 @@ public sealed class TenantBillingController(
|
||||
ICurrentAccessContext accessContext) : ControllerBase
|
||||
{
|
||||
[HttpGet("catalog")]
|
||||
[EndpointSummary("查询租户可购买 SaaS 目录")]
|
||||
public async Task<TenantBillingCatalog> Catalog(CancellationToken cancellationToken) =>
|
||||
await billingService.GetCatalogAsync(await ActorAsync(cancellationToken), cancellationToken);
|
||||
|
||||
[HttpPost("quotes")]
|
||||
[EndpointSummary("创建租户账务报价")]
|
||||
public async Task<PlatformBillingQuoteView> Quote(CreatePlatformBillingQuoteDto request, CancellationToken cancellationToken) =>
|
||||
await billingService.CreateQuoteAsync(await ActorAsync(cancellationToken), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPost("orders")]
|
||||
[EndpointSummary("创建租户账务订单")]
|
||||
public async Task<PlatformBillingOrderView> CreateOrder(CreatePlatformBillingOrderDto request, CancellationToken cancellationToken) =>
|
||||
await billingService.CreateOrderAsync(await ActorAsync(cancellationToken), request.ToCommand(), cancellationToken);
|
||||
|
||||
[HttpPost("orders/{orderNo}/payments")]
|
||||
[EndpointSummary("创建租户账务订单支付")]
|
||||
public async Task<PlatformBillingPaymentView> CreatePayment(string orderNo, CreatePlatformBillingPaymentDto request, CancellationToken cancellationToken) =>
|
||||
await billingService.CreatePaymentAsync(await ActorAsync(cancellationToken), request.ToCommand(orderNo), cancellationToken);
|
||||
|
||||
[HttpGet("orders")]
|
||||
[EndpointSummary("查询租户账务订单")]
|
||||
public async Task<IReadOnlyCollection<PlatformBillingOrderView>> Orders(int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
await billingService.GetOrdersAsync(await ActorAsync(cancellationToken), limit, cancellationToken);
|
||||
|
||||
[HttpGet("orders/{orderNo}")]
|
||||
[EndpointSummary("查询租户账务订单详情")]
|
||||
public async Task<PlatformBillingOrderView> Order(string orderNo, CancellationToken cancellationToken) =>
|
||||
await billingService.GetOrderAsync(await ActorAsync(cancellationToken), orderNo, cancellationToken);
|
||||
|
||||
[HttpGet("subscription")]
|
||||
[EndpointSummary("查询当前租户 SaaS 订阅")]
|
||||
public async Task<TenantSubscriptionView?> Subscription(CancellationToken cancellationToken) =>
|
||||
await billingService.GetSubscriptionAsync(await ActorAsync(cancellationToken), cancellationToken);
|
||||
|
||||
[HttpPost("subscription/change")]
|
||||
[EndpointSummary("变更当前租户 SaaS 订阅")]
|
||||
public async Task<PlatformBillingOrderView> Change(ChangeTenantSubscriptionDto request, CancellationToken cancellationToken) =>
|
||||
await billingService.ChangeSubscriptionAsync(await ActorAsync(cancellationToken), request.ToCommand(), request.IdempotencyKey, cancellationToken);
|
||||
|
||||
[HttpPost("subscription/renew")]
|
||||
[EndpointSummary("续费当前租户 SaaS 订阅")]
|
||||
public async Task<PlatformBillingOrderView> Renew(IdempotentTenantBillingDto request, CancellationToken cancellationToken) =>
|
||||
await billingService.RenewSubscriptionAsync(await ActorAsync(cancellationToken), request.IdempotencyKey, cancellationToken);
|
||||
|
||||
[HttpPost("subscription/cancel")]
|
||||
[EndpointSummary("取消当前租户 SaaS 订阅")]
|
||||
public async Task<TenantSubscriptionView> Cancel(CancellationToken cancellationToken) =>
|
||||
await billingService.CancelSubscriptionAsync(await ActorAsync(cancellationToken), cancellationToken);
|
||||
|
||||
[HttpGet("usage")]
|
||||
[EndpointSummary("查询当前租户功能用量")]
|
||||
public async Task<IReadOnlyCollection<FeatureQuotaSnapshot>> Usage(CancellationToken cancellationToken) =>
|
||||
await billingService.GetUsageAsync(await ActorAsync(cancellationToken), cancellationToken);
|
||||
|
||||
[HttpGet("invoices")]
|
||||
[EndpointSummary("查询当前租户发票")]
|
||||
public async Task<IReadOnlyCollection<PlatformBillingInvoice>> Invoices(int limit = 100, CancellationToken cancellationToken = default) =>
|
||||
await billingService.GetInvoicesAsync(await ActorAsync(cancellationToken), limit, cancellationToken);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using Tiku.Domain.Commerce;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-交易运营")]
|
||||
[Authorize(Policy = BackendPermissions.TenantCommerceOperate)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.StudentStore)]
|
||||
[Produces("application/json")]
|
||||
|
||||
@@ -9,6 +9,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-内容管理")]
|
||||
[Authorize(Policy = BackendPermissions.TenantContentManage)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/tenant-content")]
|
||||
|
||||
@@ -12,6 +12,7 @@ using Tiku.Domain.Content;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-内容直接管理")]
|
||||
[Produces("application/json")]
|
||||
[Route("api/tenant-content")]
|
||||
public sealed class TenantContentDirectController(
|
||||
|
||||
@@ -7,6 +7,7 @@ using Tiku.Application.Tenancy;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-前端配置")]
|
||||
[Authorize(Policy = BackendPermissions.TenantSettingsManage)]
|
||||
[Produces("application/json")]
|
||||
[Route("api/tenant-admin/frontend-config")]
|
||||
|
||||
@@ -6,6 +6,7 @@ using Tiku.Application.Tenancy;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-开通引导")]
|
||||
[Route("api/tenant-onboarding")]
|
||||
[Authorize(Policy = BackendPermissions.TenantSettingsManage)]
|
||||
public sealed class TenantOnboardingController(
|
||||
@@ -13,6 +14,7 @@ public sealed class TenantOnboardingController(
|
||||
ICurrentAccessContext accessContext) : ControllerBase
|
||||
{
|
||||
[HttpGet("status")]
|
||||
[EndpointSummary("查询租户开通引导状态")]
|
||||
public async Task<TenantOnboardingStatus> Status(CancellationToken cancellationToken)
|
||||
{
|
||||
var access = await accessContext.GetAsync(cancellationToken);
|
||||
|
||||
@@ -13,6 +13,7 @@ using Tiku.Application.Tenancy;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-公开配置")]
|
||||
[AllowAnonymous]
|
||||
[Produces("application/json")]
|
||||
[Route("api/tenant")]
|
||||
|
||||
@@ -9,6 +9,7 @@ using Tiku.Infrastructure.Persistence;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("租户端-当前租户")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Route("api/tenants")]
|
||||
public sealed class TenantsController(
|
||||
|
||||
@@ -8,6 +8,7 @@ using Tiku.Application.Security;
|
||||
namespace Tiku.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Tags("学生端-视频")]
|
||||
[Authorize(Policy = TikuPolicies.CurrentTenantMember)]
|
||||
[Tiku.Api.Security.RequireSaasFeature(SaasFeatureCatalog.Video)]
|
||||
[Produces("application/json")]
|
||||
|
||||
Reference in New Issue
Block a user