All checks were successful
Build and Deploy / deploy (push) Successful in 1m12s
门户可见范围改用客户当前 AgentId;返佣仍认订单快照 AgentId。 Co-authored-by: Cursor <cursoragent@cursor.com>
580 lines
22 KiB
C#
580 lines
22 KiB
C#
using System.Linq.Expressions;
|
||
using Fake.Application;
|
||
using Fake.Domain.Exceptions;
|
||
using Microsoft.AspNetCore.Mvc;
|
||
using MiniExcelLibs;
|
||
using Oms.Application.Dtos.Agents;
|
||
using Oms.Application.Dtos.Shared;
|
||
using Oms.Application.Shared;
|
||
using Oms.Domain.AgentsAggregate.Consts;
|
||
using Oms.Domain.AgentsAggregate.Entities;
|
||
using Oms.Domain.AgentsAggregate.Repositories;
|
||
using Oms.Domain.ChannelsAggregate.Repositories;
|
||
using Oms.Domain.CustomersAggregate.Entities;
|
||
using Oms.Domain.CustomersAggregate.Repositories;
|
||
using Oms.Domain.OrdersAggregate;
|
||
using Oms.Domain.OrdersAggregate.Consts;
|
||
using Oms.Domain.OrdersAggregate.Entities;
|
||
using Oms.Domain.OrdersAggregate.Repositories;
|
||
|
||
namespace Oms.Application.Services.Agents;
|
||
|
||
/// <summary>
|
||
/// 渠道代理门户 API(名下客户 / 订单 / 返佣 / 工作台)。
|
||
/// </summary>
|
||
[ApiExplorerSettings(GroupName = "OMS-Agent")]
|
||
public class AgentPortalService : ApplicationService
|
||
{
|
||
private IAgentRepository AgentRepository => LazyServiceProvider.GetRequiredService<IAgentRepository>();
|
||
|
||
private IAgentCommissionDetailRepository DetailRepository =>
|
||
LazyServiceProvider.GetRequiredService<IAgentCommissionDetailRepository>();
|
||
|
||
private ICustomerRepository CustomerRepository => LazyServiceProvider.GetRequiredService<ICustomerRepository>();
|
||
|
||
private IOrderRepository OrderRepository => LazyServiceProvider.GetRequiredService<IOrderRepository>();
|
||
|
||
private ISalesProductRepository SalesProductRepository =>
|
||
LazyServiceProvider.GetRequiredService<ISalesProductRepository>();
|
||
|
||
/// <summary>当前代理资料(含返佣规则展示字段)。</summary>
|
||
[HttpGet("/agent/portal/profile")]
|
||
public async Task<AgentOutput> GetProfileAsync()
|
||
{
|
||
var agent = await GetCurrentAgentOrThrowAsync();
|
||
var productNames = await ResolveSalesProductNamesAsync(agent.SalesProductIds);
|
||
return new AgentOutput
|
||
{
|
||
Id = agent.Id,
|
||
AgentCode = agent.AgentCode,
|
||
AgentName = agent.AgentName,
|
||
Phone = agent.Phone,
|
||
Email = agent.Email,
|
||
Status = agent.Status,
|
||
BaseType = agent.BaseType,
|
||
BaseTypeName = ResolveBaseTypeName(agent.BaseType),
|
||
CommissionRate = agent.CommissionRate,
|
||
SalesProductIds = agent.SalesProductIds,
|
||
SalesProductNames = productNames,
|
||
Remark = agent.Remark,
|
||
CreateTime = agent.CreateTime
|
||
};
|
||
}
|
||
|
||
/// <summary>名下客户分页(含活跃度:最近下单 / 近30天票数 / 待付款数)。</summary>
|
||
[HttpPost("/agent/portal/customers/list")]
|
||
public async Task<OmsPageResult<AgentPortalCustomerOutput>> GetCustomersAsync(AgentPortalPageInput input)
|
||
{
|
||
var agent = await GetCurrentAgentOrThrowAsync();
|
||
var keyword = input.Keyword?.Trim();
|
||
Expression<Func<Customer, bool>> predicate = string.IsNullOrWhiteSpace(keyword)
|
||
? x => x.AgentId == agent.Id && x.ParentCustomerId == null
|
||
: x => x.AgentId == agent.Id
|
||
&& x.ParentCustomerId == null
|
||
&& (x.CustomerCode.Contains(keyword!)
|
||
|| x.CustomerName.Contains(keyword!)
|
||
|| (x.Phone != null && x.Phone.Contains(keyword!)));
|
||
|
||
var page = OmsDocHelper.NormalizePage(input.Page);
|
||
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
||
var entities = await CustomerRepository.GetPagedListAsync(
|
||
predicate,
|
||
page,
|
||
pageSize,
|
||
new Dictionary<string, bool>
|
||
{
|
||
[nameof(Customer.CreateTime)] = false,
|
||
[nameof(Customer.Id)] = false
|
||
});
|
||
var total = await CustomerRepository.CountAsync(predicate);
|
||
var activityMap = await BuildCustomerActivityMapAsync(agent.Id, entities.Select(x => x.Id).ToList());
|
||
|
||
return new OmsPageResult<AgentPortalCustomerOutput>
|
||
{
|
||
Items = entities.Select(x =>
|
||
{
|
||
activityMap.TryGetValue(x.Id, out var activity);
|
||
return new AgentPortalCustomerOutput
|
||
{
|
||
Id = x.Id,
|
||
CustomerCode = x.CustomerCode,
|
||
CustomerName = MaskName(x.CustomerName) ?? string.Empty,
|
||
Phone = MaskPhone(x.Phone),
|
||
AgentBindTime = x.AgentBindTime,
|
||
CreateTime = x.CreateTime,
|
||
LastOrderTime = activity.LastOrderTime,
|
||
OrderCount30d = activity.OrderCount30d,
|
||
PendingPaymentCount = activity.PendingPaymentCount
|
||
};
|
||
}).ToList(),
|
||
Total = total
|
||
};
|
||
}
|
||
|
||
/// <summary>名下订单分页(按当前绑定客户可见;不含应付)。</summary>
|
||
[HttpPost("/agent/portal/orders/list")]
|
||
public async Task<OmsPageResult<AgentPortalOrderOutput>> GetOrdersAsync(AgentPortalPageInput input)
|
||
{
|
||
var agent = await GetCurrentAgentOrThrowAsync();
|
||
var keyword = input.Keyword?.Trim();
|
||
var filter = new OrderListFilter
|
||
{
|
||
OwnedByAgentId = agent.Id,
|
||
Keyword = string.IsNullOrWhiteSpace(keyword) ? null : keyword,
|
||
Status = "all"
|
||
};
|
||
|
||
var page = OmsDocHelper.NormalizePage(input.Page);
|
||
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
||
var (entities, total) = await OrderRepository.GetFilteredPagedListAsync(page, pageSize, filter);
|
||
|
||
var customerIds = entities.Where(x => x.CustomerId.HasValue).Select(x => x.CustomerId!.Value).Distinct().ToList();
|
||
var customers = customerIds.Count == 0
|
||
? []
|
||
: await CustomerRepository.GetListAsync(x => customerIds.Contains(x.Id));
|
||
var customerMap = customers.ToDictionary(x => x.Id);
|
||
|
||
return new OmsPageResult<AgentPortalOrderOutput>
|
||
{
|
||
Items = entities.Select(x =>
|
||
{
|
||
customerMap.TryGetValue(x.CustomerId ?? 0, out var customer);
|
||
return new AgentPortalOrderOutput
|
||
{
|
||
Id = x.Id,
|
||
ServiceNo = x.ServiceNo,
|
||
TrackNo = x.TrackNo,
|
||
CustomerId = x.CustomerId,
|
||
CustomerCode = customer?.CustomerCode,
|
||
CustomerName = MaskName(customer?.CustomerName),
|
||
ProductCode = x.ProductCode,
|
||
OrderStatus = x.OrderStatus,
|
||
ConsigneeCountryName = x.ConsigneeCountryName,
|
||
ReceivableSubtotal = x.ReceivableSubtotal,
|
||
PayableAmount = null,
|
||
CreateTime = x.CreateTime
|
||
};
|
||
}).ToList(),
|
||
Total = total
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 代理工作台统计:名下客户、运单状态桶、待结算/已打款返佣、本周新增绑定。
|
||
/// </summary>
|
||
[HttpGet("/agent/portal/workplace/stats")]
|
||
public async Task<AgentWorkplaceStatsOutput> GetWorkplaceStatsAsync()
|
||
{
|
||
var agent = await GetCurrentAgentOrThrowAsync();
|
||
var filter = new OrderListFilter { OwnedByAgentId = agent.Id };
|
||
var rows = await OrderRepository.GetStatusCountsByFilterAsync(filter);
|
||
var counts = rows
|
||
.Where(x => !string.Equals(x.Status, OrderStatusCodes.Deleted, StringComparison.OrdinalIgnoreCase))
|
||
.ToDictionary(x => x.Status, x => x.Count, StringComparer.OrdinalIgnoreCase);
|
||
|
||
int GetCount(string status) =>
|
||
counts.TryGetValue(status, out var value) ? value : 0;
|
||
|
||
var today = DateTime.Today;
|
||
var tomorrow = today.AddDays(1);
|
||
var yesterday = today.AddDays(-1);
|
||
var todayCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, today, tomorrow);
|
||
var yesterdayCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, yesterday, today);
|
||
|
||
decimal? growth = null;
|
||
if (yesterdayCreated > 0)
|
||
{
|
||
growth = Math.Round((todayCreated - yesterdayCreated) * 100m / yesterdayCreated, 1);
|
||
}
|
||
else if (todayCreated > 0)
|
||
{
|
||
growth = 100m;
|
||
}
|
||
|
||
var customerCount = await CustomerRepository.CountAsync(x =>
|
||
x.AgentId == agent.Id && x.ParentCustomerId == null);
|
||
|
||
var weekStart = today.AddDays(-(((int)today.DayOfWeek + 6) % 7));
|
||
var weekNewCustomers = await CustomerRepository.CountAsync(x =>
|
||
x.AgentId == agent.Id
|
||
&& x.ParentCustomerId == null
|
||
&& x.AgentBindTime != null
|
||
&& x.AgentBindTime >= weekStart
|
||
&& x.AgentBindTime < tomorrow);
|
||
|
||
var pendingDetails = await DetailRepository.GetListAsync(x =>
|
||
x.AgentId == agent.Id && x.Status == AgentCommissionStatusCodes.Pending);
|
||
var paidDetails = await DetailRepository.GetListAsync(x =>
|
||
x.AgentId == agent.Id && x.Status == AgentCommissionStatusCodes.Paid);
|
||
|
||
return new AgentWorkplaceStatsOutput
|
||
{
|
||
CustomerCount = customerCount,
|
||
TodayCreated = todayCreated,
|
||
YesterdayCreated = yesterdayCreated,
|
||
DayOverDayGrowthPercent = growth,
|
||
PendingPayment = GetCount(OrderStatusCodes.PendingPayment),
|
||
Shipping = GetCount(OrderStatusCodes.Shipping) + GetCount(OrderStatusCodes.PendingOnline),
|
||
Problematic = GetCount(OrderStatusCodes.Problematic),
|
||
DeliverySuccess = GetCount(OrderStatusCodes.DeliverySuccess),
|
||
DeliveryFailed = GetCount(OrderStatusCodes.DeliveryFailed),
|
||
PendingCommissionCount = pendingDetails.Count,
|
||
PendingCommissionAmount = pendingDetails.Sum(x => x.CommissionAmount),
|
||
PaidCommissionAmount = paidDetails.Sum(x => x.CommissionAmount),
|
||
WeekNewCustomers = weekNewCustomers,
|
||
Counts = counts,
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 代理工作台趋势:按日统计代客下单数与计提返佣金额。
|
||
/// </summary>
|
||
/// <param name="days">天数,默认 7,最大 31。</param>
|
||
[HttpGet("/agent/portal/workplace/trend")]
|
||
public async Task<AgentWorkplaceTrendOutput> GetWorkplaceTrendAsync([FromQuery] int days = 7)
|
||
{
|
||
var agent = await GetCurrentAgentOrThrowAsync();
|
||
days = Math.Clamp(days, 1, 31);
|
||
var filter = new OrderListFilter { OwnedByAgentId = agent.Id };
|
||
var today = DateTime.Today;
|
||
var rangeStart = today.AddDays(-(days - 1));
|
||
var rangeEnd = today.AddDays(1);
|
||
|
||
var commissions = await DetailRepository.GetListAsync(x =>
|
||
x.AgentId == agent.Id
|
||
&& x.CreateTime >= rangeStart
|
||
&& x.CreateTime < rangeEnd);
|
||
|
||
var points = new List<AgentWorkplaceTrendPoint>(days);
|
||
for (var i = 0; i < days; i++)
|
||
{
|
||
var start = rangeStart.AddDays(i);
|
||
var end = start.AddDays(1);
|
||
var orderCount = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, start, end);
|
||
var commissionAmount = commissions
|
||
.Where(x => x.CreateTime >= start && x.CreateTime < end)
|
||
.Sum(x => x.CommissionAmount);
|
||
points.Add(new AgentWorkplaceTrendPoint
|
||
{
|
||
Label = start.ToString("MM-dd"),
|
||
Start = start,
|
||
End = end,
|
||
OrderCount = orderCount,
|
||
CommissionAmount = commissionAmount,
|
||
});
|
||
}
|
||
|
||
return new AgentWorkplaceTrendOutput
|
||
{
|
||
Dimension = "day",
|
||
Points = points,
|
||
};
|
||
}
|
||
|
||
/// <summary>名下返佣明细(支持状态 / 运单号 / 计提时间筛选)。</summary>
|
||
[HttpPost("/agent/portal/commission/list")]
|
||
public async Task<OmsPageResult<AgentCommissionDetailOutput>> GetCommissionListAsync(
|
||
AgentPortalCommissionListInput input)
|
||
{
|
||
var agent = await GetCurrentAgentOrThrowAsync();
|
||
var details = await QueryCommissionDetailsAsync(agent, input);
|
||
var page = OmsDocHelper.NormalizePage(input.Page);
|
||
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
||
var total = details.Count;
|
||
var pageItems = details
|
||
.Skip((page - 1) * pageSize)
|
||
.Take(pageSize)
|
||
.ToList();
|
||
|
||
return new OmsPageResult<AgentCommissionDetailOutput>
|
||
{
|
||
Items = await MapCommissionOutputsAsync(agent, pageItems),
|
||
Total = total
|
||
};
|
||
}
|
||
|
||
/// <summary>导出名下返佣明细(Excel,最多 5000 条)。</summary>
|
||
[HttpPost("/agent/portal/commission/export")]
|
||
public async Task<FileContentResult> ExportCommissionAsync(AgentPortalCommissionListInput input)
|
||
{
|
||
var agent = await GetCurrentAgentOrThrowAsync();
|
||
var details = await QueryCommissionDetailsAsync(agent, input);
|
||
const int maxRows = 5000;
|
||
if (details.Count > maxRows)
|
||
{
|
||
throw new BusinessException($"导出结果超过 {maxRows} 条(当前 {details.Count}),请缩小筛选条件后再导出");
|
||
}
|
||
|
||
var outputs = await MapCommissionOutputsAsync(agent, details);
|
||
var rows = outputs.Select(x => new
|
||
{
|
||
运单号 = x.ServiceNo,
|
||
客户编号 = x.CustomerCode,
|
||
客户名称 = x.CustomerName,
|
||
基数类型 = ResolveBaseTypeName(x.BaseType),
|
||
基数金额 = x.BaseAmount,
|
||
返佣比例 = x.CommissionRate,
|
||
返佣金额 = x.CommissionAmount,
|
||
状态 = string.Equals(x.Status, AgentCommissionStatusCodes.Paid, StringComparison.OrdinalIgnoreCase)
|
||
? "已打款"
|
||
: "待结算",
|
||
触发状态 = x.TriggerOrderStatus,
|
||
计提时间 = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
||
打款时间 = x.PaidTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? "",
|
||
}).ToList();
|
||
|
||
await using var stream = new MemoryStream();
|
||
await MiniExcel.SaveAsAsync(stream, rows);
|
||
return new FileContentResult(
|
||
stream.ToArray(),
|
||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||
{
|
||
FileDownloadName = $"agent-commission-{DateTime.Now:yyyyMMddHHmmss}.xlsx"
|
||
};
|
||
}
|
||
|
||
private async Task<List<AgentCommissionDetail>> QueryCommissionDetailsAsync(
|
||
Agent agent,
|
||
AgentPortalCommissionListInput input)
|
||
{
|
||
var status = input.Status?.Trim();
|
||
var keyword = input.Keyword?.Trim();
|
||
var start = input.CreateTimeStart;
|
||
var end = input.CreateTimeEnd;
|
||
|
||
Expression<Func<AgentCommissionDetail, bool>> predicate = x => x.AgentId == agent.Id;
|
||
if (!string.IsNullOrWhiteSpace(status))
|
||
{
|
||
predicate = x => x.AgentId == agent.Id && x.Status == status;
|
||
}
|
||
|
||
var list = await DetailRepository.GetListAsync(predicate);
|
||
if (start.HasValue)
|
||
{
|
||
list = list.Where(x => x.CreateTime >= start.Value).ToList();
|
||
}
|
||
|
||
if (end.HasValue)
|
||
{
|
||
var endExclusive = end.Value.Date.AddDays(1);
|
||
list = list.Where(x => x.CreateTime < endExclusive).ToList();
|
||
}
|
||
|
||
if (!string.IsNullOrWhiteSpace(keyword))
|
||
{
|
||
var orderIds = list.Select(x => x.OrderId).Distinct().ToList();
|
||
var orders = orderIds.Count == 0
|
||
? []
|
||
: await OrderRepository.GetListAsync(x => orderIds.Contains(x.Id));
|
||
var matchedOrderIds = orders
|
||
.Where(o => o.ServiceNo.Contains(keyword, StringComparison.OrdinalIgnoreCase)
|
||
|| (o.TrackNo != null && o.TrackNo.Contains(keyword, StringComparison.OrdinalIgnoreCase)))
|
||
.Select(o => o.Id)
|
||
.ToHashSet();
|
||
list = list.Where(x => matchedOrderIds.Contains(x.OrderId)).ToList();
|
||
}
|
||
|
||
return list
|
||
.OrderByDescending(x => x.CreateTime)
|
||
.ThenByDescending(x => x.Id)
|
||
.ToList();
|
||
}
|
||
|
||
private async Task<List<AgentCommissionDetailOutput>> MapCommissionOutputsAsync(
|
||
Agent agent,
|
||
IReadOnlyCollection<AgentCommissionDetail> entities)
|
||
{
|
||
if (entities.Count == 0)
|
||
{
|
||
return [];
|
||
}
|
||
|
||
var customerIds = entities.Select(x => x.CustomerId).Distinct().ToList();
|
||
var orderIds = entities.Select(x => x.OrderId).Distinct().ToList();
|
||
var customers = await CustomerRepository.GetListAsync(x => customerIds.Contains(x.Id));
|
||
var orders = await OrderRepository.GetListAsync(x => orderIds.Contains(x.Id));
|
||
var customerMap = customers.ToDictionary(x => x.Id);
|
||
var orderMap = orders.ToDictionary(x => x.Id);
|
||
|
||
return entities.Select(x =>
|
||
{
|
||
customerMap.TryGetValue(x.CustomerId, out var customer);
|
||
orderMap.TryGetValue(x.OrderId, out var order);
|
||
return new AgentCommissionDetailOutput
|
||
{
|
||
Id = x.Id,
|
||
AgentId = x.AgentId,
|
||
AgentCode = agent.AgentCode,
|
||
AgentName = agent.AgentName,
|
||
OrderId = x.OrderId,
|
||
ServiceNo = order?.ServiceNo,
|
||
CustomerId = x.CustomerId,
|
||
CustomerCode = customer?.CustomerCode,
|
||
CustomerName = MaskName(customer?.CustomerName),
|
||
SalesProductId = x.SalesProductId,
|
||
BaseType = x.BaseType,
|
||
BaseAmount = x.BaseAmount,
|
||
CommissionRate = x.CommissionRate,
|
||
CommissionAmount = x.CommissionAmount,
|
||
Status = x.Status,
|
||
TriggerOrderStatus = x.TriggerOrderStatus,
|
||
PaidTime = x.PaidTime,
|
||
Remark = x.Remark,
|
||
CreateTime = x.CreateTime
|
||
};
|
||
}).ToList();
|
||
}
|
||
|
||
private async Task<Dictionary<int, (DateTime? LastOrderTime, int OrderCount30d, int PendingPaymentCount)>>
|
||
BuildCustomerActivityMapAsync(int agentId, List<int> mainCustomerIds)
|
||
{
|
||
var result = mainCustomerIds.ToDictionary(
|
||
id => id,
|
||
_ => ((DateTime?)null, 0, 0));
|
||
if (mainCustomerIds.Count == 0)
|
||
{
|
||
return result;
|
||
}
|
||
|
||
var children = await CustomerRepository.GetListAsync(x =>
|
||
x.ParentCustomerId != null && mainCustomerIds.Contains(x.ParentCustomerId.Value));
|
||
var mainByCustomerId = new Dictionary<int, int>();
|
||
foreach (var id in mainCustomerIds)
|
||
{
|
||
mainByCustomerId[id] = id;
|
||
}
|
||
|
||
foreach (var child in children)
|
||
{
|
||
if (child.ParentCustomerId is > 0)
|
||
{
|
||
mainByCustomerId[child.Id] = child.ParentCustomerId.Value;
|
||
}
|
||
}
|
||
|
||
var allIds = mainByCustomerId.Keys.ToList();
|
||
var since30 = DateTime.Today.AddDays(-30);
|
||
var orders = await OrderRepository.GetListAsync(x =>
|
||
x.AgentId == agentId
|
||
&& x.CustomerId != null
|
||
&& allIds.Contains(x.CustomerId.Value)
|
||
&& x.OrderStatus != OrderStatusCodes.Deleted);
|
||
|
||
foreach (var group in orders.GroupBy(o => mainByCustomerId[o.CustomerId!.Value]))
|
||
{
|
||
var list = group.ToList();
|
||
result[group.Key] = (
|
||
list.Max(o => (DateTime?)o.CreateTime),
|
||
list.Count(o => o.CreateTime >= since30),
|
||
list.Count(o => string.Equals(
|
||
o.OrderStatus,
|
||
OrderStatusCodes.PendingPayment,
|
||
StringComparison.OrdinalIgnoreCase)));
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
private async Task<List<string>> ResolveSalesProductNamesAsync(string? salesProductIds)
|
||
{
|
||
var ids = ParseSalesProductIds(salesProductIds);
|
||
if (ids.Count == 0)
|
||
{
|
||
return [];
|
||
}
|
||
|
||
var products = await SalesProductRepository.GetListAsync(x => ids.Contains(x.Id));
|
||
var map = products.ToDictionary(x => x.Id);
|
||
return ids
|
||
.Select(id => map.TryGetValue(id, out var p) ? $"{p.ProductName}({p.ProductCode})" : $"#{id}")
|
||
.ToList();
|
||
}
|
||
|
||
private static List<int> ParseSalesProductIds(string? raw)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(raw))
|
||
{
|
||
return [];
|
||
}
|
||
|
||
var text = raw.Trim();
|
||
if (text.StartsWith('['))
|
||
{
|
||
try
|
||
{
|
||
var arr = global::System.Text.Json.JsonSerializer.Deserialize<List<int>>(text);
|
||
return arr?.Where(x => x > 0).Distinct().ToList() ?? [];
|
||
}
|
||
catch
|
||
{
|
||
// fall through
|
||
}
|
||
}
|
||
|
||
return text
|
||
.Split([',', ';', '|', ' '], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||
.Select(x => int.TryParse(x, out var id) ? id : 0)
|
||
.Where(x => x > 0)
|
||
.Distinct()
|
||
.ToList();
|
||
}
|
||
|
||
private static string ResolveBaseTypeName(string? baseType)
|
||
{
|
||
if (string.Equals(baseType, "receivable", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return "应收";
|
||
}
|
||
|
||
if (string.Equals(baseType, "freight", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return "运费";
|
||
}
|
||
|
||
return string.IsNullOrWhiteSpace(baseType) ? "运费" : baseType;
|
||
}
|
||
|
||
private async Task<Agent> GetCurrentAgentOrThrowAsync()
|
||
{
|
||
var mapId = OmsSessionHelper.ResolveMapUserId(CurrentUser);
|
||
if (mapId <= 0)
|
||
{
|
||
throw new BusinessException("代理未登录");
|
||
}
|
||
|
||
var agent = await AgentRepository.GetByUserIdAsync(mapId);
|
||
if (agent == null)
|
||
{
|
||
throw new BusinessException("代理不存在");
|
||
}
|
||
|
||
if (agent.Status != Domain.Shared.Enums.EnableStatus.Enabled)
|
||
{
|
||
throw new BusinessException("代理已停用");
|
||
}
|
||
|
||
return agent;
|
||
}
|
||
|
||
private static string? MaskPhone(string? phone)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(phone) || phone.Length < 7)
|
||
{
|
||
return phone;
|
||
}
|
||
|
||
return string.Concat(phone.AsSpan(0, 3), "****", phone.AsSpan(phone.Length - 4));
|
||
}
|
||
|
||
private static string? MaskName(string? name)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(name))
|
||
{
|
||
return name;
|
||
}
|
||
|
||
var text = name.Trim();
|
||
return text.Length <= 1 ? "*" : text[0] + new string('*', Math.Min(2, text.Length - 1));
|
||
}
|
||
}
|