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}/roles")] public sealed class RolesController(IMediator mediator) : BaseApiController { /// /// 获取预置角色模板列表。 /// /// /// 示例:GET /api/admin/v1/roles/templates /// /// 角色模板列表。 [HttpGet("templates")] [PermissionAuthorize("identity:role:read")] [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] public async Task>> ListTemplates([FromQuery] bool? isActive, CancellationToken cancellationToken) { // 1. 查询模板列表 var result = await mediator.Send(new ListRoleTemplatesQuery { IsActive = isActive }, cancellationToken); // 2. 返回模板集合 return ApiResponse>.Ok(result); } /// /// 获取单个角色模板详情。 /// /// /// 示例:GET /api/admin/v1/roles/templates/tenant-admin /// /// 角色模板详情。 [HttpGet("templates/{templateCode}")] [PermissionAuthorize("identity:role:read")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> GetTemplate(string templateCode, CancellationToken cancellationToken) { // 1. 查询指定模板 var result = await mediator.Send(new GetRoleTemplateQuery { TemplateCode = templateCode }, cancellationToken); // 2. 返回模板或 404 return result is null ? ApiResponse.Error(StatusCodes.Status404NotFound, "角色模板不存在") : ApiResponse.Ok(result); } /// /// 创建角色模板。 /// /// 创建的角色模板信息。 [HttpPost("templates")] [PermissionAuthorize("role-template:create")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> CreateTemplate([FromBody, Required] CreateRoleTemplateCommand command, CancellationToken cancellationToken) { // 1. 创建模板 var result = await mediator.Send(command, cancellationToken); // 2. 返回创建结果 return ApiResponse.Ok(result); } /// /// 更新角色模板。 /// /// 更新后的角色模板信息。 [HttpPut("templates/{templateCode}")] [PermissionAuthorize("role-template:update")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> UpdateTemplate( string templateCode, [FromBody, Required] UpdateRoleTemplateCommand command, CancellationToken cancellationToken) { // 1. 绑定模板编码 command = command with { TemplateCode = templateCode }; // 2. 执行更新 var result = await mediator.Send(command, cancellationToken); // 3. 返回更新结果或 404 return result is null ? ApiResponse.Error(StatusCodes.Status404NotFound, "角色模板不存在") : ApiResponse.Ok(result); } /// /// 删除角色模板。 /// /// 删除结果。 [HttpDelete("templates/{templateCode}")] [PermissionAuthorize("role-template:delete")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> DeleteTemplate(string templateCode, CancellationToken cancellationToken) { // 1. 删除模板 var result = await mediator.Send(new DeleteRoleTemplateCommand { TemplateCode = templateCode }, cancellationToken); // 2. 返回执行结果 return ApiResponse.Ok(result); } /// /// 按模板复制角色并绑定权限。 /// /// /// 示例:POST /api/admin/v1/roles/templates/store-manager/copy /// Body: { "roleName": "新区店长" } /// /// 创建的角色信息。 [HttpPost("templates/{templateCode}/copy")] [PermissionAuthorize("identity:role:create")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> CopyFromTemplate( string templateCode, [FromBody, Required] CopyRoleTemplateCommand command, CancellationToken cancellationToken) { // 1. 绑定模板编码 command = command with { TemplateCode = templateCode }; // 2. 复制模板并返回角色 var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } /// /// 为当前租户批量初始化预置角色模板。 /// /// /// 示例:POST /api/admin/v1/roles/templates/init /// Body: { "templateCodes": ["tenant-admin","store-manager","store-staff"] } /// /// 创建的角色列表。 [HttpPost("templates/init")] [PermissionAuthorize("identity:role:create")] [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] public async Task>> InitializeTemplates( [FromBody] InitializeRoleTemplatesCommand? command, CancellationToken cancellationToken) { // 1. 确保命令实例存在 command ??= new InitializeRoleTemplatesCommand(); // 2. 执行初始化 var result = await mediator.Send(command, cancellationToken); return ApiResponse>.Ok(result); } /// /// 分页查询角色。 /// /// /// 示例: /// GET /api/admin/v1/roles?keyword=ops&page=1&pageSize=20 /// Header: Authorization: Bearer <JWT> + X-Tenant-Id /// /// 角色分页结果。 [HttpGet] [PermissionAuthorize("identity:role:read")] [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)] public async Task>> Search([FromQuery] SearchRolesQuery query, CancellationToken cancellationToken) { // 1. 查询角色分页 var result = await mediator.Send(query, cancellationToken); // 2. 返回分页数据 return ApiResponse>.Ok(result); } /// /// 创建角色。 /// /// 创建的角色信息。 [HttpPost] [PermissionAuthorize("identity:role:create")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Create([FromBody, Required] CreateRoleCommand command, CancellationToken cancellationToken) { // 1. 创建角色 var result = await mediator.Send(command, 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 roleId, [FromBody, Required] UpdateRoleCommand command, CancellationToken cancellationToken) { // 1. 绑定角色标识 command = command with { RoleId = roleId }; // 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 roleId, CancellationToken cancellationToken) { // 1. 构建删除命令 var command = new DeleteRoleCommand { RoleId = roleId }; // 2. 执行删除 var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } /// /// 绑定角色权限(覆盖式)。 /// /// 是否绑定成功。 [HttpPut("{roleId:long}/permissions")] [PermissionAuthorize("identity:role:bind-permission")] [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> BindPermissions(long roleId, [FromBody, Required] BindRolePermissionsCommand command, CancellationToken cancellationToken) { // 1. 绑定角色标识 command = command with { RoleId = roleId }; // 2. 执行覆盖式授权 var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } }