feat(customer): add customer analysis query APIs

This commit is contained in:
2026-03-03 16:45:39 +08:00
parent a993b81aeb
commit 26afffd874
12 changed files with 2540 additions and 0 deletions

View File

@@ -0,0 +1,431 @@
namespace TakeoutSaaS.Application.App.Customers.Dto;
/// <summary>
/// 客户分析增长趋势点 DTO。
/// </summary>
public sealed class CustomerAnalysisTrendPointDto
{
/// <summary>
/// 维度标签。
/// </summary>
public string Label { get; init; } = string.Empty;
/// <summary>
/// 数量值。
/// </summary>
public int Value { get; init; }
}
/// <summary>
/// 客户分析新老客构成项 DTO。
/// </summary>
public sealed class CustomerAnalysisCompositionItemDto
{
/// <summary>
/// 分群编码。
/// </summary>
public string SegmentCode { get; init; } = string.Empty;
/// <summary>
/// 分群名称。
/// </summary>
public string Label { get; init; } = string.Empty;
/// <summary>
/// 分群人数。
/// </summary>
public int Count { get; init; }
/// <summary>
/// 分群占比(百分比)。
/// </summary>
public decimal Percent { get; init; }
/// <summary>
/// 色调blue/green/orange/gray
/// </summary>
public string Tone { get; init; } = "blue";
}
/// <summary>
/// 客单价分布项 DTO。
/// </summary>
public sealed class CustomerAnalysisAmountDistributionItemDto
{
/// <summary>
/// 分群编码。
/// </summary>
public string SegmentCode { get; init; } = string.Empty;
/// <summary>
/// 区间标签。
/// </summary>
public string Label { get; init; } = string.Empty;
/// <summary>
/// 人数。
/// </summary>
public int Count { get; init; }
/// <summary>
/// 占比(百分比)。
/// </summary>
public decimal Percent { get; init; }
}
/// <summary>
/// RFM 分层单元 DTO。
/// </summary>
public sealed class CustomerAnalysisRfmCellDto
{
/// <summary>
/// 分群编码。
/// </summary>
public string SegmentCode { get; init; } = string.Empty;
/// <summary>
/// 分层标签。
/// </summary>
public string Label { get; init; } = string.Empty;
/// <summary>
/// 人数。
/// </summary>
public int Count { get; init; }
/// <summary>
/// 温度hot/warm/cool/cold
/// </summary>
public string Tone { get; init; } = "cold";
}
/// <summary>
/// RFM 分层行 DTO。
/// </summary>
public sealed class CustomerAnalysisRfmRowDto
{
/// <summary>
/// 行标签。
/// </summary>
public string Label { get; init; } = string.Empty;
/// <summary>
/// 单元格集合。
/// </summary>
public IReadOnlyList<CustomerAnalysisRfmCellDto> Cells { get; init; } = [];
}
/// <summary>
/// 高价值客户 DTO。
/// </summary>
public sealed class CustomerAnalysisTopCustomerDto
{
/// <summary>
/// 排名。
/// </summary>
public int Rank { get; init; }
/// <summary>
/// 客户标识。
/// </summary>
public string CustomerKey { get; init; } = string.Empty;
/// <summary>
/// 客户名称。
/// </summary>
public string Name { get; init; } = string.Empty;
/// <summary>
/// 手机号(脱敏)。
/// </summary>
public string PhoneMasked { get; init; } = string.Empty;
/// <summary>
/// 累计消费。
/// </summary>
public decimal TotalAmount { get; init; }
/// <summary>
/// 下单次数。
/// </summary>
public int OrderCount { get; init; }
/// <summary>
/// 客单价。
/// </summary>
public decimal AverageAmount { get; init; }
/// <summary>
/// 最近下单时间。
/// </summary>
public DateTime LastOrderAt { get; init; }
/// <summary>
/// 客户标签。
/// </summary>
public IReadOnlyList<CustomerTagDto> Tags { get; init; } = [];
}
/// <summary>
/// 客户分析总览 DTO。
/// </summary>
public sealed class CustomerAnalysisOverviewDto
{
/// <summary>
/// 统计周期编码。
/// </summary>
public string PeriodCode { get; init; } = "30d";
/// <summary>
/// 统计周期天数。
/// </summary>
public int PeriodDays { get; init; } = 30;
/// <summary>
/// 客户总数。
/// </summary>
public int TotalCustomers { get; init; }
/// <summary>
/// 周期新增客户数。
/// </summary>
public int NewCustomers { get; init; }
/// <summary>
/// 新增较上一周期增长百分比。
/// </summary>
public decimal GrowthRatePercent { get; init; }
/// <summary>
/// 周期内日均新增客户。
/// </summary>
public decimal NewCustomersDailyAverage { get; init; }
/// <summary>
/// 活跃客户数。
/// </summary>
public int ActiveCustomers { get; init; }
/// <summary>
/// 活跃率(百分比)。
/// </summary>
public decimal ActiveRatePercent { get; init; }
/// <summary>
/// 平均客户价值(累计消费均值)。
/// </summary>
public decimal AverageLifetimeValue { get; init; }
/// <summary>
/// 客户增长趋势。
/// </summary>
public IReadOnlyList<CustomerAnalysisTrendPointDto> GrowthTrend { get; init; } = [];
/// <summary>
/// 新老客占比。
/// </summary>
public IReadOnlyList<CustomerAnalysisCompositionItemDto> Composition { get; init; } = [];
/// <summary>
/// 客单价分布。
/// </summary>
public IReadOnlyList<CustomerAnalysisAmountDistributionItemDto> AmountDistribution { get; init; } = [];
/// <summary>
/// RFM 分层。
/// </summary>
public IReadOnlyList<CustomerAnalysisRfmRowDto> RfmRows { get; init; } = [];
/// <summary>
/// 高价值客户 Top10。
/// </summary>
public IReadOnlyList<CustomerAnalysisTopCustomerDto> TopCustomers { get; init; } = [];
}
/// <summary>
/// 客群明细行 DTO。
/// </summary>
public sealed class CustomerAnalysisSegmentListItemDto
{
/// <summary>
/// 客户标识。
/// </summary>
public string CustomerKey { get; init; } = string.Empty;
/// <summary>
/// 客户名称。
/// </summary>
public string Name { get; init; } = string.Empty;
/// <summary>
/// 手机号(脱敏)。
/// </summary>
public string PhoneMasked { get; init; } = string.Empty;
/// <summary>
/// 头像文案。
/// </summary>
public string AvatarText { get; init; } = string.Empty;
/// <summary>
/// 头像颜色。
/// </summary>
public string AvatarColor { get; init; } = string.Empty;
/// <summary>
/// 客户标签。
/// </summary>
public IReadOnlyList<CustomerTagDto> Tags { get; init; } = [];
/// <summary>
/// 是否会员。
/// </summary>
public bool IsMember { get; init; }
/// <summary>
/// 会员等级。
/// </summary>
public string MemberTierName { get; init; } = string.Empty;
/// <summary>
/// 累计消费。
/// </summary>
public decimal TotalAmount { get; init; }
/// <summary>
/// 下单次数。
/// </summary>
public int OrderCount { get; init; }
/// <summary>
/// 客单价。
/// </summary>
public decimal AverageAmount { get; init; }
/// <summary>
/// 注册时间。
/// </summary>
public DateTime RegisteredAt { get; init; }
/// <summary>
/// 最近下单时间。
/// </summary>
public DateTime LastOrderAt { get; init; }
/// <summary>
/// 是否弱化显示。
/// </summary>
public bool IsDimmed { get; init; }
}
/// <summary>
/// 客群明细结果 DTO。
/// </summary>
public sealed class CustomerAnalysisSegmentListResultDto
{
/// <summary>
/// 分群编码。
/// </summary>
public string SegmentCode { get; init; } = string.Empty;
/// <summary>
/// 分群标题。
/// </summary>
public string SegmentTitle { get; init; } = string.Empty;
/// <summary>
/// 分群说明。
/// </summary>
public string SegmentDescription { get; init; } = string.Empty;
/// <summary>
/// 列表项。
/// </summary>
public IReadOnlyList<CustomerAnalysisSegmentListItemDto> Items { get; init; } = [];
/// <summary>
/// 当前页。
/// </summary>
public int Page { get; init; }
/// <summary>
/// 每页条数。
/// </summary>
public int PageSize { get; init; }
/// <summary>
/// 总记录数。
/// </summary>
public int TotalCount { get; init; }
}
/// <summary>
/// 会员详情 DTO。
/// </summary>
public sealed class CustomerMemberDetailDto
{
/// <summary>
/// 客户标识。
/// </summary>
public string CustomerKey { get; init; } = string.Empty;
/// <summary>
/// 客户名称。
/// </summary>
public string Name { get; init; } = string.Empty;
/// <summary>
/// 手机号(脱敏)。
/// </summary>
public string PhoneMasked { get; init; } = string.Empty;
/// <summary>
/// 来源。
/// </summary>
public string Source { get; init; } = string.Empty;
/// <summary>
/// 注册时间。
/// </summary>
public DateTime RegisteredAt { get; init; }
/// <summary>
/// 最近下单时间。
/// </summary>
public DateTime LastOrderAt { get; init; }
/// <summary>
/// 会员摘要。
/// </summary>
public CustomerMemberSummaryDto Member { get; init; } = new();
/// <summary>
/// 客户标签。
/// </summary>
public IReadOnlyList<CustomerTagDto> Tags { get; init; } = [];
/// <summary>
/// 累计下单次数。
/// </summary>
public int TotalOrders { get; init; }
/// <summary>
/// 累计消费。
/// </summary>
public decimal TotalAmount { get; init; }
/// <summary>
/// 客单价。
/// </summary>
public decimal AverageAmount { get; init; }
/// <summary>
/// 复购率。
/// </summary>
public decimal RepurchaseRatePercent { get; init; }
/// <summary>
/// 最近订单。
/// </summary>
public IReadOnlyList<CustomerRecentOrderDto> RecentOrders { get; init; } = [];
}