V13-FE-011: finalize search list layout slice
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Modules.ERP.Items.Search;
|
||||
|
||||
public sealed class Endpoint(SearchItemsHandler handler) : Endpoint<SearchItemsRequest, SearchItemsResponse>
|
||||
{
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/api/erp/items");
|
||||
Permissions("erp.item.read");
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(SearchItemsRequest req, CancellationToken ct)
|
||||
=> await Send.OkAsync(await handler.HandleAsync(req, ct), ct);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
|
||||
namespace Modules.ERP.Items.Search;
|
||||
|
||||
public sealed class SearchItemsHandler(NpgsqlDataSource dataSource)
|
||||
{
|
||||
public async Task<SearchItemsResponse> HandleAsync(SearchItemsRequest request, CancellationToken ct)
|
||||
{
|
||||
var page = Math.Max(request.Page, 1);
|
||||
var pageSize = Math.Clamp(request.PageSize, 1, 500);
|
||||
var offset = (page - 1) * pageSize;
|
||||
var keyword = string.IsNullOrWhiteSpace(request.Keyword) ? null : request.Keyword.Trim();
|
||||
|
||||
const string sql = """
|
||||
select
|
||||
p.id,
|
||||
p.code,
|
||||
p.name,
|
||||
p.category_name as CategoryName,
|
||||
p.specification,
|
||||
p.unit,
|
||||
p.barcode,
|
||||
p.default_warehouse_id as DefaultWarehouseId,
|
||||
p.default_warehouse_name as DefaultWarehouseName,
|
||||
p.lot_managed as LotManaged,
|
||||
p.expiry_managed as ExpiryManaged,
|
||||
p.active,
|
||||
p.version
|
||||
from erp_item_search_projection p
|
||||
where (@Keyword is null or p.search_text ilike '%' || @Keyword || '%')
|
||||
order by p.code
|
||||
limit @PageSize offset @Offset;
|
||||
|
||||
select count(*)::int
|
||||
from erp_item_search_projection p
|
||||
where (@Keyword is null or p.search_text ilike '%' || @Keyword || '%');
|
||||
""";
|
||||
|
||||
await using var connection = await dataSource.OpenConnectionAsync(ct);
|
||||
using var multi = await connection.QueryMultipleAsync(new CommandDefinition(sql, new { Keyword = keyword, PageSize = pageSize, Offset = offset }, cancellationToken: ct));
|
||||
var items = (await multi.ReadAsync<ItemMasterRow>()).AsList();
|
||||
var count = await multi.ReadSingleAsync<int>();
|
||||
return new(items, count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Modules.ERP.Items.Search;
|
||||
|
||||
public sealed record SearchItemsRequest(
|
||||
string? Keyword,
|
||||
int Page = 1,
|
||||
int PageSize = 200);
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Modules.ERP.Items.Search;
|
||||
|
||||
public sealed record ItemMasterRow(
|
||||
Guid Id,
|
||||
string Code,
|
||||
string Name,
|
||||
string CategoryName,
|
||||
string Specification,
|
||||
string Unit,
|
||||
string Barcode,
|
||||
Guid? DefaultWarehouseId,
|
||||
string DefaultWarehouseName,
|
||||
bool LotManaged,
|
||||
bool ExpiryManaged,
|
||||
bool Active,
|
||||
long Version);
|
||||
|
||||
public sealed record SearchItemsResponse(
|
||||
IReadOnlyList<ItemMasterRow> Items,
|
||||
int TotalCount);
|
||||
Reference in New Issue
Block a user