- Replace TenantRepository with TenantManager (ASP.NET Identity style) - Change TenantId from long to int (auto-increment) - Add TenantStore with CRUD operations - Update TenantService, UserService, RoleService to use TenantManager - Add Tenant entity with TenantStatus enum - Update DTOs and controllers for int tenant IDs
337 lines
13 KiB
C#
337 lines
13 KiB
C#
namespace Fengling.Console.Controllers;
|
|
|
|
using Fengling.Console.Services;
|
|
|
|
/// <summary>
|
|
/// 租户管理控制器
|
|
/// 提供租户的增删改查以及租户用户、角色、配置管理功能
|
|
/// </summary>
|
|
[ApiController]
|
|
[Route("api/console/[controller]")]
|
|
[Authorize(AuthenticationSchemes = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme)]
|
|
public class TenantsController : ControllerBase
|
|
{
|
|
private readonly ITenantService _tenantService;
|
|
private readonly IH5LinkService _h5LinkService;
|
|
private readonly ILogger<TenantsController> _logger;
|
|
|
|
public TenantsController(ITenantService tenantService, IH5LinkService h5LinkService, ILogger<TenantsController> logger)
|
|
{
|
|
_tenantService = tenantService;
|
|
_h5LinkService = h5LinkService;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取租户列表
|
|
/// </summary>
|
|
/// <param name="query">分页查询参数,支持按名称、租户编码和状态筛选</param>
|
|
/// <returns>分页的租户列表,包含租户基本信息和状态</returns>
|
|
/// <response code="200">成功返回租户分页列表</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpGet]
|
|
[Produces("application/json")]
|
|
[ProducesResponseType(typeof(PagedResultDto<TenantDto>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<ActionResult<PagedResultDto<TenantDto>>> GetTenants([FromQuery] TenantQueryDto query)
|
|
{
|
|
try
|
|
{
|
|
var (items, totalCount) = await _tenantService.GetTenantsAsync(query.Page, query.PageSize, query.Name,
|
|
query.TenantId, query.Status);
|
|
var result = new PagedResultDto<TenantDto>
|
|
{
|
|
Items = items.ToList(),
|
|
TotalCount = totalCount,
|
|
Page = query.Page,
|
|
PageSize = query.PageSize
|
|
};
|
|
return Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting tenants");
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取单个租户详情
|
|
/// </summary>
|
|
/// <param name="id">租户ID</param>
|
|
/// <returns>租户的详细信息,包括配置、限额等信息</returns>
|
|
/// <response code="200">成功返回租户详情</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpGet("{id}")]
|
|
[Produces("application/json")]
|
|
[ProducesResponseType(typeof(TenantDto), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<ActionResult<TenantDto>> GetTenant(int id)
|
|
{
|
|
try
|
|
{
|
|
var tenant = await _tenantService.GetTenantAsync(id);
|
|
if (tenant == null)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
return Ok(tenant);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting tenant {TenantId}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取指定租户的用户列表
|
|
/// </summary>
|
|
/// <param name="tenantId">租户ID</param>
|
|
/// <returns>属于该租户的所有用户列表</returns>
|
|
/// <response code="200">成功返回用户列表</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpGet("{tenantId}/users")]
|
|
[Produces("application/json")]
|
|
[ProducesResponseType(typeof(IEnumerable<UserDto>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<ActionResult<IEnumerable<UserDto>>> GetTenantUsers(int tenantId)
|
|
{
|
|
try
|
|
{
|
|
var users = await _tenantService.GetTenantUsersAsync(tenantId);
|
|
return Ok(users);
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Tenant not found: {TenantId}", tenantId);
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting users for tenant {TenantId}", tenantId);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取指定租户的角色列表
|
|
/// </summary>
|
|
/// <param name="tenantId">租户ID</param>
|
|
/// <returns>属于该租户的所有角色列表</returns>
|
|
/// <response code="200">成功返回角色列表</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpGet("{tenantId}/roles")]
|
|
[Produces("application/json")]
|
|
[ProducesResponseType(typeof(IEnumerable<object>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<ActionResult<IEnumerable<object>>> GetTenantRoles(int tenantId)
|
|
{
|
|
try
|
|
{
|
|
var roles = await _tenantService.GetTenantRolesAsync(tenantId);
|
|
return Ok(roles);
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Tenant not found: {TenantId}", tenantId);
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting roles for tenant {TenantId}", tenantId);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取租户配置信息
|
|
/// </summary>
|
|
/// <param name="id">租户ID</param>
|
|
/// <returns>租户的详细配置信息,包括功能开关、配额限制等</returns>
|
|
/// <response code="200">成功返回租户配置</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpGet("{id}/settings")]
|
|
[Produces("application/json")]
|
|
[ProducesResponseType(typeof(TenantSettingsDto), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<ActionResult<TenantSettingsDto>> GetTenantSettings(int id)
|
|
{
|
|
try
|
|
{
|
|
var settings = await _tenantService.GetTenantSettingsAsync(id);
|
|
return Ok(settings);
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Tenant not found: {TenantId}", id);
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting settings for tenant {TenantId}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新租户配置
|
|
/// </summary>
|
|
/// <param name="id">租户ID</param>
|
|
/// <param name="settings">需要更新的租户配置信息</param>
|
|
/// <returns>无内容响应</returns>
|
|
/// <response code="204">成功更新租户配置</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpPut("{id}/settings")]
|
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<IActionResult> UpdateTenantSettings(int id, [FromBody] TenantSettingsDto settings)
|
|
{
|
|
try
|
|
{
|
|
await _tenantService.UpdateTenantSettingsAsync(id, settings);
|
|
return NoContent();
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Tenant not found: {TenantId}", id);
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error updating settings for tenant {TenantId}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 创建新租户
|
|
/// </summary>
|
|
/// <param name="dto">创建租户所需的配置信息</param>
|
|
/// <returns>创建的租户详情</returns>
|
|
/// <response code="201">成功创建租户</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpPost]
|
|
[Produces("application/json")]
|
|
[ProducesResponseType(typeof(TenantDto), StatusCodes.Status201Created)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<ActionResult<TenantDto>> CreateTenant([FromBody] CreateTenantDto dto)
|
|
{
|
|
try
|
|
{
|
|
var tenant = await _tenantService.CreateTenantAsync(dto);
|
|
return CreatedAtAction(nameof(GetTenant), new { id = tenant.Id }, tenant);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error creating tenant");
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新租户信息
|
|
/// </summary>
|
|
/// <param name="id">租户ID</param>
|
|
/// <param name="dto">需要更新的租户配置信息</param>
|
|
/// <returns>无内容响应</returns>
|
|
/// <response code="204">成功更新租户</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpPut("{id}")]
|
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<IActionResult> UpdateTenant(int id, [FromBody] UpdateTenantDto dto)
|
|
{
|
|
try
|
|
{
|
|
await _tenantService.UpdateTenantAsync(id, dto);
|
|
return NoContent();
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Tenant not found: {TenantId}", id);
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error updating tenant {TenantId}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除租户
|
|
/// </summary>
|
|
/// <param name="id">租户ID</param>
|
|
/// <returns>无内容响应</returns>
|
|
/// <response code="204">成功删除租户</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpDelete("{id}")]
|
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<IActionResult> DeleteTenant(int id)
|
|
{
|
|
try
|
|
{
|
|
await _tenantService.DeleteTenantAsync(id);
|
|
return NoContent();
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Tenant not found: {TenantId}", id);
|
|
return NotFound();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error deleting tenant {TenantId}", id);
|
|
return StatusCode(500, new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成H5访问链接和二维码
|
|
/// </summary>
|
|
/// <param name="id">租户ID</param>
|
|
/// <returns>H5链接和二维码Base64</returns>
|
|
/// <response code="200">成功返回链接和二维码</response>
|
|
/// <response code="404">租户不存在</response>
|
|
/// <response code="500">服务器内部错误</response>
|
|
[HttpGet("{id}/h5-link")]
|
|
[Produces("application/json")]
|
|
[ProducesResponseType(typeof(H5LinkResult), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(object), StatusCodes.Status500InternalServerError)]
|
|
public async Task<ActionResult<H5LinkResult>> GetH5Link(int id)
|
|
{
|
|
try
|
|
{
|
|
var result = await _h5LinkService.GenerateH5LinkAsync(id);
|
|
return Ok(result);
|
|
}
|
|
catch (KeyNotFoundException ex)
|
|
{
|
|
_logger.LogWarning(ex, "Tenant not found: {TenantId}", id);
|
|
return NotFound(new { message = ex.Message });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error generating H5 link for tenant {TenantId}", id);
|
|
return StatusCode(500, new { message = "Failed to generate H5 link" });
|
|
}
|
|
}
|
|
} |