From 50f0d86b91e0ee40c7877f94c4f9f5262765ba96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A9=AC=E6=A2=93=E5=BD=AD?= Date: Fri, 15 May 2026 11:07:00 +0800 Subject: [PATCH] =?UTF-8?q?=E8=8F=9C=E5=8D=95=E9=85=8D=E7=BD=AE=E6=9D=83?= =?UTF-8?q?=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- YD_Event.Application/Client/MyController.cs | 17 ++- .../Event/Dtos/UserCompetitionDtos.cs | 5 + .../Event/UserEventRegistrationService.cs | 1 + YD_Event.Application/Menu/SysMenuService.cs | 75 +++++++++- YD_Event.Application/Order/OrderService.cs | 134 ++++++++++++------ YD_Event.Application/applicationsettings.json | 3 +- YD_Event.Core/Options/RoleOptions.cs | 5 + 7 files changed, 189 insertions(+), 51 deletions(-) diff --git a/YD_Event.Application/Client/MyController.cs b/YD_Event.Application/Client/MyController.cs index 9820d39..446b202 100644 --- a/YD_Event.Application/Client/MyController.cs +++ b/YD_Event.Application/Client/MyController.cs @@ -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((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. 查询关联的报名信息,包括软删除的 diff --git a/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs b/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs index 67167ba..0c11b80 100644 --- a/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs +++ b/YD_Event.Application/Event/Dtos/UserCompetitionDtos.cs @@ -183,6 +183,11 @@ public class UserEventDetailOutput /// public string? MaterialRemark { get; set; } + /// + /// 素材上传开始时间 + /// + public DateTime? MaterialUploadStartTime { get; set; } + /// /// 素材上传截止时间 /// diff --git a/YD_Event.Application/Event/UserEventRegistrationService.cs b/YD_Event.Application/Event/UserEventRegistrationService.cs index 8e1d6cd..5d14e24 100644 --- a/YD_Event.Application/Event/UserEventRegistrationService.cs +++ b/YD_Event.Application/Event/UserEventRegistrationService.cs @@ -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; // 查询省市区名称 diff --git a/YD_Event.Application/Menu/SysMenuService.cs b/YD_Event.Application/Menu/SysMenuService.cs index 1c7dcfa..27ae9e0 100644 --- a/YD_Event.Application/Menu/SysMenuService.cs +++ b/YD_Event.Application/Menu/SysMenuService.cs @@ -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, ITransient private readonly ISqlSugarRepository _sysMenuRepository; private readonly IEasyCachingProvider _easyCachingProvider; private readonly AuthManager _authManager; + private readonly ISqlSugarRepository _sysUserRoleRepository; + private readonly IOptionsMonitor _roleOptionsMonitor; public SysMenuService(ISqlSugarRepository sysMenuRepository, IEasyCachingProvider easyCachingProvider, - AuthManager authManager) : base(sysMenuRepository) + AuthManager authManager, + ISqlSugarRepository sysUserRoleRepository, + IOptionsMonitor roleOptionsMonitor) : base(sysMenuRepository) { _sysMenuRepository = sysMenuRepository; _easyCachingProvider = easyCachingProvider; _authManager = authManager; + _sysUserRoleRepository = sysUserRoleRepository; + _roleOptionsMonitor = roleOptionsMonitor; } /// @@ -182,6 +190,18 @@ public class SysMenuService : BaseService, 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(); + if (hiddenMenuIds.Any()) + { + FilterMenus(list, hiddenMenuIds); + } + } + return list.Adapt>(); } @@ -249,7 +269,47 @@ public class SysMenuService : BaseService, ITransient } /// - /// 菜单按钮树 + /// 检查当前登录用户是否是管理员 + /// + /// + private async Task IsCurrentUserAdminAsync() + { + var userId = _authManager.UserId; + // 首先检查是否是超级管理员 + if (_authManager.IsSuperAdmin) + { + return true; + } + // 检查用户是否拥有管理员角色 + return await _sysUserRoleRepository.IsAnyAsync(x => x.UserId == userId && x.RoleId == _roleOptionsMonitor.CurrentValue.AdminRoleId); + } + + /// + /// 过滤菜单,移除配置中指定的菜单ID及其子菜单 + /// + /// 菜单列表 + /// 需要隐藏的菜单ID列表 + private void FilterMenus(List menus, List 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); + } + } + } + + /// + /// 菜单按钮树 - 仅在角色管理页面使用此接口时应用隐藏规则 /// /// [DisplayName("菜单按钮树")] @@ -275,6 +335,17 @@ public class SysMenuService : BaseService, ITransient .ToTreeAsync(x => x.Children, x => x.ParentId, null); } + // 检查当前用户是否是管理员,如果不是管理员则过滤指定菜单 + var isAdmin = await IsCurrentUserAdminAsync(); + if (!isAdmin) + { + var hiddenMenuIds = _roleOptionsMonitor.CurrentValue.HiddenMenuIds ?? new List(); + if (hiddenMenuIds.Any()) + { + FilterMenus(menus, hiddenMenuIds); + } + } + return menus.Adapt>(); } diff --git a/YD_Event.Application/Order/OrderService.cs b/YD_Event.Application/Order/OrderService.cs index 42103dc..d06900a 100644 --- a/YD_Event.Application/Order/OrderService.cs +++ b/YD_Event.Application/Order/OrderService.cs @@ -220,7 +220,10 @@ public class OrderService : BaseService, 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, 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, ITransien [HttpGet("export")] public async Task Export([FromQuery] OrderQueryInput input) { - var list = await _orderRepository.AsQueryable() + var userId = _authManager.UserId; + // 判断是否是单位认证账号 + var certification = await _db.Queryable() + .FirstAsync(c => c.UserId == userId && c.AuditStatus == AuditStatus.Pass && !c.DeleteMark); + + var query = _orderRepository.AsQueryable() .LeftJoin((o, e) => o.EventId == e.Id) .LeftJoin((o, e, m) => o.MerchantId == m.Id) .LeftJoin((o, e, m, r) => o.RegistrationId == r.Id) .LeftJoin((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, 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, 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, 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; diff --git a/YD_Event.Application/applicationsettings.json b/YD_Event.Application/applicationsettings.json index 50d414e..13f558e 100644 --- a/YD_Event.Application/applicationsettings.json +++ b/YD_Event.Application/applicationsettings.json @@ -167,6 +167,7 @@ // 角色配置 "RoleSettings": { "AdminRoleId": 1000, - "UnitUserRoleId": 1001 + "UnitUserRoleId": 1001, + "HiddenMenuIds": [2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009] } } \ No newline at end of file diff --git a/YD_Event.Core/Options/RoleOptions.cs b/YD_Event.Core/Options/RoleOptions.cs index dc64991..0a806af 100644 --- a/YD_Event.Core/Options/RoleOptions.cs +++ b/YD_Event.Core/Options/RoleOptions.cs @@ -17,4 +17,9 @@ public class RoleOptions : IConfigurableOptions /// 单位用户角色ID /// public long UnitUserRoleId { get; set; } + + /// + /// 需要对非管理员用户隐藏的菜单ID列表 + /// + public List HiddenMenuIds { get; set; } = new List(); }