feat(store): add quick business toggle endpoint and auto-approve creation
All checks were successful
Build and Deploy TenantApi / build-and-deploy (push) Successful in 42s
All checks were successful
Build and Deploy TenantApi / build-and-deploy (push) Successful in 42s
This commit is contained in:
@@ -108,5 +108,26 @@ public sealed class StoreController(IMediator mediator) : BaseApiController
|
|||||||
// 2. 返回成功响应
|
// 2. 返回成功响应
|
||||||
return ApiResponse<object>.Ok(null);
|
return ApiResponse<object>.Ok(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 快速切换门店经营状态。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">切换命令。</param>
|
||||||
|
/// <param name="cancellationToken">取消标记。</param>
|
||||||
|
/// <returns>切换后的门店信息。</returns>
|
||||||
|
[HttpPost("toggle-business-status")]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<StoreDto>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<StoreDto>), StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(typeof(ApiResponse<StoreDto>), StatusCodes.Status422UnprocessableEntity)]
|
||||||
|
public async Task<ApiResponse<StoreDto>> ToggleBusinessStatus(
|
||||||
|
[FromBody] ToggleBusinessStatusCommand command,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// 1. 执行状态切换
|
||||||
|
var result = await mediator.Send(command, cancellationToken);
|
||||||
|
|
||||||
|
// 2. 返回切换结果
|
||||||
|
return ApiResponse<StoreDto>.Ok(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using TakeoutSaaS.Domain.Stores.Enums;
|
|||||||
using TakeoutSaaS.Domain.Stores.Repositories;
|
using TakeoutSaaS.Domain.Stores.Repositories;
|
||||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||||
|
using TakeoutSaaS.Shared.Abstractions.Security;
|
||||||
|
|
||||||
namespace TakeoutSaaS.Application.App.Stores.Handlers;
|
namespace TakeoutSaaS.Application.App.Stores.Handlers;
|
||||||
|
|
||||||
@@ -16,7 +17,8 @@ namespace TakeoutSaaS.Application.App.Stores.Handlers;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class CreateStoreCommandHandler(
|
public sealed class CreateStoreCommandHandler(
|
||||||
StoreContextService storeContextService,
|
StoreContextService storeContextService,
|
||||||
IStoreRepository storeRepository)
|
IStoreRepository storeRepository,
|
||||||
|
ICurrentUserAccessor currentUserAccessor)
|
||||||
: IRequestHandler<CreateStoreCommand>
|
: IRequestHandler<CreateStoreCommand>
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -24,6 +26,7 @@ public sealed class CreateStoreCommandHandler(
|
|||||||
{
|
{
|
||||||
// 1. 解析上下文
|
// 1. 解析上下文
|
||||||
var context = storeContextService.GetRequiredContext();
|
var context = storeContextService.GetRequiredContext();
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
|
||||||
// 2. 生成唯一门店编码
|
// 2. 生成唯一门店编码
|
||||||
var existingStores = await storeRepository.SearchAsync(
|
var existingStores = await storeRepository.SearchAsync(
|
||||||
@@ -54,15 +57,29 @@ public sealed class CreateStoreCommandHandler(
|
|||||||
CoverImageUrl = request.CoverImage?.Trim(),
|
CoverImageUrl = request.CoverImage?.Trim(),
|
||||||
SignboardImageUrl = request.CoverImage?.Trim(),
|
SignboardImageUrl = request.CoverImage?.Trim(),
|
||||||
OwnershipType = StoreOwnershipType.SameEntity,
|
OwnershipType = StoreOwnershipType.SameEntity,
|
||||||
AuditStatus = StoreAuditStatus.Draft,
|
AuditStatus = StoreAuditStatus.Activated,
|
||||||
BusinessStatus = StoreBusinessStatus.Resting,
|
BusinessStatus = StoreBusinessStatus.Resting,
|
||||||
|
SubmittedAt = now,
|
||||||
|
ActivatedAt = now,
|
||||||
Status = StoreStatus.Operating
|
Status = StoreStatus.Operating
|
||||||
};
|
};
|
||||||
StoreListMapping.ApplyServiceTypes(store, serviceTypes);
|
StoreListMapping.ApplyServiceTypes(store, serviceTypes);
|
||||||
|
|
||||||
// 4. 持久化
|
// 4. 持久化门店并记录自动审核通过
|
||||||
await storeRepository.AddStoreAsync(store, cancellationToken);
|
await storeRepository.AddStoreAsync(store, cancellationToken);
|
||||||
await storeRepository.SaveChangesAsync(cancellationToken);
|
await storeRepository.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
await storeRepository.AddAuditRecordAsync(new StoreAuditRecord
|
||||||
|
{
|
||||||
|
StoreId = store.Id,
|
||||||
|
Action = StoreAuditAction.Approve,
|
||||||
|
PreviousStatus = StoreAuditStatus.Draft,
|
||||||
|
NewStatus = StoreAuditStatus.Activated,
|
||||||
|
OperatorId = ResolveOperatorId(currentUserAccessor),
|
||||||
|
OperatorName = ResolveOperatorName(currentUserAccessor),
|
||||||
|
Remarks = "系统自动审核通过"
|
||||||
|
}, cancellationToken);
|
||||||
|
await storeRepository.SaveChangesAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -87,4 +104,16 @@ public sealed class CreateStoreCommandHandler(
|
|||||||
|
|
||||||
throw new BusinessException(ErrorCodes.Conflict, "门店编码生成失败,请稍后重试");
|
throw new BusinessException(ErrorCodes.Conflict, "门店编码生成失败,请稍后重试");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static long? ResolveOperatorId(ICurrentUserAccessor currentUserAccessor)
|
||||||
|
{
|
||||||
|
var id = currentUserAccessor.UserId;
|
||||||
|
return id == 0 ? null : id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolveOperatorName(ICurrentUserAccessor currentUserAccessor)
|
||||||
|
{
|
||||||
|
var id = currentUserAccessor.UserId;
|
||||||
|
return id == 0 ? "system" : $"user:{id}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user