From 8a4848644f7dd60f4a7b049b7e9d0e6a9b82c0cc Mon Sep 17 00:00:00 2001 From: zzh <1368735060@qq.com> Date: Thu, 29 Oct 2026 16:04:02 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20KPI=E5=88=86=E5=8C=BA=E6=98=8E=E7=BB=86?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=94=AF=E6=8C=81=E8=A1=A8=E5=A4=B4=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=E5=90=8E=E7=AB=AF=E7=AD=9B=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EOF Co-authored-by: Cursor --- .../Dtos/Channels/KpiAreaInfoListInput.cs | 35 ++++++++ .../Services/Channels/KpiAreaService.cs | 17 +++- .../Repositories/IKpiAreaRepository.cs | 26 +++++- .../Channels/KpiAreaRepository.cs | 81 +++++++++++++++++-- 4 files changed, 150 insertions(+), 9 deletions(-) diff --git a/src/Oms.Application/Dtos/Channels/KpiAreaInfoListInput.cs b/src/Oms.Application/Dtos/Channels/KpiAreaInfoListInput.cs index 120c115..6f9152c 100644 --- a/src/Oms.Application/Dtos/Channels/KpiAreaInfoListInput.cs +++ b/src/Oms.Application/Dtos/Channels/KpiAreaInfoListInput.cs @@ -19,4 +19,39 @@ public class KpiAreaInfoListInput /// 每页条数。 /// public int PageSize { get; set; } + + /// + /// 国家/地区(匹配国家名称或国家代码,模糊)。 + /// + public string? Country { get; set; } + + /// + /// 匹配维度(如 zip/state/city/country,模糊)。 + /// + public string? MatchDim { get; set; } + + /// + /// 匹配方式(如 prefix/exact/range/all,模糊)。 + /// + public string? MatchMode { get; set; } + + /// + /// 州/省(模糊)。 + /// + public string? Province { get; set; } + + /// + /// 城市(模糊)。 + /// + public string? City { get; set; } + + /// + /// 起始邮编(模糊)。 + /// + public string? LeftPostcode { get; set; } + + /// + /// 截止邮编(模糊)。 + /// + public string? RightPostcode { get; set; } } diff --git a/src/Oms.Application/Services/Channels/KpiAreaService.cs b/src/Oms.Application/Services/Channels/KpiAreaService.cs index 95f6061..6ec6e34 100644 --- a/src/Oms.Application/Services/Channels/KpiAreaService.cs +++ b/src/Oms.Application/Services/Channels/KpiAreaService.cs @@ -106,8 +106,9 @@ public class KpiAreaService : ApplicationService await GetAreaOrThrowAsync(input.AreaId); var pageIndex = OmsDocHelper.NormalizePage(input.Page); var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize); - var entities = await KpiAreaRepository.GetInfosAsync(input.AreaId, pageIndex, pageSize); - var total = await KpiAreaRepository.CountInfosAsync(input.AreaId); + var filter = BuildInfoQueryFilter(input); + var entities = await KpiAreaRepository.GetInfosAsync(input.AreaId, pageIndex, pageSize, filter); + var total = await KpiAreaRepository.CountInfosAsync(input.AreaId, filter); return new OmsPageResult { Items = entities.Select(MapInfoOutput).ToList(), @@ -115,6 +116,18 @@ public class KpiAreaService : ApplicationService }; } + private static KpiAreaInfoQueryFilter BuildInfoQueryFilter(KpiAreaInfoListInput input) => + new() + { + Country = input.Country, + MatchDim = input.MatchDim, + MatchMode = input.MatchMode, + Province = input.Province, + City = input.City, + LeftPostcode = input.LeftPostcode, + RightPostcode = input.RightPostcode + }; + /// /// 新增KPI分区明细。 /// diff --git a/src/Oms.Domain/ChannelsAggregate/Repositories/IKpiAreaRepository.cs b/src/Oms.Domain/ChannelsAggregate/Repositories/IKpiAreaRepository.cs index 6dce96b..183980d 100644 --- a/src/Oms.Domain/ChannelsAggregate/Repositories/IKpiAreaRepository.cs +++ b/src/Oms.Domain/ChannelsAggregate/Repositories/IKpiAreaRepository.cs @@ -3,15 +3,37 @@ using Oms.Domain.ChannelsAggregate.Entities; namespace Oms.Domain.ChannelsAggregate.Repositories; +/// +/// KPI 分区明细列表筛选条件(字段均为可选,模糊匹配)。 +/// +public class KpiAreaInfoQueryFilter +{ + public string? Country { get; set; } + public string? MatchDim { get; set; } + public string? MatchMode { get; set; } + public string? Province { get; set; } + public string? City { get; set; } + public string? LeftPostcode { get; set; } + public string? RightPostcode { get; set; } +} + public interface IKpiAreaRepository : IRepository, IKpiAreaPublishRepository { Task GetByAppKeyTypeAndNameAsync(string appKey, string areaType, string name, CancellationToken cancellationToken = default); Task ExistsNameAsync(string appKey, string areaType, string name, CancellationToken cancellationToken = default); - Task> GetInfosAsync(int areaId, int pageIndex, int pageSize, CancellationToken cancellationToken = default); + Task> GetInfosAsync( + int areaId, + int pageIndex, + int pageSize, + KpiAreaInfoQueryFilter? filter = null, + CancellationToken cancellationToken = default); - Task CountInfosAsync(int areaId, CancellationToken cancellationToken = default); + Task CountInfosAsync( + int areaId, + KpiAreaInfoQueryFilter? filter = null, + CancellationToken cancellationToken = default); Task InsertInfoAsync(KpiAreaInfo info, CancellationToken cancellationToken = default); diff --git a/src/Oms.SqlSugarCore/Channels/KpiAreaRepository.cs b/src/Oms.SqlSugarCore/Channels/KpiAreaRepository.cs index e50b197..057a9dd 100644 --- a/src/Oms.SqlSugarCore/Channels/KpiAreaRepository.cs +++ b/src/Oms.SqlSugarCore/Channels/KpiAreaRepository.cs @@ -18,20 +18,91 @@ public class KpiAreaRepository : OmsSqlSugarRepository, IKpiAreaReposit return AnyAsync(x => x.AppKey == appKey && x.AreaType == areaType && x.Name == name, cancellationToken); } - public async Task> GetInfosAsync(int areaId, int pageIndex, int pageSize, CancellationToken cancellationToken = default) + public async Task> GetInfosAsync( + int areaId, + int pageIndex, + int pageSize, + KpiAreaInfoQueryFilter? filter = null, + CancellationToken cancellationToken = default) { var db = await GetDbContextAsync(cancellationToken); // 依赖 idx_kpi_info_area_id (AreaId, Id),避免大分区 filesort - return await db.Queryable() - .Where(x => x.AreaId == areaId) + return await BuildInfoQueryable(db, areaId, filter) .OrderBy(x => x.Id, OrderByType.Desc) .ToPageListAsync(pageIndex, pageSize, cancellationToken); } - public async Task CountInfosAsync(int areaId, CancellationToken cancellationToken = default) + public async Task CountInfosAsync( + int areaId, + KpiAreaInfoQueryFilter? filter = null, + CancellationToken cancellationToken = default) { var db = await GetDbContextAsync(cancellationToken); - return await db.Queryable().Where(x => x.AreaId == areaId).CountAsync(cancellationToken); + return await BuildInfoQueryable(db, areaId, filter).CountAsync(cancellationToken); + } + + private static ISugarQueryable BuildInfoQueryable( + ISqlSugarClient db, + int areaId, + KpiAreaInfoQueryFilter? filter) + { + var query = db.Queryable().Where(x => x.AreaId == areaId); + if (filter == null) + { + return query; + } + + var country = TrimOrNull(filter.Country); + if (country != null) + { + query = query.Where(x => + (x.CountryName != null && x.CountryName.Contains(country)) + || (x.CountryCode != null && x.CountryCode.Contains(country))); + } + + var matchDim = TrimOrNull(filter.MatchDim); + if (matchDim != null) + { + query = query.Where(x => x.MatchDim != null && x.MatchDim.Contains(matchDim)); + } + + var matchMode = TrimOrNull(filter.MatchMode); + if (matchMode != null) + { + query = query.Where(x => x.MatchMode != null && x.MatchMode.Contains(matchMode)); + } + + var province = TrimOrNull(filter.Province); + if (province != null) + { + query = query.Where(x => x.Province != null && x.Province.Contains(province)); + } + + var city = TrimOrNull(filter.City); + if (city != null) + { + query = query.Where(x => x.City != null && x.City.Contains(city)); + } + + var leftPostcode = TrimOrNull(filter.LeftPostcode); + if (leftPostcode != null) + { + query = query.Where(x => x.LeftPostcode != null && x.LeftPostcode.Contains(leftPostcode)); + } + + var rightPostcode = TrimOrNull(filter.RightPostcode); + if (rightPostcode != null) + { + query = query.Where(x => x.RightPostcode != null && x.RightPostcode.Contains(rightPostcode)); + } + + return query; + } + + private static string? TrimOrNull(string? value) + { + var trimmed = value?.Trim(); + return string.IsNullOrEmpty(trimmed) ? null : trimmed; } public async Task InsertInfoAsync(KpiAreaInfo info, CancellationToken cancellationToken = default)