feat(customer): 完成客户画像会员摘要与权限链路
All checks were successful
Build and Deploy TenantApi + SkuWorker / build-and-deploy (push) Successful in 2m2s

This commit is contained in:
2026-03-03 14:39:33 +08:00
parent 1b28fa6db4
commit a993b81aeb
15 changed files with 3053 additions and 1 deletions

View File

@@ -0,0 +1,462 @@
namespace TakeoutSaaS.Application.App.Customers.Dto;
/// <summary>
/// 客户标签 DTO。
/// </summary>
public sealed class CustomerTagDto
{
/// <summary>
/// 标签编码。
/// </summary>
public string Code { get; init; } = string.Empty;
/// <summary>
/// 标签文案。
/// </summary>
public string Label { get; init; } = string.Empty;
/// <summary>
/// 标签色调orange/blue/green/gray/red
/// </summary>
public string Tone { get; init; } = "blue";
}
/// <summary>
/// 客户列表行 DTO。
/// </summary>
public sealed class CustomerListItemDto
{
/// <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 int OrderCount { get; init; }
/// <summary>
/// 下单次数条形宽度百分比。
/// </summary>
public int OrderCountBarPercent { get; init; }
/// <summary>
/// 累计消费。
/// </summary>
public decimal TotalAmount { 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 IReadOnlyList<CustomerTagDto> Tags { get; init; } = [];
/// <summary>
/// 是否弱化展示。
/// </summary>
public bool IsDimmed { get; init; }
}
/// <summary>
/// 客户列表统计 DTO。
/// </summary>
public sealed class CustomerListStatsDto
{
/// <summary>
/// 客户总数。
/// </summary>
public int TotalCustomers { get; init; }
/// <summary>
/// 本月新增客户数。
/// </summary>
public int MonthlyNewCustomers { get; init; }
/// <summary>
/// 本月较上月增长百分比。
/// </summary>
public decimal MonthlyGrowthRatePercent { get; init; }
/// <summary>
/// 活跃客户数(近 30 天有下单)。
/// </summary>
public int ActiveCustomers { get; init; }
/// <summary>
/// 近 30 天客均消费(按订单均值)。
/// </summary>
public decimal AverageAmountLast30Days { get; init; }
}
/// <summary>
/// 客户偏好 DTO。
/// </summary>
public sealed class CustomerPreferenceDto
{
/// <summary>
/// 偏好品类。
/// </summary>
public IReadOnlyList<string> PreferredCategories { get; init; } = [];
/// <summary>
/// 偏好下单时段。
/// </summary>
public string PreferredOrderPeaks { get; init; } = string.Empty;
/// <summary>
/// 偏好履约方式。
/// </summary>
public string PreferredDelivery { get; init; } = string.Empty;
/// <summary>
/// 偏好支付方式。
/// </summary>
public string PreferredPaymentMethod { get; init; } = string.Empty;
/// <summary>
/// 平均配送距离文案。
/// </summary>
public string AverageDeliveryDistance { get; init; } = string.Empty;
}
/// <summary>
/// 客户常购商品 DTO。
/// </summary>
public sealed class CustomerTopProductDto
{
/// <summary>
/// 排名。
/// </summary>
public int Rank { get; init; }
/// <summary>
/// 商品名称。
/// </summary>
public string ProductName { get; init; } = string.Empty;
/// <summary>
/// 购买次数。
/// </summary>
public int Count { get; init; }
/// <summary>
/// 占比0-100
/// </summary>
public decimal ProportionPercent { get; init; }
}
/// <summary>
/// 客户趋势点 DTO。
/// </summary>
public sealed class CustomerTrendPointDto
{
/// <summary>
/// 月份标签。
/// </summary>
public string Label { get; init; } = string.Empty;
/// <summary>
/// 消费金额。
/// </summary>
public decimal Amount { get; init; }
}
/// <summary>
/// 客户最近订单 DTO。
/// </summary>
public sealed class CustomerRecentOrderDto
{
/// <summary>
/// 订单号。
/// </summary>
public string OrderNo { get; init; } = string.Empty;
/// <summary>
/// 下单时间。
/// </summary>
public DateTime OrderedAt { get; init; }
/// <summary>
/// 订单金额。
/// </summary>
public decimal Amount { get; init; }
/// <summary>
/// 商品摘要。
/// </summary>
public string ItemsSummary { get; init; } = string.Empty;
/// <summary>
/// 履约方式文案。
/// </summary>
public string DeliveryType { get; init; } = string.Empty;
/// <summary>
/// 状态文案。
/// </summary>
public string Status { get; init; } = string.Empty;
}
/// <summary>
/// 客户会员摘要 DTO。
/// </summary>
public sealed class CustomerMemberSummaryDto
{
/// <summary>
/// 是否会员。
/// </summary>
public bool IsMember { get; init; }
/// <summary>
/// 会员等级名称。
/// </summary>
public string TierName { get; init; } = string.Empty;
/// <summary>
/// 积分余额。
/// </summary>
public int PointsBalance { get; init; }
/// <summary>
/// 成长值。
/// </summary>
public int GrowthValue { get; init; }
/// <summary>
/// 入会时间。
/// </summary>
public DateTime? JoinedAt { get; init; }
}
/// <summary>
/// 客户详情 DTO。
/// </summary>
public sealed class CustomerDetailDto
{
/// <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 DateTime RegisteredAt { get; init; }
/// <summary>
/// 首次下单时间。
/// </summary>
public DateTime FirstOrderAt { get; init; }
/// <summary>
/// 客户来源。
/// </summary>
public string Source { get; init; } = string.Empty;
/// <summary>
/// 客户标签。
/// </summary>
public IReadOnlyList<CustomerTagDto> Tags { get; init; } = [];
/// <summary>
/// 会员摘要。
/// </summary>
public CustomerMemberSummaryDto Member { get; init; } = new();
/// <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 CustomerPreferenceDto Preference { get; init; } = new();
/// <summary>
/// 常购商品 Top 5。
/// </summary>
public IReadOnlyList<CustomerTopProductDto> TopProducts { get; init; } = [];
/// <summary>
/// 趋势数据。
/// </summary>
public IReadOnlyList<CustomerTrendPointDto> Trend { get; init; } = [];
/// <summary>
/// 最近订单。
/// </summary>
public IReadOnlyList<CustomerRecentOrderDto> RecentOrders { get; init; } = [];
}
/// <summary>
/// 客户画像 DTO。
/// </summary>
public sealed class CustomerProfileDto
{
/// <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 DateTime RegisteredAt { get; init; }
/// <summary>
/// 首次下单时间。
/// </summary>
public DateTime FirstOrderAt { get; init; }
/// <summary>
/// 客户来源。
/// </summary>
public string Source { get; init; } = string.Empty;
/// <summary>
/// 客户标签。
/// </summary>
public IReadOnlyList<CustomerTagDto> Tags { get; init; } = [];
/// <summary>
/// 会员摘要。
/// </summary>
public CustomerMemberSummaryDto Member { get; init; } = new();
/// <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 decimal AverageOrderIntervalDays { get; init; }
/// <summary>
/// 偏好数据。
/// </summary>
public CustomerPreferenceDto Preference { get; init; } = new();
/// <summary>
/// 常购商品 Top 5。
/// </summary>
public IReadOnlyList<CustomerTopProductDto> TopProducts { get; init; } = [];
/// <summary>
/// 趋势数据。
/// </summary>
public IReadOnlyList<CustomerTrendPointDto> Trend { get; init; } = [];
/// <summary>
/// 最近订单。
/// </summary>
public IReadOnlyList<CustomerRecentOrderDto> RecentOrders { get; init; } = [];
}
/// <summary>
/// 客户导出 DTO。
/// </summary>
public sealed class CustomerExportDto
{
/// <summary>
/// 文件名。
/// </summary>
public string FileName { get; init; } = string.Empty;
/// <summary>
/// 文件 Base64。
/// </summary>
public string FileContentBase64 { get; init; } = string.Empty;
/// <summary>
/// 导出总数。
/// </summary>
public int TotalCount { get; init; }
}