TD-001 - PUT /api/admin/v1/tenants/{tenantId}:
- 新增 UpdateTenantCommand + UpdateTenantCommandHandler
- Controller 新增 Update 端点(tenant:update 权限)
- 校验:租户存在、name 非空、name/contactPhone 冲突返回 409
- 仓储扩展:ITenantRepository.ExistsByNameAsync
TD-002 - GET /api/admin/v1/tenants/{tenantId}/quota-usage-history:
- 新增 CQRS Query/Handler/DTO/Validator
- 支持分页(Page>=1, PageSize 1~100)
- 支持时间范围和 QuotaType 过滤
- 新增 tenant_quota_usage_histories 表(含迁移)
- 写入点:CheckTenantQuotaCommandHandler + PurchaseQuotaPackageCommandHandler
构建验证:dotnet build 通过
数据库迁移:已应用 20251218121053_AddTenantQuotaUsageHistories
73 lines
3.1 KiB
C#
73 lines
3.1 KiB
C#
using MediatR;
|
||
using Microsoft.Extensions.Logging;
|
||
using TakeoutSaaS.Application.App.Tenants.Commands;
|
||
using TakeoutSaaS.Domain.Tenants.Repositories;
|
||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||
|
||
namespace TakeoutSaaS.Application.App.Tenants.Handlers;
|
||
|
||
/// <summary>
|
||
/// 更新租户基础信息处理器。
|
||
/// </summary>
|
||
public sealed class UpdateTenantCommandHandler(
|
||
ITenantRepository tenantRepository,
|
||
ILogger<UpdateTenantCommandHandler> logger)
|
||
: IRequestHandler<UpdateTenantCommand, Unit>
|
||
{
|
||
/// <inheritdoc />
|
||
public async Task<Unit> Handle(UpdateTenantCommand request, CancellationToken cancellationToken)
|
||
{
|
||
// 1. 参数校验
|
||
if (request.TenantId <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.BadRequest, "tenantId 不能为空");
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
throw new BusinessException(ErrorCodes.BadRequest, "租户名称不能为空");
|
||
}
|
||
|
||
// 2. (空行后) 查询租户
|
||
var tenant = await tenantRepository.FindByIdAsync(request.TenantId, cancellationToken)
|
||
?? throw new BusinessException(ErrorCodes.NotFound, "租户不存在");
|
||
|
||
// 3. (空行后) 校验租户名称唯一性(排除自身)
|
||
var normalizedName = request.Name.Trim();
|
||
if (await tenantRepository.ExistsByNameAsync(normalizedName, excludeTenantId: request.TenantId, cancellationToken))
|
||
{
|
||
throw new BusinessException(ErrorCodes.Conflict, $"租户名称 {normalizedName} 已存在");
|
||
}
|
||
|
||
// 4. (空行后) 校验联系人手机号唯一性(仅当填写时)
|
||
if (!string.IsNullOrWhiteSpace(request.ContactPhone))
|
||
{
|
||
var normalizedPhone = request.ContactPhone.Trim();
|
||
var existingTenantId = await tenantRepository.FindTenantIdByContactPhoneAsync(normalizedPhone, cancellationToken);
|
||
if (existingTenantId.HasValue && existingTenantId.Value != request.TenantId)
|
||
{
|
||
throw new BusinessException(ErrorCodes.Conflict, $"手机号 {normalizedPhone} 已注册");
|
||
}
|
||
}
|
||
|
||
// 5. (空行后) 更新基础信息(禁止修改 Code)
|
||
tenant.Name = normalizedName;
|
||
tenant.ShortName = string.IsNullOrWhiteSpace(request.ShortName) ? null : request.ShortName.Trim();
|
||
tenant.Industry = string.IsNullOrWhiteSpace(request.Industry) ? null : request.Industry.Trim();
|
||
tenant.ContactName = string.IsNullOrWhiteSpace(request.ContactName) ? null : request.ContactName.Trim();
|
||
tenant.ContactPhone = string.IsNullOrWhiteSpace(request.ContactPhone) ? null : request.ContactPhone.Trim();
|
||
tenant.ContactEmail = string.IsNullOrWhiteSpace(request.ContactEmail) ? null : request.ContactEmail.Trim();
|
||
|
||
// 6. (空行后) 持久化更新
|
||
await tenantRepository.UpdateTenantAsync(tenant, cancellationToken);
|
||
await tenantRepository.SaveChangesAsync(cancellationToken);
|
||
|
||
// 7. (空行后) 记录日志
|
||
logger.LogInformation("已更新租户基础信息 {TenantId}", tenant.Id);
|
||
|
||
return Unit.Value;
|
||
}
|
||
}
|
||
|