菜单配置权限

This commit is contained in:
马梓彭 2026-05-15 11:07:00 +08:00
parent 2b262abda1
commit 50f0d86b91
7 changed files with 189 additions and 51 deletions

View File

@ -521,10 +521,21 @@ public class MyController : IDynamicApiController
{
var userId = GetCurrentUserId();
// 先查询所有订单
// 首先获取用户自己创建的订单ID列表
var userOrderIds = await _orderRepository.AsQueryable()
.Where(o => o.CreatedUserId == userId && !o.DeleteMark)
.Select(o => o.Id)
.ToListAsync();
// 查询订单:包括用户自己创建的订单,以及关联到用户订单的退款订单
var orders = await _orderRepository.AsQueryable()
.LeftJoin<EventInfo>((o, e) => o.EventId == e.Id)
.Where((o, e) => o.CreatedUserId == userId && !o.DeleteMark && o.OrderStatus != OrderStatus.Cancelled)
.Where((o, e) =>
!o.DeleteMark &&
o.OrderStatus != OrderStatus.Cancelled &&
(o.CreatedUserId == userId ||
(o.OrderType == 2 && o.RelatedOrderId.HasValue && userOrderIds.Contains(o.RelatedOrderId.Value)))
)
.Select((o, e) => new
{
o.Id,
@ -589,7 +600,7 @@ public class MyController : IDynamicApiController
var userId = GetCurrentUserId();
// 1. 先查询订单
var order = await _orderRepository.GetFirstAsync(o => o.Id == id && o.CreatedUserId == userId && !o.DeleteMark);
var order = await _orderRepository.GetFirstAsync(o => o.Id == id && !o.DeleteMark);
if (order == null) throw Oops.Bah("订单不存在");
// 2. 查询关联的报名信息,包括软删除的

View File

@ -183,6 +183,11 @@ public class UserEventDetailOutput
/// </summary>
public string? MaterialRemark { get; set; }
/// <summary>
/// 素材上传开始时间
/// </summary>
public DateTime? MaterialUploadStartTime { get; set; }
/// <summary>
/// 素材上传截止时间
/// </summary>

View File

@ -225,6 +225,7 @@ public class UserEventRegistrationService : IDynamicApiController, ITransient
output.IsNeedMaterial = eventInfo.IsNeedMaterial;
output.MaterialRemark = eventInfo.MaterialRemark;
output.MaterialUploadStartTime = eventInfo.MaterialUploadStartTime;
output.MaterialUploadEndTime = eventInfo.MaterialUploadEndTime;
// 查询省市区名称

View File

@ -1,5 +1,7 @@
using YD_Event.Application.Auth;
using YD_Event.Application.Menu.Dtos;
using YD_Event.Core.Options;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi;
namespace YD_Event.Application.Menu;
@ -11,14 +13,20 @@ public class SysMenuService : BaseService<SysMenu>, ITransient
private readonly ISqlSugarRepository<SysMenu> _sysMenuRepository;
private readonly IEasyCachingProvider _easyCachingProvider;
private readonly AuthManager _authManager;
private readonly ISqlSugarRepository<SysUserRole> _sysUserRoleRepository;
private readonly IOptionsMonitor<RoleOptions> _roleOptionsMonitor;
public SysMenuService(ISqlSugarRepository<SysMenu> sysMenuRepository,
IEasyCachingProvider easyCachingProvider,
AuthManager authManager) : base(sysMenuRepository)
AuthManager authManager,
ISqlSugarRepository<SysUserRole> sysUserRoleRepository,
IOptionsMonitor<RoleOptions> roleOptionsMonitor) : base(sysMenuRepository)
{
_sysMenuRepository = sysMenuRepository;
_easyCachingProvider = easyCachingProvider;
_authManager = authManager;
_sysUserRoleRepository = sysUserRoleRepository;
_roleOptionsMonitor = roleOptionsMonitor;
}
/// <summary>
@ -182,6 +190,18 @@ public class SysMenuService : BaseService<SysMenu>, ITransient
.OrderBy(x => x.Id)
.WithCache()
.ToTreeAsync(x => x.Children, x => x.ParentId, null);
// 检查当前用户是否是管理员,如果不是管理员则过滤指定菜单
var isAdmin = await IsCurrentUserAdminAsync();
if (!isAdmin)
{
var hiddenMenuIds = _roleOptionsMonitor.CurrentValue.HiddenMenuIds ?? new List<long>();
if (hiddenMenuIds.Any())
{
FilterMenus(list, hiddenMenuIds);
}
}
return list.Adapt<List<TreeSelectOutput>>();
}
@ -249,7 +269,47 @@ public class SysMenuService : BaseService<SysMenu>, ITransient
}
/// <summary>
/// 菜单按钮树
/// 检查当前登录用户是否是管理员
/// </summary>
/// <returns></returns>
private async Task<bool> IsCurrentUserAdminAsync()
{
var userId = _authManager.UserId;
// 首先检查是否是超级管理员
if (_authManager.IsSuperAdmin)
{
return true;
}
// 检查用户是否拥有管理员角色
return await _sysUserRoleRepository.IsAnyAsync(x => x.UserId == userId && x.RoleId == _roleOptionsMonitor.CurrentValue.AdminRoleId);
}
/// <summary>
/// 过滤菜单,移除配置中指定的菜单ID及其子菜单
/// </summary>
/// <param name="menus">菜单列表</param>
/// <param name="hiddenMenuIds">需要隐藏的菜单ID列表</param>
private void FilterMenus(List<SysMenu> menus, List<long> hiddenMenuIds)
{
for (int i = menus.Count - 1; i >= 0; i--)
{
var menu = menus[i];
// 如果当前菜单在隐藏列表中,移除它
if (hiddenMenuIds.Contains(menu.Id))
{
menus.RemoveAt(i);
continue;
}
// 递归处理子菜单
if (menu.Children != null && menu.Children.Any())
{
FilterMenus(menu.Children, hiddenMenuIds);
}
}
}
/// <summary>
/// 菜单按钮树 - 仅在角色管理页面使用此接口时应用隐藏规则
/// </summary>
/// <returns></returns>
[DisplayName("菜单按钮树")]
@ -275,6 +335,17 @@ public class SysMenuService : BaseService<SysMenu>, ITransient
.ToTreeAsync(x => x.Children, x => x.ParentId, null);
}
// 检查当前用户是否是管理员,如果不是管理员则过滤指定菜单
var isAdmin = await IsCurrentUserAdminAsync();
if (!isAdmin)
{
var hiddenMenuIds = _roleOptionsMonitor.CurrentValue.HiddenMenuIds ?? new List<long>();
if (hiddenMenuIds.Any())
{
FilterMenus(menus, hiddenMenuIds);
}
}
return menus.Adapt<List<TreeSelectOutput>>();
}

View File

@ -220,7 +220,10 @@ public class OrderService : BaseService<YD_Event.Core.Entities.Order>, ITransien
ContactPhone = r.ContactPhone,
OriginalAmount = o.OriginalAmount,
DiscountAmount = o.DiscountAmount,
ActualAmount = o.ActualAmount,
// 收款订单:实付金额=原金额-优惠金额;退款订单:显示原始订单的实付金额
ActualAmount = o.OrderType == 1
? (o.OriginalAmount - o.DiscountAmount > 0 ? o.OriginalAmount - o.DiscountAmount : 0)
: o.ActualAmount,
OrderStatus = o.OrderStatus,
OrderStatusText =
o.OrderStatus == OrderStatus.Pending ? "待支付" :
@ -234,7 +237,7 @@ public class OrderService : BaseService<YD_Event.Core.Entities.Order>, ITransien
PaymentTime = o.PaymentTime,
RefundAmount = o.OrderType == 2 ? o.ActualAmount : 0, // 如果是退款订单,ActualAmount即为退款金额
RefundTime = o.OrderType == 2 ? o.PaymentTime : null, // 退款时间
RelatedOrderActualAmount = o.OrderType == 2 ? ro.ActualAmount : null, // 退款订单显示原始订单实付金额
RelatedOrderActualAmount = o.OrderType == 2 ? (ro.OriginalAmount - ro.DiscountAmount) : null, // 退款订单显示原始订单实付金额(原金额-优惠金额)
IsRefundOrder = o.OrderType == 2,
PayeeName = o.PayeeName,
PayeeBankName = o.PayeeBankName,
@ -575,17 +578,23 @@ public class OrderService : BaseService<YD_Event.Core.Entities.Order>, ITransien
[HttpGet("export")]
public async Task<IActionResult> Export([FromQuery] OrderQueryInput input)
{
var list = await _orderRepository.AsQueryable()
var userId = _authManager.UserId;
// 判断是否是单位认证账号
var certification = await _db.Queryable<MerchantCertification>()
.FirstAsync(c => c.UserId == userId && c.AuditStatus == AuditStatus.Pass && !c.DeleteMark);
var query = _orderRepository.AsQueryable()
.LeftJoin<EventInfo>((o, e) => o.EventId == e.Id)
.LeftJoin<YD_Event.Core.Entities.Merchant>((o, e, m) => o.MerchantId == m.Id)
.LeftJoin<EventRegistration>((o, e, m, r) => o.RegistrationId == r.Id)
.LeftJoin<YD_Event.Core.Entities.Order>((o, e, m, r, ro) => o.RelatedOrderId == ro.Id)
// 默认只导出已完成支付流程的订单(已支付、已发货、已完成、已退款)
// 默认只导出已完成支付流程的订单(已支付、已发货、已完成、已退款、报名失败)
.WhereIF(!input.OrderStatus.HasValue, (o, e, m, r, ro) =>
o.OrderStatus == OrderStatus.Paid ||
o.OrderStatus == OrderStatus.Shipped ||
o.OrderStatus == OrderStatus.Completed ||
o.OrderStatus == OrderStatus.Refunded)
o.OrderStatus == OrderStatus.Refunded ||
o.OrderStatus == OrderStatus.RegistrationFailed)
.WhereIF(!string.IsNullOrWhiteSpace(input.OrderNo), (o, e, m, r, ro) => o.OrderNo.Contains(input.OrderNo))
.WhereIF(!string.IsNullOrWhiteSpace(input.EventName), (o, e, m, r, ro) => e.EventName.Contains(input.EventName))
.WhereIF(input.OrderType.HasValue, (o, e, m, r, ro) => o.OrderType == input.OrderType)
@ -595,38 +604,49 @@ public class OrderService : BaseService<YD_Event.Core.Entities.Order>, ITransien
.WhereIF(!string.IsNullOrWhiteSpace(input.ContactPhone), (o, e, m, r, ro) => r.ContactPhone.Contains(input.ContactPhone))
.WhereIF(input.StartTime.HasValue, (o, e, m, r, ro) => o.CreatedTime >= input.StartTime)
.WhereIF(input.EndTime.HasValue, (o, e, m, r, ro) => o.CreatedTime <= input.EndTime)
.OrderByDescending((o, e, m, r, ro) => o.CreatedTime)
.Select((o, e, m, r, ro) => new OrderListOutput
{
OrderNo = o.OrderNo,
UnitName = SqlFunc.IsNullOrEmpty(m.MerchantName) ? "/" : m.MerchantName,
EventName = e.EventName,
OrderType = o.OrderType == 1 ? "收入" : "退款",
RelatedOrderNo = ro.OrderNo,
PaymentMethod = r.PaymentMethod == 2 ? "线上" : "线下",
RegistrationMode = r.RegistrationMode == 1 ? "个人" : "团队",
ContactName = r.ContactName,
ContactPhone = r.ContactPhone,
OriginalAmount = o.OriginalAmount,
DiscountAmount = o.DiscountAmount,
ActualAmount = o.ActualAmount,
OrderStatus = o.OrderStatus,
OrderStatusText =
o.OrderStatus == OrderStatus.Pending ? "待支付" :
o.OrderStatus == OrderStatus.Paid ? "已支付" :
o.OrderStatus == OrderStatus.Cancelled ? "已取消" :
o.OrderStatus == OrderStatus.Refunded ? "已退款" :
o.OrderStatus == OrderStatus.Shipped ? "已发货" :
o.OrderStatus == OrderStatus.Completed ? "已完成" :
o.OrderStatus == OrderStatus.RegistrationFailed ? "报名失败" : "",
CreatedTime = o.CreatedTime,
RelatedOrderActualAmount = o.OrderType == 2 ? ro.ActualAmount : null,
IsRefundOrder = o.OrderType == 2,
PayeeName = o.PayeeName,
PayeeBankName = o.PayeeBankName,
PayeeBankAccount = o.PayeeBankAccount
})
.ToListAsync();
.OrderByDescending((o, e, m, r, ro) => o.CreatedTime);
// 权限判断:如果是单位认证用户,只能查看自己单位认证的订单
if (certification != null && !_authManager.IsSuperAdmin)
{
query = query.Where((o, e, m, r, ro) => o.MerchantCertificationId == certification.Id);
}
var list = await query.Select((o, e, m, r, ro) => new OrderListOutput
{
OrderNo = o.OrderNo,
UnitName = SqlFunc.IsNullOrEmpty(m.MerchantName) ? "/" : m.MerchantName,
EventName = e.EventName,
OrderType = o.OrderType == 1 ? "收入" : "退款",
RelatedOrderNo = ro.OrderNo,
PaymentMethod = r.PaymentMethod == 2 ? "线上" : "线下",
RegistrationMode = r.RegistrationMode == 1 ? "个人" : "团队",
ContactName = r.ContactName,
ContactPhone = r.ContactPhone,
OriginalAmount = o.OriginalAmount,
DiscountAmount = o.DiscountAmount,
// 收款订单:实付金额=原金额-优惠金额;退款订单:显示原始订单的实付金额
ActualAmount = o.OrderType == 1
? (o.OriginalAmount - o.DiscountAmount > 0 ? o.OriginalAmount - o.DiscountAmount : 0)
: o.ActualAmount,
OrderStatus = o.OrderStatus,
OrderStatusText =
o.OrderStatus == OrderStatus.Pending ? "待支付" :
o.OrderStatus == OrderStatus.Paid ? "已支付" :
o.OrderStatus == OrderStatus.Cancelled ? "已取消" :
o.OrderStatus == OrderStatus.Refunded ? "已退款" :
o.OrderStatus == OrderStatus.Shipped ? "已发货" :
o.OrderStatus == OrderStatus.Completed ? "已完成" :
o.OrderStatus == OrderStatus.RegistrationFailed ? "报名失败" : "",
CreatedTime = o.CreatedTime,
RefundAmount = o.OrderType == 2 ? o.ActualAmount : 0,
RelatedOrderActualAmount = o.OrderType == 2 ? (ro.OriginalAmount - ro.DiscountAmount) : null,
IsRefundOrder = o.OrderType == 2,
PayeeName = o.PayeeName,
PayeeBankName = o.PayeeBankName,
PayeeBankAccount = o.PayeeBankAccount
})
.ToListAsync();
var bytes = await GenerateOrderExcelAsync(list);
@ -648,16 +668,25 @@ public class OrderService : BaseService<YD_Event.Core.Entities.Order>, ITransien
var rowIndex = 1;
// 计算汇总数据
var totalOriginal = orders.Sum(x => x.OriginalAmount);
var totalDiscount = orders.Sum(x => x.DiscountAmount);
var totalRefund = orders.Where(x => x.OrderType == "退款").Sum(x => x.ActualAmount);
var totalActual = orders.Where(x => x.OrderType == "收款").Sum(x => x.ActualAmount);
// 计算汇总数据(根据业务要求)
// 1. 原金额:所有支付订单(排除报名失败)的原始报名费用总和
var paymentOrders = orders.Where(x => x.OrderType == "收入" && x.OrderStatus != OrderStatus.RegistrationFailed);
var totalOriginal = paymentOrders.Sum(x => x.OriginalAmount);
// 2. 优惠金额:所有支付订单(排除报名失败)的折扣金额总和
var totalDiscount = paymentOrders.Sum(x => x.DiscountAmount);
// 3. 退款金额:所有退款数据中的金额总和,排除报名失败状态的退款记录
var refundOrders = orders.Where(x => x.OrderType == "退款" && x.OrderStatus != OrderStatus.RegistrationFailed);
var totalRefund = refundOrders.Sum(x => x.ActualAmount);
// 4. 实付金额:所有实际收款的金额总和,排除报名失败状态的订单记录
var totalActual = paymentOrders.Sum(x => x.ActualAmount);
// 汇总信息行
var summaryRange = worksheet.Cells[rowIndex, 1, rowIndex, 19];
summaryRange.Merge = true;
summaryRange.Value = $"汇总信息: 原金额:{totalOriginal}, 优惠金额:{totalDiscount}, 退款金额:{totalRefund}, 实付金额:{totalActual}";
summaryRange.Value = $"汇总信息: 原金额:{totalOriginal:F2}, 优惠金额:{totalDiscount:F2}, 退款金额:{totalRefund:F2}, 实付金额:{totalActual:F2}";
var summaryStyle = summaryRange.Style;
summaryStyle.Font.Bold = true;
summaryStyle.Font.Size = 12;
@ -697,8 +726,23 @@ public class OrderService : BaseService<YD_Event.Core.Entities.Order>, ITransien
{
// 统一显示为"收款"而不是"收入"
var orderTypeText = item.OrderType == "收入" ? "收款" : item.OrderType;
var refundAmount = item.OrderType == "退款" ? item.ActualAmount : 0;
var actualPayAmount = item.OrderType == "收入" ? item.ActualAmount : 0;
// 计算金额(与页面展示完全一致)
decimal actualPayAmount;
decimal refundAmount;
if (item.IsRefundOrder)
{
// 退款订单:实付金额显示原始订单的实付金额
actualPayAmount = item.RelatedOrderActualAmount ?? 0;
refundAmount = item.ActualAmount;
}
else
{
// 收款订单:实付金额=原金额-优惠金额
actualPayAmount = item.ActualAmount; // 已经在查询时计算好了
refundAmount = 0;
}
worksheet.Cells[rowIndex, 1].Value = item.OrderNo;
worksheet.Cells[rowIndex, 2].Value = item.UnitName;

View File

@ -167,6 +167,7 @@
// 角色配置
"RoleSettings": {
"AdminRoleId": 1000,
"UnitUserRoleId": 1001
"UnitUserRoleId": 1001,
"HiddenMenuIds": [2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009]
}
}

View File

@ -17,4 +17,9 @@ public class RoleOptions : IConfigurableOptions
/// 单位用户角色ID
/// </summary>
public long UnitUserRoleId { get; set; }
/// <summary>
/// 需要对非管理员用户隐藏的菜单ID列表
/// </summary>
public List<long> HiddenMenuIds { get; set; } = new List<long>();
}