diff --git a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/DistributionController.cs b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/DistributionController.cs index 4c5b35a..74afd00 100644 --- a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/DistributionController.cs +++ b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/DistributionController.cs @@ -3,6 +3,7 @@ using MiAssessment.Admin.Business.Models; using MiAssessment.Admin.Business.Models.Common; using MiAssessment.Admin.Business.Models.Distribution; using MiAssessment.Admin.Business.Services.Interfaces; +using ClosedXML.Excel; using Microsoft.AspNetCore.Mvc; namespace MiAssessment.Admin.Business.Controllers; @@ -91,11 +92,42 @@ public class DistributionController : BusinessControllerBase { var items = await _distributionService.ExportInviteCodesAsync(request); - // 生成CSV内容 - var csvContent = GenerateInviteCodeCsv(items); - var fileName = $"invite_codes_{DateTime.Now:yyyyMMddHHmmss}.csv"; + using var workbook = new XLWorkbook(); + var worksheet = workbook.Worksheets.Add("邀请码列表"); - return File(System.Text.Encoding.UTF8.GetBytes(csvContent), "text/csv", fileName); + var headers = new[] { "ID", "邀请码", "批次号", "分配用户", "分配时间", "使用用户", "使用订单ID", "使用时间", "状态", "创建时间" }; + for (var i = 0; i < headers.Length; i++) + worksheet.Cell(1, i + 1).Value = headers[i]; + + var headerRow = worksheet.Range(1, 1, 1, headers.Length); + headerRow.Style.Font.Bold = true; + headerRow.Style.Fill.BackgroundColor = XLColor.FromHtml("#4A90E2"); + headerRow.Style.Font.FontColor = XLColor.White; + + for (var i = 0; i < items.Count; i++) + { + var row = i + 2; + var item = items[i]; + worksheet.Cell(row, 1).Value = item.Id; + worksheet.Cell(row, 2).Value = item.Code; + worksheet.Cell(row, 3).Value = item.BatchNo ?? ""; + worksheet.Cell(row, 4).Value = item.AssignUserNickname ?? ""; + worksheet.Cell(row, 5).Value = item.AssignTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; + worksheet.Cell(row, 6).Value = item.UseUserNickname ?? ""; + worksheet.Cell(row, 7).Value = item.UseOrderId?.ToString() ?? ""; + worksheet.Cell(row, 8).Value = item.UseTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; + worksheet.Cell(row, 9).Value = item.StatusName; + worksheet.Cell(row, 10).Value = item.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } + + worksheet.Columns().AdjustToContents(); + + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + + return File(stream.ToArray(), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + $"邀请码列表_{DateTime.Now:yyyyMMddHHmmss}.xlsx"); } #endregion @@ -162,11 +194,43 @@ public class DistributionController : BusinessControllerBase { var items = await _distributionService.ExportCommissionsAsync(request); - // 生成CSV内容 - var csvContent = GenerateCommissionCsv(items); - var fileName = $"commissions_{DateTime.Now:yyyyMMddHHmmss}.csv"; + using var workbook = new XLWorkbook(); + var worksheet = workbook.Worksheets.Add("佣金记录"); - return File(System.Text.Encoding.UTF8.GetBytes(csvContent), "text/csv", fileName); + var headers = new[] { "ID", "获佣用户", "来源用户", "订单编号", "订单金额", "佣金比例", "佣金金额", "层级", "状态", "结算时间", "创建时间" }; + for (var i = 0; i < headers.Length; i++) + worksheet.Cell(1, i + 1).Value = headers[i]; + + var headerRow = worksheet.Range(1, 1, 1, headers.Length); + headerRow.Style.Font.Bold = true; + headerRow.Style.Fill.BackgroundColor = XLColor.FromHtml("#4A90E2"); + headerRow.Style.Font.FontColor = XLColor.White; + + for (var i = 0; i < items.Count; i++) + { + var row = i + 2; + var item = items[i]; + worksheet.Cell(row, 1).Value = item.Id; + worksheet.Cell(row, 2).Value = item.UserNickname ?? ""; + worksheet.Cell(row, 3).Value = item.FromUserNickname ?? ""; + worksheet.Cell(row, 4).Value = item.OrderNo ?? ""; + worksheet.Cell(row, 5).Value = item.OrderAmount; + worksheet.Cell(row, 6).Value = item.CommissionRate; + worksheet.Cell(row, 7).Value = item.CommissionAmount; + worksheet.Cell(row, 8).Value = item.LevelName; + worksheet.Cell(row, 9).Value = item.StatusName; + worksheet.Cell(row, 10).Value = item.SettleTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; + worksheet.Cell(row, 11).Value = item.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } + + worksheet.Columns().AdjustToContents(); + + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + + return File(stream.ToArray(), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + $"佣金记录_{DateTime.Now:yyyyMMddHHmmss}.xlsx"); } #endregion @@ -292,79 +356,47 @@ public class DistributionController : BusinessControllerBase { var items = await _distributionService.ExportWithdrawalsAsync(request); - // 生成CSV内容 - var csvContent = GenerateWithdrawalCsv(items); - var fileName = $"withdrawals_{DateTime.Now:yyyyMMddHHmmss}.csv"; + using var workbook = new XLWorkbook(); + var worksheet = workbook.Worksheets.Add("提现记录"); - return File(System.Text.Encoding.UTF8.GetBytes(csvContent), "text/csv", fileName); + var headers = new[] { "提现单号", "用户昵称", "手机号", "提现金额", "提现前余额", "提现后余额", "状态", "审核时间", "审核备注", "打款时间", "打款交易号", "创建时间" }; + for (var i = 0; i < headers.Length; i++) + worksheet.Cell(1, i + 1).Value = headers[i]; + + var headerRow = worksheet.Range(1, 1, 1, headers.Length); + headerRow.Style.Font.Bold = true; + headerRow.Style.Fill.BackgroundColor = XLColor.FromHtml("#4A90E2"); + headerRow.Style.Font.FontColor = XLColor.White; + + for (var i = 0; i < items.Count; i++) + { + var row = i + 2; + var item = items[i]; + worksheet.Cell(row, 1).Value = item.WithdrawalNo; + worksheet.Cell(row, 2).Value = item.UserNickname ?? ""; + worksheet.Cell(row, 3).Value = item.UserPhone ?? ""; + worksheet.Cell(row, 4).Value = item.Amount; + worksheet.Cell(row, 5).Value = item.BeforeBalance; + worksheet.Cell(row, 6).Value = item.AfterBalance; + worksheet.Cell(row, 7).Value = item.StatusName; + worksheet.Cell(row, 8).Value = item.AuditTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; + worksheet.Cell(row, 9).Value = item.AuditRemark ?? ""; + worksheet.Cell(row, 10).Value = item.PayTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; + worksheet.Cell(row, 11).Value = item.PayTransactionId ?? ""; + worksheet.Cell(row, 12).Value = item.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } + + worksheet.Columns().AdjustToContents(); + + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + + return File(stream.ToArray(), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + $"提现记录_{DateTime.Now:yyyyMMddHHmmss}.xlsx"); } #endregion - #region 私有方法 - - /// - /// 生成邀请码CSV内容 - /// - /// 邀请码列表 - /// CSV内容 - private static string GenerateInviteCodeCsv(List items) - { - var sb = new System.Text.StringBuilder(); - - // CSV 头部 - sb.AppendLine("ID,邀请码,批次号,分配用户,分配时间,使用用户,使用订单ID,使用时间,状态,创建时间"); - - // CSV 数据行 - foreach (var item in items) - { - sb.AppendLine($"{item.Id},{item.Code},{item.BatchNo ?? ""},{item.AssignUserNickname ?? ""},{item.AssignTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""},{item.UseUserNickname ?? ""},{item.UseOrderId?.ToString() ?? ""},{item.UseTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""},{item.StatusName},{item.CreateTime:yyyy-MM-dd HH:mm:ss}"); - } - - return sb.ToString(); - } - - /// - /// 生成佣金记录CSV内容 - /// - /// 佣金记录列表 - /// CSV内容 - private static string GenerateCommissionCsv(List items) - { - var sb = new System.Text.StringBuilder(); - - // CSV 头部 - sb.AppendLine("ID,获得佣金用户ID,获得佣金用户,来源用户ID,来源用户,订单ID,订单编号,订单金额,佣金比例,佣金金额,层级,状态,结算时间,创建时间"); - - // CSV 数据行 - foreach (var item in items) - { - sb.AppendLine($"{item.Id},{item.UserId},{item.UserNickname ?? ""},{item.FromUserId},{item.FromUserNickname ?? ""},{item.OrderId},{item.OrderNo ?? ""},{item.OrderAmount},{item.CommissionRate},{item.CommissionAmount},{item.LevelName},{item.StatusName},{item.SettleTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""},{item.CreateTime:yyyy-MM-dd HH:mm:ss}"); - } - - return sb.ToString(); - } - - /// - /// 生成提现记录CSV内容 - /// - /// 提现记录列表 - /// CSV内容 - private static string GenerateWithdrawalCsv(List items) - { - var sb = new System.Text.StringBuilder(); - - // CSV 头部 - sb.AppendLine("ID,提现单号,用户ID,用户昵称,用户手机号,提现金额,提现前余额,提现后余额,状态,审核人ID,审核时间,审核备注,打款时间,打款交易号,创建时间"); - - // CSV 数据行 - foreach (var item in items) - { - sb.AppendLine($"{item.Id},{item.WithdrawalNo},{item.UserId},{item.UserNickname ?? ""},{item.UserPhone ?? ""},{item.Amount},{item.BeforeBalance},{item.AfterBalance},{item.StatusName},{item.AuditUserId?.ToString() ?? ""},{item.AuditTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""},{item.AuditRemark ?? ""},{item.PayTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""},{item.PayTransactionId ?? ""},{item.CreateTime:yyyy-MM-dd HH:mm:ss}"); - } - - return sb.ToString(); - } - #endregion } diff --git a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/OrderController.cs b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/OrderController.cs index e8c0b5d..b06866e 100644 --- a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/OrderController.cs +++ b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/OrderController.cs @@ -3,6 +3,7 @@ using MiAssessment.Admin.Business.Models; using MiAssessment.Admin.Business.Models.Common; using MiAssessment.Admin.Business.Models.Order; using MiAssessment.Admin.Business.Services.Interfaces; +using ClosedXML.Excel; using Microsoft.AspNetCore.Mvc; namespace MiAssessment.Admin.Business.Controllers; @@ -105,7 +106,7 @@ public class OrderController : BusinessControllerBase /// 导出订单列表 /// /// 查询请求 - /// 导出数据 + /// Excel文件 [HttpGet("export")] [BusinessPermission("order:view")] public async Task Export([FromQuery] OrderQueryRequest request) @@ -113,7 +114,45 @@ public class OrderController : BusinessControllerBase try { var result = await _orderService.ExportOrdersAsync(request); - return Ok(result); + + using var workbook = new XLWorkbook(); + var worksheet = workbook.Worksheets.Add("订单列表"); + + var headers = new[] { "订单编号", "用户UID", "用户昵称", "手机号", "订单类型", "商品名称", "订单金额", "实付金额", "支付方式", "状态", "支付时间", "创建时间" }; + for (var i = 0; i < headers.Length; i++) + worksheet.Cell(1, i + 1).Value = headers[i]; + + var headerRow = worksheet.Range(1, 1, 1, headers.Length); + headerRow.Style.Font.Bold = true; + headerRow.Style.Fill.BackgroundColor = XLColor.FromHtml("#4A90E2"); + headerRow.Style.Font.FontColor = XLColor.White; + + for (var i = 0; i < result.Count; i++) + { + var row = i + 2; + var o = result[i]; + worksheet.Cell(row, 1).Value = o.OrderNo; + worksheet.Cell(row, 2).Value = o.UserUid; + worksheet.Cell(row, 3).Value = o.UserNickname; + worksheet.Cell(row, 4).Value = o.UserPhone; + worksheet.Cell(row, 5).Value = o.OrderTypeName; + worksheet.Cell(row, 6).Value = o.ProductName; + worksheet.Cell(row, 7).Value = o.Amount; + worksheet.Cell(row, 8).Value = o.PayAmount; + worksheet.Cell(row, 9).Value = o.PayTypeName; + worksheet.Cell(row, 10).Value = o.StatusName; + worksheet.Cell(row, 11).Value = o.PayTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; + worksheet.Cell(row, 12).Value = o.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } + + worksheet.Columns().AdjustToContents(); + + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + + return File(stream.ToArray(), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + $"订单列表_{DateTime.Now:yyyyMMddHHmmss}.xlsx"); } catch (BusinessException ex) { diff --git a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/PlannerController.cs b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/PlannerController.cs index 8035915..4198339 100644 --- a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/PlannerController.cs +++ b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/PlannerController.cs @@ -3,6 +3,7 @@ using MiAssessment.Admin.Business.Models; using MiAssessment.Admin.Business.Models.Common; using MiAssessment.Admin.Business.Models.Planner; using MiAssessment.Admin.Business.Services.Interfaces; +using ClosedXML.Excel; using Microsoft.AspNetCore.Mvc; namespace MiAssessment.Admin.Business.Controllers; @@ -259,7 +260,7 @@ public class PlannerController : BusinessControllerBase /// 导出预约记录列表 /// /// 查询请求 - /// 导出数据 + /// Excel文件 [HttpGet("booking/export")] [BusinessPermission("planner:view")] public async Task ExportBookings([FromQuery] BookingQueryRequest request) @@ -267,7 +268,46 @@ public class PlannerController : BusinessControllerBase try { var result = await _plannerService.ExportBookingsAsync(request); - return Ok(result); + + using var workbook = new XLWorkbook(); + var worksheet = workbook.Worksheets.Add("预约记录"); + + var headers = new[] { "用户UID", "用户昵称", "手机号", "订单编号", "规划师", "预约日期", "预约时间", "学生姓名", "联系电话", "性别", "年级", "状态", "创建时间" }; + for (var i = 0; i < headers.Length; i++) + worksheet.Cell(1, i + 1).Value = headers[i]; + + var headerRow = worksheet.Range(1, 1, 1, headers.Length); + headerRow.Style.Font.Bold = true; + headerRow.Style.Fill.BackgroundColor = XLColor.FromHtml("#4A90E2"); + headerRow.Style.Font.FontColor = XLColor.White; + + for (var i = 0; i < result.Count; i++) + { + var row = i + 2; + var item = result[i]; + worksheet.Cell(row, 1).Value = item.UserUid ?? ""; + worksheet.Cell(row, 2).Value = item.UserNickname ?? ""; + worksheet.Cell(row, 3).Value = item.UserPhone ?? ""; + worksheet.Cell(row, 4).Value = item.OrderNo ?? ""; + worksheet.Cell(row, 5).Value = item.PlannerName ?? ""; + worksheet.Cell(row, 6).Value = item.BookingDate.ToString("yyyy-MM-dd"); + worksheet.Cell(row, 7).Value = item.BookingTime; + worksheet.Cell(row, 8).Value = item.Name; + worksheet.Cell(row, 9).Value = item.Phone; + worksheet.Cell(row, 10).Value = item.GenderName; + worksheet.Cell(row, 11).Value = item.GradeName; + worksheet.Cell(row, 12).Value = item.StatusName; + worksheet.Cell(row, 13).Value = item.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"); + } + + worksheet.Columns().AdjustToContents(); + + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + + return File(stream.ToArray(), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + $"预约记录_{DateTime.Now:yyyyMMddHHmmss}.xlsx"); } catch (BusinessException ex) { diff --git a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/UserController.cs b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/UserController.cs index 8a6aa90..b09c8c7 100644 --- a/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/UserController.cs +++ b/server/MiAssessment/src/MiAssessment.Admin.Business/Controllers/UserController.cs @@ -3,6 +3,7 @@ using MiAssessment.Admin.Business.Models; using MiAssessment.Admin.Business.Models.Common; using MiAssessment.Admin.Business.Models.User; using MiAssessment.Admin.Business.Services.Interfaces; +using ClosedXML.Excel; using Microsoft.AspNetCore.Mvc; namespace MiAssessment.Admin.Business.Controllers; @@ -191,7 +192,7 @@ public class UserController : BusinessControllerBase /// 导出用户列表 /// /// 查询请求 - /// 导出数据 + /// Excel文件 [HttpGet("export")] [BusinessPermission("user:view")] public async Task Export([FromQuery] UserQueryRequest request) @@ -199,7 +200,51 @@ public class UserController : BusinessControllerBase try { var result = await _userService.ExportUsersAsync(request); - return Ok(result); + + // 生成 Excel 文件 + using var workbook = new XLWorkbook(); + var worksheet = workbook.Worksheets.Add("用户列表"); + + // 表头 + var headers = new[] { "UID", "手机号", "昵称", "用户等级", "余额", "累计收入", "状态", "创建时间", "最后登录" }; + for (var i = 0; i < headers.Length; i++) + { + worksheet.Cell(1, i + 1).Value = headers[i]; + } + + // 表头样式 + var headerRow = worksheet.Range(1, 1, 1, headers.Length); + headerRow.Style.Font.Bold = true; + headerRow.Style.Fill.BackgroundColor = XLColor.FromHtml("#4A90E2"); + headerRow.Style.Font.FontColor = XLColor.White; + + // 数据行 + for (var i = 0; i < result.Count; i++) + { + var row = i + 2; + var user = result[i]; + worksheet.Cell(row, 1).Value = user.Uid; + worksheet.Cell(row, 2).Value = user.Phone; + worksheet.Cell(row, 3).Value = user.Nickname; + worksheet.Cell(row, 4).Value = user.UserLevelName; + worksheet.Cell(row, 5).Value = user.Balance; + worksheet.Cell(row, 6).Value = user.TotalIncome; + worksheet.Cell(row, 7).Value = user.StatusName; + worksheet.Cell(row, 8).Value = user.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"); + worksheet.Cell(row, 9).Value = user.LastLoginTime?.ToString("yyyy-MM-dd HH:mm:ss") ?? ""; + } + + // 自动列宽 + worksheet.Columns().AdjustToContents(); + + using var stream = new MemoryStream(); + workbook.SaveAs(stream); + stream.Position = 0; + + var fileName = $"用户列表_{DateTime.Now:yyyyMMddHHmmss}.xlsx"; + return File(stream.ToArray(), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + fileName); } catch (BusinessException ex) { diff --git a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/utils/request.ts b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/utils/request.ts index c4e1552..70fba6b 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/utils/request.ts +++ b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/utils/request.ts @@ -191,6 +191,11 @@ service.interceptors.request.use( // 响应拦截器 service.interceptors.response.use( (response: AxiosResponse) => { + // blob 类型直接返回,不走业务 code 判断 + if (response.config.responseType === 'blob') { + return { code: 0, message: 'success', data: response.data } as any + } + const res = response.data // code 为 0 表示成功 diff --git a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/dashboard/index.vue b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/dashboard/index.vue index afb0361..06c1a09 100644 --- a/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/dashboard/index.vue +++ b/server/MiAssessment/src/MiAssessment.Admin/admin-web/src/views/dashboard/index.vue @@ -185,7 +185,7 @@
- + 用户管理 - + 订单管理 - + 规划师管理 - + 提现审核 - + 轮播图管理 - + 测评管理