using System.Text; using OfficeOpenXml; using OfficeOpenXml.Style; using System.Drawing; using YD_Event.Application.Auth; using YD_Event.Application.Event; using YD_Event.Application.Order.Dtos; using YD_Event.Core.Entities; using YD_Event.Core.Enum; using Microsoft.Extensions.Logging; using YD_Event.Core.Domain; namespace YD_Event.Application.Order; /// /// 订单管理服务 /// public class OrderService : BaseService, ITransient { private readonly ISqlSugarRepository _orderRepository; private readonly ISqlSugarRepository _registrationRepository; private readonly ISqlSugarRepository _itemRepository; private readonly ISqlSugarRepository _personRepository; private readonly ISqlSugarRepository _paymentRepository; private readonly ISqlSugarRepository _eventRepository; private readonly ISqlSugarRepository _merchantRepository; private readonly IIdGenerator _idGenerator; private readonly AuthManager _authManager; private readonly ISqlSugarClient _db; private readonly OrderNoGeneratorService _orderNoGeneratorService; private readonly ILogger _logger; private readonly UnifiedRegistrationService _unifiedRegistrationService; public OrderService( ISqlSugarRepository orderRepository, ISqlSugarRepository registrationRepository, ISqlSugarRepository itemRepository, ISqlSugarRepository personRepository, ISqlSugarRepository paymentRepository, ISqlSugarRepository eventRepository, ISqlSugarRepository merchantRepository, IIdGenerator idGenerator, AuthManager authManager, ISqlSugarClient db, OrderNoGeneratorService orderNoGeneratorService, ILogger logger, UnifiedRegistrationService unifiedRegistrationService) : base(orderRepository) { _orderRepository = orderRepository; _registrationRepository = registrationRepository; _itemRepository = itemRepository; _personRepository = personRepository; _paymentRepository = paymentRepository; _eventRepository = eventRepository; _merchantRepository = merchantRepository; _idGenerator = idGenerator; _authManager = authManager; _db = db; _orderNoGeneratorService = orderNoGeneratorService; _logger = logger; _unifiedRegistrationService = unifiedRegistrationService; } /// /// 创建订单 /// [DisplayName("创建订单")] [HttpPost("create")] [UnitOfWork] public async Task Create(CreateOrderInput input) { // 1. 创建报名记录 var entity = input.Adapt(); entity.Id = _idGenerator.NextId(); entity.OrderNo = await _orderNoGeneratorService.GenerateOrderNoAsync(); entity.PaymentStatus = 0; // 未支付 entity.RegistrationTime = DateTime.Now; entity.RegistrationMode = 2; // 后台管理页面只做团队报名 // 计算总金额 decimal totalAmount = 0; int totalPerson = 0; if (input.Items != null) { foreach (var item in input.Items) { totalAmount += item.UnitPrice * item.PersonCount; totalPerson += item.PersonCount; } } entity.TotalAmount = totalAmount; entity.TotalPersonCount = totalPerson; await _registrationRepository.InsertAsync(entity); // 2. 创建报名项目 var createdItems = new List(); if (input.Items != null && input.Items.Any()) { var items = input.Items.Adapt>(); items.ForEach(x => { x.Id = _idGenerator.NextId(); x.RegistrationId = entity.Id; x.TotalPrice = x.UnitPrice * x.PersonCount; }); await _itemRepository.InsertRangeAsync(items); createdItems = items; } // 3. 创建报名人员 if (input.Persons != null && input.Persons.Any()) { var persons = input.Persons.Adapt>(); persons.ForEach(x => { x.Id = _idGenerator.NextId(); x.RegistrationId = entity.Id; // 根据项目ID和组别名称关联到报名项目 var linkedItem = createdItems.FirstOrDefault(i => i.ProjectId == x.ProjectId && i.GroupName == x.GroupName); if (linkedItem != null) { x.RegistrationItemId = linkedItem.Id; } // 确保组别名称不为空(数据库约束) if (string.IsNullOrEmpty(x.GroupName)) x.GroupName = ""; }); await _personRepository.InsertRangeAsync(persons); } // 4. 创建订单(收入) // 获取赛事关联的商户ID var eventInfo = await _eventRepository.GetByIdAsync(input.EventId); // 获取当前用户的单位认证ID var certification = await _db.Queryable() .FirstAsync(c => c.UserId == entity.CreatedUserId && c.AuditStatus == AuditStatus.Pass && !c.DeleteMark); var order = new YD_Event.Core.Entities.Order { Id = _idGenerator.NextId(), OrderNo = entity.OrderNo, OrderType = 1, // 收入 MerchantId = eventInfo?.MerchantId, // 设置商户ID(支付商户) MerchantCertificationId = certification?.Id, // 设置单位认证ID EventId = input.EventId, RegistrationId = entity.Id, OriginalAmount = totalAmount, ActualAmount = totalAmount, // 折扣前金额 DiscountAmount = 0, OrderStatus = OrderStatus.Pending, // 待支付 CreatedTime = DateTime.Now, CreatedUserId = entity.CreatedUserId }; await _orderRepository.InsertAsync(order); return entity.OrderNo; } /// /// 订单分页查询 /// [DisplayName("订单分页查询")] [HttpGet("page")] public async Task> Page([FromQuery] OrderQueryInput input) { 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) .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) .WhereIF(input.OrderStatus.HasValue, (o, e, m, r, ro) => o.OrderStatus == input.OrderStatus) .WhereIF(input.PaymentMethod.HasValue, (o, e, m, r, ro) => r.PaymentMethod == input.PaymentMethod) .WhereIF(input.RegistrationMode.HasValue, (o, e, m, r, ro) => r.RegistrationMode == input.RegistrationMode) .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.PaymentTime >= input.StartTime) // 支付时间筛选 .WhereIF(input.EndTime.HasValue, (o, e, m, r, ro) => o.PaymentTime <= input.EndTime) .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 result = await query.Select((o, e, m, r, ro) => new OrderListOutput { Id = o.Id, OrderNo = o.OrderNo, UnitName = SqlFunc.IsNullOrEmpty(m.MerchantName) ? "/" : m.MerchantName, EventName = e.EventName, OrderType = o.OrderType == 1 ? "收入" : "退款", RelatedOrderNo = ro.OrderNo, PaymentMethod = r.PaymentMethod == 2 ? "线上" : "线下", PaymentMethodType = r.PaymentMethodType, PaymentMethodTypeText = r.PaymentMethodType == PaymentMethodType.WeChatPay ? "微信支付" : r.PaymentMethodType == PaymentMethodType.AliPay ? "支付宝支付" : r.PaymentMethodType == PaymentMethodType.BankTransfer ? "银行卡转账" : "未选择", PaymentProofUrl = r.PaymentProofUrl, 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 ? "已完成" : "", CreatedTime = o.CreatedTime, 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, // 退款订单显示原始订单实付金额 IsRefundOrder = o.OrderType == 2, PayeeName = o.PayeeName, PayeeBankName = o.PayeeBankName, PayeeBankAccount = o.PayeeBankAccount }) .ToPagedListAsync(input); return result; } /// /// 获取订单详情 /// [DisplayName("获取订单详情")] [HttpGet("detail")] public async Task Detail([FromQuery] long id) { var query = _orderRepository.AsQueryable() .LeftJoin((o, e) => o.EventId == e.Id) .LeftJoin((o, e, r) => o.RegistrationId == r.Id) .LeftJoin((o, e, r, ro) => o.RelatedOrderId == ro.Id) .Where(o => o.Id == id) .Select((o, e, r, ro) => new { Order = o, EventName = e.EventName, ChargeMode = e.ChargeMode, Registration = r, RelatedOrderNo = ro.OrderNo, RelatedOrderActualAmount = ro.ActualAmount }); var orderInfo = await query.FirstAsync(); if (orderInfo == null || orderInfo.Order == null) throw Oops.Bah("订单不存在"); var registrationId = orderInfo.Order.RegistrationId; var items = await _itemRepository.AsQueryable().Where(x => x.RegistrationId == registrationId).ToListAsync(); var persons = await _personRepository.AsQueryable().Where(x => x.RegistrationId == registrationId).ToListAsync(); // 将项目和人员转换为DTO var itemDtos = items.Select(x => new OrderItemDto { Id = x.Id, ProjectId = x.ProjectId, ProjectName = x.ProjectName, GroupName = x.GroupName, Fee = x.TotalPrice }).ToList(); var personDtos = persons.Select(x => new OrderPersonDto { Name = x.Name, GroupName = x.GroupName, RegistrationItemId = x.RegistrationItemId, ProjectId = x.ProjectId, ProjectName = x.ProjectName }).ToList(); return new OrderDetailOutput { Id = orderInfo.Order.Id, OrderNo = orderInfo.Order.OrderNo, OrderType = orderInfo.Order.OrderType, OrderTypeText = orderInfo.Order.OrderType == 1 ? "收入" : "退款", OrderStatus = orderInfo.Order.OrderStatus, OrderStatusText = orderInfo.Order.OrderStatus == OrderStatus.Pending ? "待支付" : orderInfo.Order.OrderStatus == OrderStatus.Paid ? "已支付" : orderInfo.Order.OrderStatus == OrderStatus.Cancelled ? "已取消" : orderInfo.Order.OrderStatus == OrderStatus.Refunded ? "已退款" : orderInfo.Order.OrderStatus == OrderStatus.Shipped ? "已发货" : orderInfo.Order.OrderStatus == OrderStatus.Completed ? "已完成" : "", EventName = orderInfo.EventName, ChargeMode = orderInfo.ChargeMode, ProjectNames = string.Join(",", items.Select(x => x.ProjectName).Distinct()), GroupNames = string.Join(",", items.Select(x => x.GroupName).Distinct()), Items = itemDtos, Persons = personDtos, PaymentMethod = orderInfo.Registration?.PaymentMethod == 2 ? "线上" : "线下", PaymentMethodType = orderInfo.Registration?.PaymentMethodType ?? PaymentMethodType.None, PaymentMethodTypeText = orderInfo.Registration?.PaymentMethodType == PaymentMethodType.WeChatPay ? "微信支付" : orderInfo.Registration?.PaymentMethodType == PaymentMethodType.AliPay ? "支付宝支付" : orderInfo.Registration?.PaymentMethodType == PaymentMethodType.BankTransfer ? "银行卡转账" : "未选择", PaymentProofUrl = orderInfo.Registration?.PaymentProofUrl, RegistrationMode = orderInfo.Registration?.RegistrationMode == 1 ? "个人" : "团队", OriginalAmount = orderInfo.Order.OriginalAmount, DiscountAmount = orderInfo.Order.DiscountAmount, ActualAmount = orderInfo.Order.ActualAmount, CreatedTime = orderInfo.Order.CreatedTime, RelatedOrderNo = orderInfo.RelatedOrderNo, ContactName = orderInfo.Registration?.ContactName, ContactPhone = orderInfo.Registration?.ContactPhone, RelatedOrderActualAmount = orderInfo.Order.OrderType == 2 ? orderInfo.RelatedOrderActualAmount : null, IsRefundOrder = orderInfo.Order.OrderType == 2 }; } /// /// 批量更新订单支付状态 /// [DisplayName("批量更新订单支付状态")] [HttpPut("payment-status")] [UnitOfWork] public async Task UpdatePaymentStatus(UpdatePaymentStatusInput input) { if (input.Ids == null || !input.Ids.Any()) { throw Oops.Bah("请选择要更新的订单"); } // 验证支付状态值 if (input.PaymentStatus < 0 || input.PaymentStatus > 3) { throw Oops.Bah("无效的支付状态值"); } // 操作前数据一致性检查:确保所有订单都存在且状态一致 var orders = await _orderRepository.AsQueryable() .Where(o => input.Ids.Contains(o.Id)) .ToListAsync(); if (!orders.Any()) { throw Oops.Bah("未找到订单"); } // 检查是否有重复的订单ID if (orders.Count != input.Ids.Distinct().Count()) { throw Oops.Bah("订单ID列表存在重复"); } // 检查所有订单对应的报名记录是否存在 var registrationIds = orders.Select(o => o.RegistrationId).Distinct().ToList(); var registrations = await _registrationRepository.AsQueryable() .Where(r => registrationIds.Contains(r.Id)) .ToListAsync(); if (registrations.Count != registrationIds.Count) { var missingIds = registrationIds.Except(registrations.Select(r => r.Id)).ToList(); _logger.LogError("批量更新支付状态时发现缺失的报名记录: {MissingIds}", string.Join(",", missingIds)); throw Oops.Bah("部分订单关联的报名记录不存在,请联系管理员"); } var currentUserId = _authManager.UserId; var now = DateTime.Now; var updatedCount = 0; foreach (var order in orders) { // 更新订单的 OrderStatus(以 EventRegistration 的支付状态为准) if (input.PaymentStatus == 1) { order.OrderStatus = OrderStatus.Paid; order.PaymentTime = now; } else if (input.PaymentStatus == 3) { order.OrderStatus = OrderStatus.Refunded; order.PaymentTime = now; } else { order.OrderStatus = OrderStatus.Pending; } order.UpdatedTime = now; order.UpdatedUserId = currentUserId; await _orderRepository.UpdateAsync(order); // 同步更新报名记录的支付状态 var reg = await _registrationRepository.GetByIdAsync(order.RegistrationId); if (reg != null) { reg.PaymentStatus = input.PaymentStatus; reg.PaymentTime = order.PaymentTime; reg.UpdatedTime = now; reg.UpdatedUserId = currentUserId; await _registrationRepository.UpdateAsync(reg); } updatedCount++; } // 操作后结果校验 var verifyOrders = await _orderRepository.AsQueryable() .Where(o => input.Ids.Contains(o.Id)) .Select(o => new { o.Id, o.OrderStatus }) .ToListAsync(); var expectedStatus = input.PaymentStatus == 1 ? OrderStatus.Paid : input.PaymentStatus == 3 ? OrderStatus.Refunded : OrderStatus.Pending; var failedOrders = verifyOrders.Where(o => o.OrderStatus != expectedStatus).ToList(); if (failedOrders.Any()) { _logger.LogError("批量更新支付状态后校验失败: {FailedOrderIds}", string.Join(",", failedOrders.Select(o => o.Id))); throw Oops.Bah("部分订单状态更新失败,请重试"); } _logger.LogInformation("批量更新支付状态成功: 更新数量={Count}, 目标状态={Status}, 操作人={UserId}", updatedCount, input.PaymentStatus, currentUserId); } /// /// 获取建议退款金额 /// [DisplayName("获取建议退款金额")] [HttpGet("refund-amount")] public async Task GetRefundAmount([FromQuery] long orderId) { var order = await _orderRepository.GetByIdAsync(orderId); if (order == null) throw Oops.Bah("订单不存在"); var eventInfo = await _eventRepository.GetByIdAsync(order.EventId); if (eventInfo == null) return order.ActualAmount; _logger.LogInformation("调用统一退款金额计算:订单ID={OrderId}, 总金额={TotalAmount}, 赛事开始时间={EventStartTime}", orderId, order.ActualAmount, eventInfo.MatchStartTime); return await _unifiedRegistrationService.CalculateRefundAmountAsync(order.ActualAmount, eventInfo.MatchStartTime); } /// /// 订单退款 /// [DisplayName("订单退款")] [HttpPost("refund")] [UnitOfWork] public async Task Refund(RefundOrderInput input) { var currentUserId = _authManager.UserId; _logger.LogInformation("调用统一后台退款:订单ID={OrderId}, 操作人={UserId}", input.Id, currentUserId); await _unifiedRegistrationService.ExecuteAdminRefundAsync(input, currentUserId); } /// /// 删除订单(软删除) /// [DisplayName("删除订单")] [HttpPost("delete")] public async Task Delete([FromBody] List ids) { if (ids == null || !ids.Any()) { throw Oops.Bah("请选择要删除的订单"); } var currentUserId = _authManager.UserId; var now = DateTime.Now; var orders = await _orderRepository.AsQueryable() .Where(o => ids.Contains(o.Id)) .ToListAsync(); foreach (var order in orders) { order.DeleteMark = true; order.UpdatedTime = now; order.UpdatedUserId = currentUserId; await _orderRepository.UpdateAsync(order); } } /// /// 导出订单 /// [DisplayName("导出订单")] [HttpGet("export")] public async Task Export([FromQuery] OrderQueryInput input) { var list = await _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) .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) .WhereIF(input.OrderStatus.HasValue, (o, e, m, r, ro) => o.OrderStatus == input.OrderStatus) .WhereIF(input.PaymentMethod.HasValue, (o, e, m, r, ro) => r.PaymentMethod == input.PaymentMethod) .WhereIF(input.RegistrationMode.HasValue, (o, e, m, r, ro) => r.RegistrationMode == input.RegistrationMode) .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 ? "已完成" : "", CreatedTime = o.CreatedTime, RelatedOrderActualAmount = o.OrderType == 2 ? ro.ActualAmount : null, IsRefundOrder = o.OrderType == 2, PayeeName = o.PayeeName, PayeeBankName = o.PayeeBankName, PayeeBankAccount = o.PayeeBankAccount }) .ToListAsync(); var bytes = await GenerateOrderExcelAsync(list); return new FileContentResult(bytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") { FileDownloadName = $"订单列表_{DateTime.Now:yyyyMMddHHmmss}.xlsx" }; } /// /// 生成订单Excel文件 /// private async Task GenerateOrderExcelAsync(List orders) { ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial; using var package = new ExcelPackage(); var worksheet = package.Workbook.Worksheets.Add("订单列表"); 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); // 汇总信息行 var summaryRange = worksheet.Cells[rowIndex, 1, rowIndex, 19]; summaryRange.Merge = true; summaryRange.Value = $"汇总信息: 原金额:{totalOriginal}, 优惠金额:{totalDiscount}, 退款金额:{totalRefund}, 实付金额:{totalActual}"; var summaryStyle = summaryRange.Style; summaryStyle.Font.Bold = true; summaryStyle.Font.Size = 12; summaryStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center; summaryStyle.VerticalAlignment = ExcelVerticalAlignment.Center; summaryStyle.Fill.PatternType = ExcelFillStyle.Solid; summaryStyle.Fill.BackgroundColor.SetColor(Color.LightGray); rowIndex++; // 列标题 var headers = new[] { "订单编号", "单位名称", "所属赛事", "订单类型", "关联订单", "支付方式", "报名方式", "报名用户", "报名账号", "原金额(元)", "实付金额(元)", "优惠金额(元)", "退款金额(元)", "订单状态", "生成时间", "收款人姓名", "收款人开户行", "收款人银行卡号" }; for (int i = 0; i < headers.Length; i++) { worksheet.Cells[rowIndex, i + 1].Value = headers[i]; } var headerRange = worksheet.Cells[rowIndex, 1, rowIndex, headers.Length]; var headerStyle = headerRange.Style; headerStyle.Font.Bold = true; headerStyle.Font.Size = 11; headerStyle.HorizontalAlignment = ExcelHorizontalAlignment.Center; headerStyle.VerticalAlignment = ExcelVerticalAlignment.Center; headerStyle.Fill.PatternType = ExcelFillStyle.Solid; headerStyle.Fill.BackgroundColor.SetColor(Color.LightBlue); SetCellBorders(headerRange, ExcelBorderStyle.Thin); rowIndex++; // 数据行 foreach (var item in orders) { // 统一显示为"收款"而不是"收入" var orderTypeText = item.OrderType == "收入" ? "收款" : item.OrderType; var refundAmount = item.OrderType == "退款" ? item.ActualAmount : 0; var actualPayAmount = item.OrderType == "收入" ? item.ActualAmount : 0; worksheet.Cells[rowIndex, 1].Value = item.OrderNo; worksheet.Cells[rowIndex, 2].Value = item.UnitName; worksheet.Cells[rowIndex, 3].Value = item.EventName; worksheet.Cells[rowIndex, 4].Value = orderTypeText; worksheet.Cells[rowIndex, 5].Value = item.RelatedOrderNo; worksheet.Cells[rowIndex, 6].Value = item.PaymentMethod; worksheet.Cells[rowIndex, 7].Value = item.RegistrationMode; worksheet.Cells[rowIndex, 8].Value = item.ContactName; worksheet.Cells[rowIndex, 9].Value = item.ContactPhone; // 金额为0时显示为空白 if (item.OriginalAmount != 0) { worksheet.Cells[rowIndex, 10].Value = item.OriginalAmount; worksheet.Cells[rowIndex, 10].Style.Numberformat.Format = "0.00"; } if (actualPayAmount != 0) { worksheet.Cells[rowIndex, 11].Value = actualPayAmount; worksheet.Cells[rowIndex, 11].Style.Numberformat.Format = "0.00"; } if (item.DiscountAmount != 0) { worksheet.Cells[rowIndex, 12].Value = item.DiscountAmount; worksheet.Cells[rowIndex, 12].Style.Numberformat.Format = "0.00"; } if (refundAmount != 0) { worksheet.Cells[rowIndex, 13].Value = refundAmount; worksheet.Cells[rowIndex, 13].Style.Numberformat.Format = "0.00"; } worksheet.Cells[rowIndex, 14].Value = item.OrderStatusText; worksheet.Cells[rowIndex, 15].Value = item.CreatedTime.ToString("yyyy-MM-dd HH:mm:ss"); worksheet.Cells[rowIndex, 16].Value = item.PayeeName; worksheet.Cells[rowIndex, 17].Value = item.PayeeBankName; worksheet.Cells[rowIndex, 18].Value = item.PayeeBankAccount; SetDataRowStyle(worksheet, rowIndex, 18); rowIndex++; } // 设置列宽 var columnWidths = new double[] { 18, 15, 15, 10, 12, 10, 10, 12, 14, 12, 14, 14, 14, 10, 18, 15, 20, 20 }; for (int i = 0; i < columnWidths.Length; i++) { worksheet.Column(i + 1).Width = columnWidths[i]; } // 冻结表头 worksheet.View.FreezePanes(3, 1); return await package.GetAsByteArrayAsync(); } /// /// 设置单元格边框 /// private void SetCellBorders(ExcelRange range, ExcelBorderStyle borderStyle) { range.Style.Border.Top.Style = borderStyle; range.Style.Border.Bottom.Style = borderStyle; range.Style.Border.Left.Style = borderStyle; range.Style.Border.Right.Style = borderStyle; } /// /// 设置数据行样式 /// private void SetDataRowStyle(ExcelWorksheet worksheet, int rowIndex, int colCount) { var range = worksheet.Cells[rowIndex, 1, rowIndex, colCount]; var style = range.Style; style.HorizontalAlignment = ExcelHorizontalAlignment.Center; style.VerticalAlignment = ExcelVerticalAlignment.Center; SetCellBorders(range, ExcelBorderStyle.Thin); } }