feat: 卖价/买价列表支持按需加载明细,缩短切换卡顿
All checks were successful
Build and Deploy / deploy (push) Successful in 1m6s

列表接口增加 includeDetails,并新增单条 price/get,供编辑弹窗按需拉取完整矩阵。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-10-07 13:36:19 +08:00
parent 6faadcf2a1
commit a164d8c837
4 changed files with 110 additions and 14 deletions

View File

@ -101,17 +101,20 @@ public partial class SalesProductService
/// <summary>
/// 一次性装配价格项、因子和明细,避免接口层 N+1 查询。
/// includeDetails=false 时跳过明细(列表页首屏),显著减小载荷。
/// </summary>
private async Task<List<SalesProductPriceListOutput>> GetPriceOutputsAsync(int salesProductId)
private async Task<List<SalesProductPriceListOutput>> GetPriceOutputsAsync(int salesProductId, bool includeDetails = true)
{
var prices = await SalesProductRepository.GetPricesAsync(salesProductId);
var priceIds = prices.Select(x => x.Id).ToArray();
var factorMap = (await SalesProductRepository.GetPriceFactorsAsync(priceIds))
.GroupBy(x => x.PriceId)
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.SerialNumber).ToList());
var detailMap = (await SalesProductRepository.GetPriceDetailsAsync(priceIds))
var detailMap = includeDetails
? (await SalesProductRepository.GetPriceDetailsAsync(priceIds))
.GroupBy(x => x.PriceId)
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.Id).ToList());
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.Id).ToList())
: new Dictionary<int, List<SalesProductPriceDetail>>();
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
prices.SelectMany(x => new[] { x.CreateUserId, x.UpdateUserId }));
@ -128,7 +131,9 @@ public partial class SalesProductService
Currency = price.Currency,
ChargingCondition = price.ChargingCondition,
Factors = factorMap.TryGetValue(price.Id, out var factors) ? factors.Select(MapPriceFactorOutput).ToList() : [],
Details = detailMap.TryGetValue(price.Id, out var details) ? details.Select(MapPriceDetailOutput).ToList() : [],
Details = includeDetails && detailMap.TryGetValue(price.Id, out var details)
? details.Select(MapPriceDetailOutput).ToList()
: [],
CreateTime = price.CreateTime,
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(price.CreateUserId, auditUserNameMap),
UpdateTime = OmsDocHelper.NullIfDefault(price.UpdateTime),
@ -136,6 +141,38 @@ public partial class SalesProductService
}).ToList();
}
/// <summary>
/// 单条价格项(含因子+明细),供编辑弹窗按需加载。
/// </summary>
private async Task<SalesProductPriceListOutput> GetPriceOutputByIdAsync(int priceId)
{
var price = await GetPriceOrThrowAsync(priceId);
var priceIds = new[] { price.Id };
var factors = await SalesProductRepository.GetPriceFactorsAsync(priceIds);
var details = await SalesProductRepository.GetPriceDetailsAsync(priceIds);
var auditUserNameMap = await UserDisplayNameResolver.ResolveManyAsync(
[price.CreateUserId, price.UpdateUserId]);
return new SalesProductPriceListOutput
{
Id = price.Id,
SalesProductId = price.SalesProductId,
SerialNumber = price.SerialNumber,
Status = (byte)price.Status,
PriceName = price.PriceName,
CostItem = price.CostItem,
CostUnit = price.CostUnit,
Currency = price.Currency,
ChargingCondition = price.ChargingCondition,
Factors = factors.OrderBy(item => item.SerialNumber).Select(MapPriceFactorOutput).ToList(),
Details = details.OrderBy(item => item.Id).Select(MapPriceDetailOutput).ToList(),
CreateTime = price.CreateTime,
CreateBy = OmsRbacUserDisplayNameResolver.FormatUserId(price.CreateUserId, auditUserNameMap),
UpdateTime = OmsDocHelper.NullIfDefault(price.UpdateTime),
UpdateBy = OmsRbacUserDisplayNameResolver.FormatUserId(price.UpdateUserId, auditUserNameMap)
};
}
/// <summary>
/// 获取排货方案,并补充服务渠道名称。
/// </summary>

View File

@ -169,17 +169,29 @@ public partial class SalesProductService : ApplicationService
/// 查询销售产品价格项列表。
/// </summary>
/// <param name="salesProductId">入参:销售产品主键。</param>
/// <param name="includeDetails">是否返回价格明细矩阵;列表页建议 false。</param>
/// <returns>销售产品价格项列表结果。</returns>
[HttpGet("/channel/sales-product/price/list")]
public async Task<OmsItemsResult<SalesProductPriceListOutput>> GetPriceListAsync([FromQuery] int salesProductId)
public async Task<OmsItemsResult<SalesProductPriceListOutput>> GetPriceListAsync(
[FromQuery] int salesProductId,
[FromQuery] bool includeDetails = true)
{
await GetProductOrThrowAsync(salesProductId);
return new OmsItemsResult<SalesProductPriceListOutput>
{
Items = await GetPriceOutputsAsync(salesProductId)
Items = await GetPriceOutputsAsync(salesProductId, includeDetails)
};
}
/// <summary>
/// 获取单条销售产品价格项(含计费因子与价格明细)。
/// </summary>
[HttpGet("/channel/sales-product/price/get")]
public async Task<SalesProductPriceListOutput> GetPriceAsync([FromQuery] int id)
{
return await GetPriceOutputByIdAsync(id);
}
/// <summary>
/// 新增销售产品价格项。
/// </summary>

View File

@ -146,17 +146,22 @@ public partial class ServiceChannelService
/// <summary>
/// 一次性装配买价项、因子和明细,避免接口层 N+1 查询。
/// includeDetails=false 时跳过明细(列表页首屏),显著减小载荷。
/// </summary>
private async Task<List<ServiceChannelPriceListOutput>> GetPriceOutputsAsync(int serviceChannelId)
private async Task<List<ServiceChannelPriceListOutput>> GetPriceOutputsAsync(
int serviceChannelId,
bool includeDetails = true)
{
var prices = await ServiceChannelRepository.GetPricesAsync(serviceChannelId);
var priceIds = prices.Select(x => x.Id).ToArray();
var factorMap = (await ServiceChannelRepository.GetPriceFactorsAsync(priceIds))
.GroupBy(x => x.PriceId)
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.SerialNumber).ToList());
var detailMap = (await ServiceChannelRepository.GetPriceDetailsAsync(priceIds))
var detailMap = includeDetails
? (await ServiceChannelRepository.GetPriceDetailsAsync(priceIds))
.GroupBy(x => x.PriceId)
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.Id).ToList());
.ToDictionary(x => x.Key, x => x.OrderBy(item => item.Id).ToList())
: new Dictionary<int, List<ServiceChannelPriceDetail>>();
return prices.Select(price => new ServiceChannelPriceListOutput
{
@ -170,12 +175,42 @@ public partial class ServiceChannelService
Currency = price.Currency,
ChargingCondition = price.ChargingCondition,
Factors = factorMap.TryGetValue(price.Id, out var factors) ? factors.Select(MapPriceFactorOutput).ToList() : [],
Details = detailMap.TryGetValue(price.Id, out var details) ? details.Select(MapPriceDetailOutput).ToList() : [],
Details = includeDetails && detailMap.TryGetValue(price.Id, out var details)
? details.Select(MapPriceDetailOutput).ToList()
: [],
CreateTime = price.CreateTime,
UpdateTime = OmsDocHelper.NullIfDefault(price.UpdateTime)
}).ToList();
}
/// <summary>
/// 单条买价项(含因子+明细),供编辑弹窗按需加载。
/// </summary>
private async Task<ServiceChannelPriceListOutput> GetPriceOutputByIdAsync(int priceId)
{
var price = await GetPriceOrThrowAsync(priceId);
var priceIds = new[] { price.Id };
var factors = await ServiceChannelRepository.GetPriceFactorsAsync(priceIds);
var details = await ServiceChannelRepository.GetPriceDetailsAsync(priceIds);
return new ServiceChannelPriceListOutput
{
Id = price.Id,
ServiceChannelId = price.ServiceChannelId,
SerialNumber = price.SerialNumber,
Status = (byte)price.Status,
PriceName = price.PriceName,
CostItem = price.CostItem,
CostUnit = price.CostUnit,
Currency = price.Currency,
ChargingCondition = price.ChargingCondition,
Factors = factors.OrderBy(item => item.SerialNumber).Select(MapPriceFactorOutput).ToList(),
Details = details.OrderBy(item => item.Id).Select(MapPriceDetailOutput).ToList(),
CreateTime = price.CreateTime,
UpdateTime = OmsDocHelper.NullIfDefault(price.UpdateTime)
};
}
/// <summary>
/// 获取指定类型的发布记录。
/// </summary>

View File

@ -215,17 +215,29 @@ public partial class ServiceChannelService : ApplicationService
/// 查询服务渠道价格项列表。
/// </summary>
/// <param name="serviceChannelId">入参:serviceChannelId。</param>
/// <param name="includeDetails">是否返回价格明细矩阵;列表页建议 false。</param>
/// <returns>服务渠道价格项列表结果。</returns>
[HttpGet("/channel/service-channel/price/list")]
public async Task<OmsItemsResult<ServiceChannelPriceListOutput>> GetPriceListAsync([FromQuery] int serviceChannelId)
public async Task<OmsItemsResult<ServiceChannelPriceListOutput>> GetPriceListAsync(
[FromQuery] int serviceChannelId,
[FromQuery] bool includeDetails = true)
{
await GetEntityOrThrowAsync(serviceChannelId);
return new OmsItemsResult<ServiceChannelPriceListOutput>
{
Items = await GetPriceOutputsAsync(serviceChannelId)
Items = await GetPriceOutputsAsync(serviceChannelId, includeDetails)
};
}
/// <summary>
/// 获取单条服务渠道价格项(含计费因子与价格明细)。
/// </summary>
[HttpGet("/channel/service-channel/price/get")]
public async Task<ServiceChannelPriceListOutput> GetPriceAsync([FromQuery] int id)
{
return await GetPriceOutputByIdAsync(id);
}
/// <summary>
/// 新增服务渠道价格项。
/// </summary>