feat: 系统参数应用层与验证
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Queries;
|
||||
using TakeoutSaaS.Module.Authorization.Attributes;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
using TakeoutSaaS.Shared.Web.Api;
|
||||
|
||||
namespace TakeoutSaaS.AdminApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 系统参数管理。
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 提供参数的新增、修改、查询与删除。
|
||||
/// </remarks>
|
||||
[ApiVersion("1.0")]
|
||||
[Authorize]
|
||||
[Route("api/admin/v{version:apiVersion}/system-parameters")]
|
||||
public sealed class SystemParametersController(IMediator mediator) : BaseApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建系统参数。
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[PermissionAuthorize("system-parameter:create")]
|
||||
[ProducesResponseType(typeof(ApiResponse<SystemParameterDto>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<SystemParameterDto>> Create([FromBody] CreateSystemParameterCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
return ApiResponse<SystemParameterDto>.Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询系统参数列表。
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[PermissionAuthorize("system-parameter:read")]
|
||||
[ProducesResponseType(typeof(ApiResponse<PagedResult<SystemParameterDto>>), StatusCodes.Status200OK)]
|
||||
public async Task<ApiResponse<PagedResult<SystemParameterDto>>> List(
|
||||
[FromQuery] string? keyword,
|
||||
[FromQuery] bool? isEnabled,
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 20,
|
||||
[FromQuery] string? sortBy = null,
|
||||
[FromQuery] bool sortDesc = true,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var result = await mediator.Send(new SearchSystemParametersQuery
|
||||
{
|
||||
Keyword = keyword,
|
||||
IsEnabled = isEnabled,
|
||||
Page = page,
|
||||
PageSize = pageSize,
|
||||
SortBy = sortBy,
|
||||
SortDescending = sortDesc
|
||||
}, cancellationToken);
|
||||
|
||||
return ApiResponse<PagedResult<SystemParameterDto>>.Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统参数详情。
|
||||
/// </summary>
|
||||
[HttpGet("{parameterId:long}")]
|
||||
[PermissionAuthorize("system-parameter:read")]
|
||||
[ProducesResponseType(typeof(ApiResponse<SystemParameterDto>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
|
||||
public async Task<ApiResponse<SystemParameterDto>> Detail(long parameterId, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = await mediator.Send(new GetSystemParameterByIdQuery(parameterId), cancellationToken);
|
||||
return result == null
|
||||
? ApiResponse<SystemParameterDto>.Error(ErrorCodes.NotFound, "系统参数不存在")
|
||||
: ApiResponse<SystemParameterDto>.Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新系统参数。
|
||||
/// </summary>
|
||||
[HttpPut("{parameterId:long}")]
|
||||
[PermissionAuthorize("system-parameter:update")]
|
||||
[ProducesResponseType(typeof(ApiResponse<SystemParameterDto>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
|
||||
public async Task<ApiResponse<SystemParameterDto>> Update(long parameterId, [FromBody] UpdateSystemParameterCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
if (command.ParameterId == 0)
|
||||
{
|
||||
command = command with { ParameterId = parameterId };
|
||||
}
|
||||
|
||||
var result = await mediator.Send(command, cancellationToken);
|
||||
return result == null
|
||||
? ApiResponse<SystemParameterDto>.Error(ErrorCodes.NotFound, "系统参数不存在")
|
||||
: ApiResponse<SystemParameterDto>.Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除系统参数。
|
||||
/// </summary>
|
||||
[HttpDelete("{parameterId:long}")]
|
||||
[PermissionAuthorize("system-parameter:delete")]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
|
||||
public async Task<ApiResponse<object>> Delete(long parameterId, CancellationToken cancellationToken)
|
||||
{
|
||||
var success = await mediator.Send(new DeleteSystemParameterCommand { ParameterId = parameterId }, cancellationToken);
|
||||
return success
|
||||
? ApiResponse.Success()
|
||||
: ApiResponse<object>.Error(ErrorCodes.NotFound, "系统参数不存在");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 创建系统参数命令。
|
||||
/// </summary>
|
||||
public sealed class CreateSystemParameterCommand : IRequest<SystemParameterDto>
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数键。
|
||||
/// </summary>
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 参数值。
|
||||
/// </summary>
|
||||
public string Value { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 描述。
|
||||
/// </summary>
|
||||
public string? Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序值。
|
||||
/// </summary>
|
||||
public int SortOrder { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用。
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using MediatR;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 删除系统参数命令。
|
||||
/// </summary>
|
||||
public sealed record DeleteSystemParameterCommand : IRequest<bool>
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数 ID。
|
||||
/// </summary>
|
||||
public long ParameterId { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// 更新系统参数命令。
|
||||
/// </summary>
|
||||
public sealed record UpdateSystemParameterCommand : IRequest<SystemParameterDto?>
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数 ID。
|
||||
/// </summary>
|
||||
public long ParameterId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数键。
|
||||
/// </summary>
|
||||
public string Key { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 参数值。
|
||||
/// </summary>
|
||||
public string Value { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 描述。
|
||||
/// </summary>
|
||||
public string? Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序值。
|
||||
/// </summary>
|
||||
public int SortOrder { get; init; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用。
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; init; } = true;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using TakeoutSaaS.Shared.Abstractions.Serialization;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
|
||||
/// <summary>
|
||||
/// 系统参数 DTO。
|
||||
/// </summary>
|
||||
public sealed class SystemParameterDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 参数 ID。
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户 ID。
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(SnowflakeIdJsonConverter))]
|
||||
public long TenantId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 参数键。
|
||||
/// </summary>
|
||||
public string Key { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 参数值。
|
||||
/// </summary>
|
||||
public string Value { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 描述。
|
||||
/// </summary>
|
||||
public string? Description { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序值。
|
||||
/// </summary>
|
||||
public int SortOrder { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用。
|
||||
/// </summary>
|
||||
public bool IsEnabled { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间。
|
||||
/// </summary>
|
||||
public DateTime CreatedAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 最近更新时间。
|
||||
/// </summary>
|
||||
public DateTime? UpdatedAt { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Entities;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 创建系统参数命令处理器。
|
||||
/// </summary>
|
||||
public sealed class CreateSystemParameterCommandHandler(
|
||||
ISystemParameterRepository repository,
|
||||
ILogger<CreateSystemParameterCommandHandler> logger)
|
||||
: IRequestHandler<CreateSystemParameterCommand, SystemParameterDto>
|
||||
{
|
||||
private readonly ISystemParameterRepository _repository = repository;
|
||||
private readonly ILogger<CreateSystemParameterCommandHandler> _logger = logger;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SystemParameterDto> Handle(CreateSystemParameterCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. 唯一性校验
|
||||
var existing = await _repository.FindByKeyAsync(request.Key, cancellationToken);
|
||||
if (existing != null)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Conflict, "系统参数键已存在");
|
||||
}
|
||||
|
||||
// 2. 构建实体
|
||||
var parameter = new SystemParameter
|
||||
{
|
||||
Key = request.Key.Trim(),
|
||||
Value = request.Value.Trim(),
|
||||
Description = request.Description?.Trim(),
|
||||
SortOrder = request.SortOrder,
|
||||
IsEnabled = request.IsEnabled
|
||||
};
|
||||
|
||||
// 3. 持久化
|
||||
await _repository.AddAsync(parameter, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
_logger.LogInformation("创建系统参数 {Key}", parameter.Key);
|
||||
|
||||
// 4. 映射返回
|
||||
return MapToDto(parameter);
|
||||
}
|
||||
|
||||
private static SystemParameterDto MapToDto(SystemParameter parameter) => new()
|
||||
{
|
||||
Id = parameter.Id,
|
||||
TenantId = parameter.TenantId,
|
||||
Key = parameter.Key,
|
||||
Value = parameter.Value,
|
||||
Description = parameter.Description,
|
||||
SortOrder = parameter.SortOrder,
|
||||
IsEnabled = parameter.IsEnabled,
|
||||
CreatedAt = parameter.CreatedAt,
|
||||
UpdatedAt = parameter.UpdatedAt
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 删除系统参数命令处理器。
|
||||
/// </summary>
|
||||
public sealed class DeleteSystemParameterCommandHandler(
|
||||
ISystemParameterRepository repository,
|
||||
ILogger<DeleteSystemParameterCommandHandler> logger)
|
||||
: IRequestHandler<DeleteSystemParameterCommand, bool>
|
||||
{
|
||||
private readonly ISystemParameterRepository _repository = repository;
|
||||
private readonly ILogger<DeleteSystemParameterCommandHandler> _logger = logger;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<bool> Handle(DeleteSystemParameterCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var existing = await _repository.FindByIdAsync(request.ParameterId, cancellationToken);
|
||||
if (existing == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
await _repository.RemoveAsync(existing, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
_logger.LogInformation("删除系统参数 {Key}", existing.Key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Queries;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统参数详情查询处理器。
|
||||
/// </summary>
|
||||
public sealed class GetSystemParameterByIdQueryHandler(ISystemParameterRepository repository)
|
||||
: IRequestHandler<GetSystemParameterByIdQuery, SystemParameterDto?>
|
||||
{
|
||||
private readonly ISystemParameterRepository _repository = repository;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SystemParameterDto?> Handle(GetSystemParameterByIdQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var parameter = await _repository.FindByIdAsync(request.ParameterId, cancellationToken);
|
||||
return parameter == null ? null : MapToDto(parameter);
|
||||
}
|
||||
|
||||
private static SystemParameterDto MapToDto(Domain.SystemParameters.Entities.SystemParameter parameter) => new()
|
||||
{
|
||||
Id = parameter.Id,
|
||||
TenantId = parameter.TenantId,
|
||||
Key = parameter.Key,
|
||||
Value = parameter.Value,
|
||||
Description = parameter.Description,
|
||||
SortOrder = parameter.SortOrder,
|
||||
IsEnabled = parameter.IsEnabled,
|
||||
CreatedAt = parameter.CreatedAt,
|
||||
UpdatedAt = parameter.UpdatedAt
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Queries;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 系统参数列表查询处理器。
|
||||
/// </summary>
|
||||
public sealed class SearchSystemParametersQueryHandler(ISystemParameterRepository repository)
|
||||
: IRequestHandler<SearchSystemParametersQuery, PagedResult<SystemParameterDto>>
|
||||
{
|
||||
private readonly ISystemParameterRepository _repository = repository;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<PagedResult<SystemParameterDto>> Handle(SearchSystemParametersQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var parameters = await _repository.SearchAsync(request.Keyword, request.IsEnabled, cancellationToken);
|
||||
|
||||
var sorted = ApplySorting(parameters, request.SortBy, request.SortDescending);
|
||||
var paged = sorted
|
||||
.Skip((request.Page - 1) * request.PageSize)
|
||||
.Take(request.PageSize)
|
||||
.ToList();
|
||||
|
||||
var items = paged.Select(MapToDto).ToList();
|
||||
return new PagedResult<SystemParameterDto>(items, request.Page, request.PageSize, parameters.Count);
|
||||
}
|
||||
|
||||
private static IOrderedEnumerable<Domain.SystemParameters.Entities.SystemParameter> ApplySorting(
|
||||
IReadOnlyCollection<Domain.SystemParameters.Entities.SystemParameter> parameters,
|
||||
string? sortBy,
|
||||
bool sortDescending)
|
||||
{
|
||||
return sortBy?.ToLowerInvariant() switch
|
||||
{
|
||||
"key" => sortDescending
|
||||
? parameters.OrderByDescending(x => x.Key)
|
||||
: parameters.OrderBy(x => x.Key),
|
||||
"sortorder" => sortDescending
|
||||
? parameters.OrderByDescending(x => x.SortOrder)
|
||||
: parameters.OrderBy(x => x.SortOrder),
|
||||
"updatedat" => sortDescending
|
||||
? parameters.OrderByDescending(x => x.UpdatedAt ?? x.CreatedAt)
|
||||
: parameters.OrderBy(x => x.UpdatedAt ?? x.CreatedAt),
|
||||
"isenabled" => sortDescending
|
||||
? parameters.OrderByDescending(x => x.IsEnabled)
|
||||
: parameters.OrderBy(x => x.IsEnabled),
|
||||
_ => sortDescending
|
||||
? parameters.OrderByDescending(x => x.CreatedAt)
|
||||
: parameters.OrderBy(x => x.CreatedAt)
|
||||
};
|
||||
}
|
||||
|
||||
private static SystemParameterDto MapToDto(Domain.SystemParameters.Entities.SystemParameter parameter) => new()
|
||||
{
|
||||
Id = parameter.Id,
|
||||
TenantId = parameter.TenantId,
|
||||
Key = parameter.Key,
|
||||
Value = parameter.Value,
|
||||
Description = parameter.Description,
|
||||
SortOrder = parameter.SortOrder,
|
||||
IsEnabled = parameter.IsEnabled,
|
||||
CreatedAt = parameter.CreatedAt,
|
||||
UpdatedAt = parameter.UpdatedAt
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Handlers;
|
||||
|
||||
/// <summary>
|
||||
/// 更新系统参数命令处理器。
|
||||
/// </summary>
|
||||
public sealed class UpdateSystemParameterCommandHandler(
|
||||
ISystemParameterRepository repository,
|
||||
ILogger<UpdateSystemParameterCommandHandler> logger)
|
||||
: IRequestHandler<UpdateSystemParameterCommand, SystemParameterDto?>
|
||||
{
|
||||
private readonly ISystemParameterRepository _repository = repository;
|
||||
private readonly ILogger<UpdateSystemParameterCommandHandler> _logger = logger;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<SystemParameterDto?> Handle(UpdateSystemParameterCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// 1. 读取已有参数
|
||||
var existing = await _repository.FindByIdAsync(request.ParameterId, cancellationToken);
|
||||
if (existing == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 唯一性校验
|
||||
var duplicate = await _repository.FindByKeyAsync(request.Key, cancellationToken);
|
||||
if (duplicate != null && duplicate.Id != existing.Id)
|
||||
{
|
||||
throw new BusinessException(ErrorCodes.Conflict, "系统参数键已存在");
|
||||
}
|
||||
|
||||
// 3. 更新字段
|
||||
existing.Key = request.Key.Trim();
|
||||
existing.Value = request.Value.Trim();
|
||||
existing.Description = request.Description?.Trim();
|
||||
existing.SortOrder = request.SortOrder;
|
||||
existing.IsEnabled = request.IsEnabled;
|
||||
|
||||
// 4. 持久化
|
||||
await _repository.UpdateAsync(existing, cancellationToken);
|
||||
await _repository.SaveChangesAsync(cancellationToken);
|
||||
_logger.LogInformation("更新系统参数 {Key}", existing.Key);
|
||||
|
||||
return MapToDto(existing);
|
||||
}
|
||||
|
||||
private static SystemParameterDto MapToDto(Domain.SystemParameters.Entities.SystemParameter parameter) => new()
|
||||
{
|
||||
Id = parameter.Id,
|
||||
TenantId = parameter.TenantId,
|
||||
Key = parameter.Key,
|
||||
Value = parameter.Value,
|
||||
Description = parameter.Description,
|
||||
SortOrder = parameter.SortOrder,
|
||||
IsEnabled = parameter.IsEnabled,
|
||||
CreatedAt = parameter.CreatedAt,
|
||||
UpdatedAt = parameter.UpdatedAt
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 获取系统参数详情查询。
|
||||
/// </summary>
|
||||
public sealed record GetSystemParameterByIdQuery(long ParameterId) : IRequest<SystemParameterDto?>;
|
||||
@@ -0,0 +1,41 @@
|
||||
using MediatR;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Dto;
|
||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Queries;
|
||||
|
||||
/// <summary>
|
||||
/// 系统参数列表查询。
|
||||
/// </summary>
|
||||
public sealed class SearchSystemParametersQuery : IRequest<PagedResult<SystemParameterDto>>
|
||||
{
|
||||
/// <summary>
|
||||
/// 关键字(匹配 Key/Description)。
|
||||
/// </summary>
|
||||
public string? Keyword { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 启用状态过滤。
|
||||
/// </summary>
|
||||
public bool? IsEnabled { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 页码。
|
||||
/// </summary>
|
||||
public int Page { get; init; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 每页条数。
|
||||
/// </summary>
|
||||
public int PageSize { get; init; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// 排序字段(key/sortOrder/createdAt/updatedAt/isEnabled)。
|
||||
/// </summary>
|
||||
public string? SortBy { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否倒序。
|
||||
/// </summary>
|
||||
public bool SortDescending { get; init; } = true;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using FluentValidation;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Validators;
|
||||
|
||||
/// <summary>
|
||||
/// 创建系统参数命令验证器。
|
||||
/// </summary>
|
||||
public sealed class CreateSystemParameterCommandValidator : AbstractValidator<CreateSystemParameterCommand>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化验证规则。
|
||||
/// </summary>
|
||||
public CreateSystemParameterCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.Key).NotEmpty().MaximumLength(128);
|
||||
RuleFor(x => x.Value).NotEmpty();
|
||||
RuleFor(x => x.Description).MaximumLength(512);
|
||||
RuleFor(x => x.SortOrder).GreaterThanOrEqualTo(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using FluentValidation;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Queries;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Validators;
|
||||
|
||||
/// <summary>
|
||||
/// 系统参数列表查询验证器。
|
||||
/// </summary>
|
||||
public sealed class SearchSystemParametersQueryValidator : AbstractValidator<SearchSystemParametersQuery>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化验证规则。
|
||||
/// </summary>
|
||||
public SearchSystemParametersQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.Page).GreaterThan(0);
|
||||
RuleFor(x => x.PageSize).InclusiveBetween(1, 200);
|
||||
RuleFor(x => x.Keyword).MaximumLength(256);
|
||||
RuleFor(x => x.SortBy).MaximumLength(64);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using FluentValidation;
|
||||
using TakeoutSaaS.Application.App.SystemParameters.Commands;
|
||||
|
||||
namespace TakeoutSaaS.Application.App.SystemParameters.Validators;
|
||||
|
||||
/// <summary>
|
||||
/// 更新系统参数命令验证器。
|
||||
/// </summary>
|
||||
public sealed class UpdateSystemParameterCommandValidator : AbstractValidator<UpdateSystemParameterCommand>
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化验证规则。
|
||||
/// </summary>
|
||||
public UpdateSystemParameterCommandValidator()
|
||||
{
|
||||
RuleFor(x => x.ParameterId).GreaterThan(0);
|
||||
RuleFor(x => x.Key).NotEmpty().MaximumLength(128);
|
||||
RuleFor(x => x.Value).NotEmpty();
|
||||
RuleFor(x => x.Description).MaximumLength(512);
|
||||
RuleFor(x => x.SortOrder).GreaterThanOrEqualTo(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Entities;
|
||||
|
||||
namespace TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 系统参数仓储接口:提供基础 CRUD 与查询能力。
|
||||
/// </summary>
|
||||
public interface ISystemParameterRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据标识获取系统参数。
|
||||
/// </summary>
|
||||
Task<SystemParameter?> FindByIdAsync(long id, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 根据键获取系统参数(当前租户)。
|
||||
/// </summary>
|
||||
Task<SystemParameter?> FindByKeyAsync(string key, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 查询系统参数列表。
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<SystemParameter>> SearchAsync(string? keyword, bool? isEnabled, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 新增系统参数。
|
||||
/// </summary>
|
||||
Task AddAsync(SystemParameter parameter, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 删除系统参数。
|
||||
/// </summary>
|
||||
Task RemoveAsync(SystemParameter parameter, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 更新系统参数。
|
||||
/// </summary>
|
||||
Task UpdateAsync(SystemParameter parameter, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// 持久化更改。
|
||||
/// </summary>
|
||||
Task SaveChangesAsync(CancellationToken cancellationToken = default);
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
using TakeoutSaaS.Infrastructure.Dictionary.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Dictionary.Services;
|
||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Dictionary.Extensions;
|
||||
|
||||
@@ -31,6 +32,7 @@ public static class DictionaryServiceCollectionExtensions
|
||||
services.AddPostgresDbContext<DictionaryDbContext>(DatabaseConstants.DictionaryDataSource);
|
||||
|
||||
services.AddScoped<IDictionaryRepository, EfDictionaryRepository>();
|
||||
services.AddScoped<ISystemParameterRepository, EfSystemParameterRepository>();
|
||||
services.AddScoped<IDictionaryCache, DistributedDictionaryCache>();
|
||||
|
||||
services.AddOptions<DictionaryCacheOptions>()
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Entities;
|
||||
using TakeoutSaaS.Domain.SystemParameters.Repositories;
|
||||
using TakeoutSaaS.Infrastructure.Dictionary.Persistence;
|
||||
|
||||
namespace TakeoutSaaS.Infrastructure.Dictionary.Repositories;
|
||||
|
||||
/// <summary>
|
||||
/// 系统参数 EF Core 仓储实现。
|
||||
/// </summary>
|
||||
public sealed class EfSystemParameterRepository(DictionaryDbContext context) : ISystemParameterRepository
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public Task<SystemParameter?> FindByIdAsync(long id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.SystemParameters
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<SystemParameter?> FindByKeyAsync(string key, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var normalizedKey = key.Trim();
|
||||
return context.SystemParameters
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.Key == normalizedKey, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<SystemParameter>> SearchAsync(string? keyword, bool? isEnabled, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var query = context.SystemParameters.AsNoTracking();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(keyword))
|
||||
{
|
||||
var normalized = keyword.Trim();
|
||||
query = query.Where(x => x.Key.Contains(normalized) || (x.Description != null && x.Description.Contains(normalized)));
|
||||
}
|
||||
|
||||
if (isEnabled.HasValue)
|
||||
{
|
||||
query = query.Where(x => x.IsEnabled == isEnabled.Value);
|
||||
}
|
||||
|
||||
var parameters = await query
|
||||
.OrderBy(x => x.SortOrder)
|
||||
.ThenBy(x => x.Key)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task AddAsync(SystemParameter parameter, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.SystemParameters.AddAsync(parameter, cancellationToken).AsTask();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task RemoveAsync(SystemParameter parameter, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.SystemParameters.Remove(parameter);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UpdateAsync(SystemParameter parameter, CancellationToken cancellationToken = default)
|
||||
{
|
||||
context.SystemParameters.Update(parameter);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user