1.06 #10
@ -10,12 +10,32 @@ public class MonitorOverviewOutput
|
|||||||
public MonitorCustomerStatsOutput Customer { get; set; } = new();
|
public MonitorCustomerStatsOutput Customer { get; set; } = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 近 7 日新增订单趋势。
|
/// 经营指标(订单量/营收/毛利)按日周月维度。
|
||||||
|
/// </summary>
|
||||||
|
public MonitorOpsStatsOutput Ops { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实时积压队列(不随维度变化)。
|
||||||
|
/// </summary>
|
||||||
|
public MonitorQueueStatsOutput Queue { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 订单趋势(随 dimension 变化;兼容字段名 OrderTrend7d 在 day 时等同本字段)。
|
||||||
|
/// </summary>
|
||||||
|
public List<MonitorTrendPointOutput> OrderTrend { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 近 7 日新增订单趋势(兼容旧前端;dimension=day 时与 OrderTrend 相同)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<MonitorTrendPointOutput> OrderTrend7d { get; set; } = [];
|
public List<MonitorTrendPointOutput> OrderTrend7d { get; set; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 近 7 日营收/毛利趋势。
|
/// 营收/毛利趋势(随 dimension 变化)。
|
||||||
|
/// </summary>
|
||||||
|
public List<MonitorRevenueTrendPointOutput> RevenueTrend { get; set; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 近 7 日营收/毛利趋势(兼容旧前端;dimension=day 时与 RevenueTrend 相同)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<MonitorRevenueTrendPointOutput> RevenueTrend7d { get; set; } = [];
|
public List<MonitorRevenueTrendPointOutput> RevenueTrend7d { get; set; } = [];
|
||||||
|
|
||||||
@ -40,6 +60,47 @@ public class MonitorOverviewOutput
|
|||||||
public MonitorTrackRatesOutput TrackRates { get; set; } = new();
|
public MonitorTrackRatesOutput TrackRates { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 经营 KPI:订单量 / 营收 / 毛利(随日周月)。
|
||||||
|
/// </summary>
|
||||||
|
public class MonitorOpsStatsOutput
|
||||||
|
{
|
||||||
|
/// <summary>day / week / month</summary>
|
||||||
|
public string Dimension { get; set; } = "day";
|
||||||
|
|
||||||
|
/// <summary>当前周期新建订单数。</summary>
|
||||||
|
public int OrderCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>订单量环比增长百分比。</summary>
|
||||||
|
public decimal? OrderCountGrowthPercent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>当前周期应收(已付)营收。</summary>
|
||||||
|
public decimal Revenue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>营收环比增长百分比。</summary>
|
||||||
|
public decimal? RevenueGrowthPercent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>当前周期毛利 = 应收 - 应付。</summary>
|
||||||
|
public decimal GrossProfit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>毛利环比增长百分比。</summary>
|
||||||
|
public decimal? GrossProfitGrowthPercent { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实时积压快照(不受日周月影响)。
|
||||||
|
/// </summary>
|
||||||
|
public class MonitorQueueStatsOutput
|
||||||
|
{
|
||||||
|
public int PendingPayment { get; set; }
|
||||||
|
|
||||||
|
public int PendingOnline { get; set; }
|
||||||
|
|
||||||
|
public int PendingSign { get; set; }
|
||||||
|
|
||||||
|
public int Problematic { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class MonitorOrderStatsOutput
|
public class MonitorOrderStatsOutput
|
||||||
{
|
{
|
||||||
public int TodayCreated { get; set; }
|
public int TodayCreated { get; set; }
|
||||||
|
|||||||
@ -34,4 +34,9 @@ public class NoticeListInput
|
|||||||
/// 仅未读(相对当前登录主体)。
|
/// 仅未读(相对当前登录主体)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? OnlyUnread { get; set; }
|
public bool? OnlyUnread { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 管理端查看全部通知(仅非客户登录生效)。默认按当前主体可见范围过滤。
|
||||||
|
/// </summary>
|
||||||
|
public bool? Manage { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,9 +12,12 @@ public partial class OrderService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 实时监控页概览(订单/客户统计与趋势)。
|
/// 实时监控页概览(订单/客户统计与趋势)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="dimension">经营指标维度:day / week / month,默认 day。</param>
|
||||||
[HttpGet("/monitor/overview")]
|
[HttpGet("/monitor/overview")]
|
||||||
public async Task<MonitorOverviewOutput> GetMonitorOverviewAsync()
|
public async Task<MonitorOverviewOutput> GetMonitorOverviewAsync(
|
||||||
|
[FromQuery] string? dimension = "day")
|
||||||
{
|
{
|
||||||
|
var dim = NormalizeMonitorDimension(dimension);
|
||||||
var filter = await BuildScopedListFilterAsync();
|
var filter = await BuildScopedListFilterAsync();
|
||||||
var today = DateTime.Today;
|
var today = DateTime.Today;
|
||||||
var tomorrow = today.AddDays(1);
|
var tomorrow = today.AddDays(1);
|
||||||
@ -28,21 +31,60 @@ public partial class OrderService
|
|||||||
int GetCount(string status) =>
|
int GetCount(string status) =>
|
||||||
counts.TryGetValue(status, out var value) ? value : 0;
|
counts.TryGetValue(status, out var value) ? value : 0;
|
||||||
|
|
||||||
var todayCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, today, tomorrow);
|
var pendingPayment = GetCount(OrderStatusCodes.PendingPayment);
|
||||||
var yesterdayCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, yesterday, today);
|
var pendingOnline = GetCount(OrderStatusCodes.PendingOnline);
|
||||||
|
var pendingSign = GetCount(OrderStatusCodes.Shipping);
|
||||||
|
var problematic = GetCount(OrderStatusCodes.Problematic);
|
||||||
|
|
||||||
|
var (currentStart, currentEndExclusive, previousStart, previousEndExclusive) =
|
||||||
|
ResolveOpsPeriodRanges(dim, today, tomorrow);
|
||||||
|
|
||||||
|
var orderCount = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(
|
||||||
|
filter, currentStart, currentEndExclusive);
|
||||||
|
var previousOrderCount = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(
|
||||||
|
filter, previousStart, previousEndExclusive);
|
||||||
|
|
||||||
|
var revenue = await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
||||||
|
filter, OrderFeeTypeCodes.Receivable, currentStart, currentEndExclusive);
|
||||||
|
var previousRevenue = await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
||||||
|
filter, OrderFeeTypeCodes.Receivable, previousStart, previousEndExclusive);
|
||||||
|
|
||||||
|
var payable = await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
||||||
|
filter, OrderFeeTypeCodes.Payable, currentStart, currentEndExclusive);
|
||||||
|
var previousPayable = await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
||||||
|
filter, OrderFeeTypeCodes.Payable, previousStart, previousEndExclusive);
|
||||||
|
var grossProfit = revenue - payable;
|
||||||
|
var previousGrossProfit = previousRevenue - previousPayable;
|
||||||
|
|
||||||
|
// 兼容旧字段:始终提供「今日」口径
|
||||||
|
var todayCreated = dim == "day"
|
||||||
|
? orderCount
|
||||||
|
: await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, today, tomorrow);
|
||||||
|
var yesterdayCreated = dim == "day"
|
||||||
|
? previousOrderCount
|
||||||
|
: await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, yesterday, today);
|
||||||
|
var todayRevenue = dim == "day"
|
||||||
|
? revenue
|
||||||
|
: await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
||||||
|
filter, OrderFeeTypeCodes.Receivable, today, tomorrow);
|
||||||
|
var yesterdayRevenue = dim == "day"
|
||||||
|
? previousRevenue
|
||||||
|
: await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
||||||
|
filter, OrderFeeTypeCodes.Receivable, yesterday, today);
|
||||||
|
|
||||||
var monthStart = new DateTime(today.Year, today.Month, 1);
|
var monthStart = new DateTime(today.Year, today.Month, 1);
|
||||||
var lastMonthStart = monthStart.AddMonths(-1);
|
var lastMonthStart = monthStart.AddMonths(-1);
|
||||||
var thisMonthCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, monthStart, tomorrow);
|
var thisMonthCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, monthStart, tomorrow);
|
||||||
var lastMonthCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, lastMonthStart, monthStart);
|
var lastMonthCreated = await OrderRepository.CountByFilterAndCreateTimeRangeAsync(filter, lastMonthStart, monthStart);
|
||||||
|
|
||||||
var todayRevenue = await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
var trendCount = dim switch
|
||||||
filter, OrderFeeTypeCodes.Receivable, today, tomorrow);
|
{
|
||||||
var yesterdayRevenue = await OrderRepository.SumFeeAmountByPayTimeRangeAsync(
|
"week" => 8,
|
||||||
filter, OrderFeeTypeCodes.Receivable, yesterday, today);
|
"month" => 6,
|
||||||
|
_ => 7,
|
||||||
var orderTrend7d = await BuildMonitorOrderTrendAsync(filter, 7);
|
};
|
||||||
var revenueTrend7d = await BuildMonitorRevenueTrendAsync(filter, 7);
|
var orderTrend = await BuildMonitorOrderTrendAsync(filter, dim, trendCount);
|
||||||
|
var revenueTrend = await BuildMonitorRevenueTrendAsync(filter, dim, trendCount);
|
||||||
|
|
||||||
var recentFilter = CloneFilterWithCreateTimeStart(filter, today.AddDays(-90));
|
var recentFilter = CloneFilterWithCreateTimeStart(filter, today.AddDays(-90));
|
||||||
var recentOrders = await OrderRepository.GetFilteredListAsync(recentFilter);
|
var recentOrders = await OrderRepository.GetFilteredListAsync(recentFilter);
|
||||||
@ -83,13 +125,30 @@ public partial class OrderService
|
|||||||
TodayCreatedGrowthPercent = CalcGrowthPercent(todayCreated, yesterdayCreated),
|
TodayCreatedGrowthPercent = CalcGrowthPercent(todayCreated, yesterdayCreated),
|
||||||
Total = counts.Values.Sum(),
|
Total = counts.Values.Sum(),
|
||||||
TotalMonthGrowthPercent = CalcGrowthPercent(thisMonthCreated, lastMonthCreated),
|
TotalMonthGrowthPercent = CalcGrowthPercent(thisMonthCreated, lastMonthCreated),
|
||||||
PendingPayment = GetCount(OrderStatusCodes.PendingPayment),
|
PendingPayment = pendingPayment,
|
||||||
PendingOnline = GetCount(OrderStatusCodes.PendingOnline),
|
PendingOnline = pendingOnline,
|
||||||
PendingSign = GetCount(OrderStatusCodes.Shipping),
|
PendingSign = pendingSign,
|
||||||
Problematic = GetCount(OrderStatusCodes.Problematic),
|
Problematic = problematic,
|
||||||
TodayRevenue = todayRevenue,
|
TodayRevenue = todayRevenue,
|
||||||
TodayRevenueGrowthPercent = CalcGrowthPercentDecimal(todayRevenue, yesterdayRevenue),
|
TodayRevenueGrowthPercent = CalcGrowthPercentDecimal(todayRevenue, yesterdayRevenue),
|
||||||
},
|
},
|
||||||
|
Ops = new MonitorOpsStatsOutput
|
||||||
|
{
|
||||||
|
Dimension = dim,
|
||||||
|
OrderCount = orderCount,
|
||||||
|
OrderCountGrowthPercent = CalcGrowthPercent(orderCount, previousOrderCount),
|
||||||
|
Revenue = revenue,
|
||||||
|
RevenueGrowthPercent = CalcGrowthPercentDecimal(revenue, previousRevenue),
|
||||||
|
GrossProfit = grossProfit,
|
||||||
|
GrossProfitGrowthPercent = CalcGrowthPercentDecimal(grossProfit, previousGrossProfit),
|
||||||
|
},
|
||||||
|
Queue = new MonitorQueueStatsOutput
|
||||||
|
{
|
||||||
|
PendingPayment = pendingPayment,
|
||||||
|
PendingOnline = pendingOnline,
|
||||||
|
PendingSign = pendingSign,
|
||||||
|
Problematic = problematic,
|
||||||
|
},
|
||||||
Customer = new MonitorCustomerStatsOutput
|
Customer = new MonitorCustomerStatsOutput
|
||||||
{
|
{
|
||||||
TotalCustomers = totalCustomers,
|
TotalCustomers = totalCustomers,
|
||||||
@ -100,8 +159,10 @@ public partial class OrderService
|
|||||||
InactiveLogin7d = inactiveLogin7d,
|
InactiveLogin7d = inactiveLogin7d,
|
||||||
InactiveLogin7dDelta = inactiveLogin7d - inactiveLogin14d,
|
InactiveLogin7dDelta = inactiveLogin7d - inactiveLogin14d,
|
||||||
},
|
},
|
||||||
OrderTrend7d = orderTrend7d,
|
OrderTrend = orderTrend,
|
||||||
RevenueTrend7d = revenueTrend7d,
|
OrderTrend7d = dim == "day" ? orderTrend : await BuildMonitorOrderTrendAsync(filter, "day", 7),
|
||||||
|
RevenueTrend = revenueTrend,
|
||||||
|
RevenueTrend7d = dim == "day" ? revenueTrend : await BuildMonitorRevenueTrendAsync(filter, "day", 7),
|
||||||
RegionOrderTrend = new MonitorRegionTrendBundleOutput
|
RegionOrderTrend = new MonitorRegionTrendBundleOutput
|
||||||
{
|
{
|
||||||
Week = new MonitorRegionTrendPeriodOutput { Labels = weekOrderLabels, Series = weekOrderSeries },
|
Week = new MonitorRegionTrendPeriodOutput { Labels = weekOrderLabels, Series = weekOrderSeries },
|
||||||
@ -117,11 +178,42 @@ public partial class OrderService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string NormalizeMonitorDimension(string? dimension)
|
||||||
|
{
|
||||||
|
var dim = (dimension ?? "day").Trim().ToLowerInvariant();
|
||||||
|
return dim is "day" or "week" or "month" ? dim : "day";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前周期(统计到今天结束)与上一完整同尺度周期。
|
||||||
|
/// </summary>
|
||||||
|
private static (DateTime CurrentStart, DateTime CurrentEndExclusive, DateTime PreviousStart, DateTime PreviousEndExclusive)
|
||||||
|
ResolveOpsPeriodRanges(string dimension, DateTime today, DateTime tomorrow)
|
||||||
|
{
|
||||||
|
if (dimension == "week")
|
||||||
|
{
|
||||||
|
var weekStart = GetWeekStart(today);
|
||||||
|
var previousWeekStart = weekStart.AddDays(-7);
|
||||||
|
return (weekStart, tomorrow, previousWeekStart, weekStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dimension == "month")
|
||||||
|
{
|
||||||
|
var monthStart = new DateTime(today.Year, today.Month, 1);
|
||||||
|
var previousMonthStart = monthStart.AddMonths(-1);
|
||||||
|
return (monthStart, tomorrow, previousMonthStart, monthStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
var yesterday = today.AddDays(-1);
|
||||||
|
return (today, tomorrow, yesterday, today);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<List<MonitorTrendPointOutput>> BuildMonitorOrderTrendAsync(
|
private async Task<List<MonitorTrendPointOutput>> BuildMonitorOrderTrendAsync(
|
||||||
OrderListFilter filter,
|
OrderListFilter filter,
|
||||||
|
string dimension,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
var buckets = BuildTrendBuckets("day", count);
|
var buckets = BuildTrendBuckets(dimension, count);
|
||||||
var points = new List<MonitorTrendPointOutput>(buckets.Count);
|
var points = new List<MonitorTrendPointOutput>(buckets.Count);
|
||||||
foreach (var bucket in buckets)
|
foreach (var bucket in buckets)
|
||||||
{
|
{
|
||||||
@ -135,9 +227,10 @@ public partial class OrderService
|
|||||||
|
|
||||||
private async Task<List<MonitorRevenueTrendPointOutput>> BuildMonitorRevenueTrendAsync(
|
private async Task<List<MonitorRevenueTrendPointOutput>> BuildMonitorRevenueTrendAsync(
|
||||||
OrderListFilter filter,
|
OrderListFilter filter,
|
||||||
|
string dimension,
|
||||||
int count)
|
int count)
|
||||||
{
|
{
|
||||||
var buckets = BuildTrendBuckets("day", count);
|
var buckets = BuildTrendBuckets(dimension, count);
|
||||||
var points = new List<MonitorRevenueTrendPointOutput>(buckets.Count);
|
var points = new List<MonitorRevenueTrendPointOutput>(buckets.Count);
|
||||||
foreach (var bucket in buckets)
|
foreach (var bucket in buckets)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -49,15 +49,16 @@ public class NoticeService : ApplicationService
|
|||||||
[HttpGet("/system/notice/list")]
|
[HttpGet("/system/notice/list")]
|
||||||
public async Task<OmsPageResult<NoticeOutput>> GetListAsync([FromQuery] NoticeListInput input)
|
public async Task<OmsPageResult<NoticeOutput>> GetListAsync([FromQuery] NoticeListInput input)
|
||||||
{
|
{
|
||||||
var receiverUserId = CurrentUser.GetId<int>();
|
var receiverUserId = OmsSessionHelper.ResolveMapUserId(CurrentUser);
|
||||||
if (receiverUserId <= 0)
|
if (receiverUserId <= 0)
|
||||||
{
|
{
|
||||||
return new OmsPageResult<NoticeOutput> { Items = [], Total = 0 };
|
return new OmsPageResult<NoticeOutput> { Items = [], Total = 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedReceiverType = OmsSessionHelper.IsCustomerLogin(CurrentUser)
|
var isCustomer = OmsSessionHelper.IsCustomerLogin(CurrentUser);
|
||||||
? ReceiverTypeCustomer
|
var expectedReceiverType = isCustomer ? ReceiverTypeCustomer : ReceiverTypeUser;
|
||||||
: ReceiverTypeUser;
|
// 管理端公告页:管理员可看全部;工作台/H5/未读仍按接收范围过滤
|
||||||
|
var manageAll = input.Manage == true && !isCustomer;
|
||||||
|
|
||||||
var myReadNoticeIds = (await NoticeReadRepository.GetListAsync(x =>
|
var myReadNoticeIds = (await NoticeReadRepository.GetListAsync(x =>
|
||||||
x.ReceiverType == expectedReceiverType && x.ReceiverId == receiverUserId))
|
x.ReceiverType == expectedReceiverType && x.ReceiverId == receiverUserId))
|
||||||
@ -65,11 +66,13 @@ public class NoticeService : ApplicationService
|
|||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var predicate = BuildListPredicate(
|
var predicate = manageAll
|
||||||
input,
|
? BuildManageListPredicate(input)
|
||||||
receiverUserId,
|
: BuildListPredicate(
|
||||||
expectedReceiverType,
|
input,
|
||||||
input.OnlyUnread == true ? myReadNoticeIds : null);
|
receiverUserId,
|
||||||
|
expectedReceiverType,
|
||||||
|
input.OnlyUnread == true ? myReadNoticeIds : null);
|
||||||
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
|
var pageIndex = OmsDocHelper.NormalizePage(input.Page);
|
||||||
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
var pageSize = OmsDocHelper.NormalizePageSize(input.PageSize);
|
||||||
var notices = await NoticeRepository.GetPagedListAsync(
|
var notices = await NoticeRepository.GetPagedListAsync(
|
||||||
@ -197,7 +200,7 @@ public class NoticeService : ApplicationService
|
|||||||
var currentReceiverType = OmsSessionHelper.IsCustomerLogin(CurrentUser)
|
var currentReceiverType = OmsSessionHelper.IsCustomerLogin(CurrentUser)
|
||||||
? ReceiverTypeCustomer
|
? ReceiverTypeCustomer
|
||||||
: ReceiverTypeUser;
|
: ReceiverTypeUser;
|
||||||
var currentReceiverId = CurrentUser.GetId<int>();
|
var currentReceiverId = OmsSessionHelper.ResolveMapUserId(CurrentUser);
|
||||||
if (currentReceiverId <= 0)
|
if (currentReceiverId <= 0)
|
||||||
{
|
{
|
||||||
throw new BusinessException("当前登录主体无效");
|
throw new BusinessException("当前登录主体无效");
|
||||||
@ -349,6 +352,19 @@ public class NoticeService : ApplicationService
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Expression<Func<Notice, bool>> BuildManageListPredicate(NoticeListInput input)
|
||||||
|
{
|
||||||
|
var noticeType = input.NoticeType?.Trim();
|
||||||
|
var receiverType = input.ReceiverType?.Trim();
|
||||||
|
var keyword = input.Keyword?.Trim();
|
||||||
|
return x =>
|
||||||
|
(string.IsNullOrWhiteSpace(noticeType) || x.NoticeType == noticeType) &&
|
||||||
|
(string.IsNullOrWhiteSpace(receiverType) || x.ReceiverType == receiverType) &&
|
||||||
|
(string.IsNullOrWhiteSpace(keyword) ||
|
||||||
|
x.Title.Contains(keyword) ||
|
||||||
|
x.Content.Contains(keyword));
|
||||||
|
}
|
||||||
|
|
||||||
private static Expression<Func<Notice, bool>> BuildListPredicate(
|
private static Expression<Func<Notice, bool>> BuildListPredicate(
|
||||||
NoticeListInput input,
|
NoticeListInput input,
|
||||||
int receiverUserId,
|
int receiverUserId,
|
||||||
|
|||||||
@ -43,6 +43,27 @@ public static class OmsSessionHelper
|
|||||||
return string.Equals(role, CustomerRoleName, StringComparison.OrdinalIgnoreCase);
|
return string.Equals(role, CustomerRoleName, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析当前会话的 RBAC mapId(user.userid)。
|
||||||
|
/// JWT nameidentifier 多为 Guid,GetId<int> 常为 0,需回退读 mapId claim。
|
||||||
|
/// </summary>
|
||||||
|
public static int ResolveMapUserId(ICurrentUser currentUser)
|
||||||
|
{
|
||||||
|
var userId = currentUser.GetId<int>();
|
||||||
|
if (userId > 0)
|
||||||
|
{
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapIdRaw = currentUser.FindClaimOrNull(MapIdClaim)?.Value;
|
||||||
|
if (int.TryParse(mapIdRaw, out var mapId) && mapId > 0)
|
||||||
|
{
|
||||||
|
return mapId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 客户登录时返回 mapId(对应 t_customer.UserId / 订单 CreateUserId);管理员返回 null。
|
/// 客户登录时返回 mapId(对应 t_customer.UserId / 订单 CreateUserId);管理员返回 null。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -53,20 +74,8 @@ public static class OmsSessionHelper
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userId = currentUser.GetId<int>();
|
var mapId = ResolveMapUserId(currentUser);
|
||||||
if (userId > 0)
|
return mapId > 0 ? mapId : null;
|
||||||
{
|
|
||||||
return userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetId 未绑到 mapId 时,直接读 claim,避免客户会话被当成管理员(不过滤)
|
|
||||||
var mapIdRaw = currentUser.FindClaimOrNull(MapIdClaim)?.Value;
|
|
||||||
if (int.TryParse(mapIdRaw, out var mapId) && mapId > 0)
|
|
||||||
{
|
|
||||||
return mapId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user