- POST /v1/in/stats/history/export 엔드포인트 추가 - history/list와 동일 필터(keyword/status/date) 기준 엑셀 내보내기 - PushSendLogRepository에서 GroupBy 쿼리를 private helper로 리팩토링 - ClosedXML로 엑셀 생성 (메시지코드/제목/서비스명/발송일시/대상수/성공/실패/오픈율/상태) Closes #191
138 lines
7.7 KiB
C#
138 lines
7.7 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Swashbuckle.AspNetCore.Annotations;
|
|
using SPMS.Application.DTOs.Stats;
|
|
using SPMS.Application.Interfaces;
|
|
using SPMS.Domain.Common;
|
|
|
|
namespace SPMS.API.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("v1/in/stats")]
|
|
[ApiExplorerSettings(GroupName = "stats")]
|
|
public class StatsController : ControllerBase
|
|
{
|
|
private readonly IStatsService _statsService;
|
|
|
|
public StatsController(IStatsService statsService)
|
|
{
|
|
_statsService = statsService;
|
|
}
|
|
|
|
[HttpPost("daily")]
|
|
[SwaggerOperation(Summary = "일별 통계 조회", Description = "기간별 일별 발송/성공/실패/열람 통계를 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetDailyAsync([FromBody] DailyStatRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetDailyAsync(serviceId, request);
|
|
return Ok(ApiResponse<DailyStatResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("summary")]
|
|
[SwaggerOperation(Summary = "요약 통계 조회", Description = "대시보드 요약 통계를 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetSummaryAsync()
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetSummaryAsync(serviceId);
|
|
return Ok(ApiResponse<SummaryStatResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("message")]
|
|
[SwaggerOperation(Summary = "메시지별 통계 조회", Description = "특정 메시지의 발송 통계를 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetMessageStatAsync([FromBody] MessageStatRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetMessageStatAsync(serviceId, request);
|
|
return Ok(ApiResponse<MessageStatResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("hourly")]
|
|
[SwaggerOperation(Summary = "시간대별 통계 조회", Description = "시간대별 발송 추이를 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetHourlyAsync([FromBody] HourlyStatRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetHourlyAsync(serviceId, request);
|
|
return Ok(ApiResponse<HourlyStatResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("device")]
|
|
[SwaggerOperation(Summary = "디바이스 통계 조회", Description = "플랫폼/모델별 디바이스 분포를 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetDeviceStatAsync()
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetDeviceStatAsync(serviceId);
|
|
return Ok(ApiResponse<DeviceStatResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("export")]
|
|
[SwaggerOperation(Summary = "통계 리포트 다운로드", Description = "일별/시간대별/플랫폼별 통계를 엑셀(.xlsx) 파일로 다운로드합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> ExportReportAsync([FromBody] StatsExportRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var fileBytes = await _statsService.ExportReportAsync(serviceId, request);
|
|
var fileName = $"stats_report_{request.StartDate}_{request.EndDate}.xlsx";
|
|
return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
|
|
}
|
|
|
|
[HttpPost("failure")]
|
|
[SwaggerOperation(Summary = "실패원인 통계 조회", Description = "실패 원인별 집계를 상위 N개로 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetFailureStatAsync([FromBody] FailureStatRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetFailureStatAsync(serviceId, request);
|
|
return Ok(ApiResponse<FailureStatResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("dashboard")]
|
|
[SwaggerOperation(Summary = "대시보드 통합 조회", Description = "KPI, 일별 추이, 시간대별 분포, 플랫폼 비율, 상위 메시지를 한번에 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetDashboardAsync([FromBody] DashboardRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetDashboardAsync(serviceId, request);
|
|
return Ok(ApiResponse<DashboardResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("history/list")]
|
|
[SwaggerOperation(Summary = "이력 목록 조회", Description = "메시지별 발송 이력 목록을 조회합니다. keyword/status/date 필터를 지원합니다. X-Service-Code 헤더 미지정 시 전체 서비스 이력을 조회합니다.")]
|
|
public async Task<IActionResult> GetHistoryListAsync([FromBody] HistoryListRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetHistoryListAsync(serviceId, request);
|
|
return Ok(ApiResponse<HistoryListResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("history/detail")]
|
|
[SwaggerOperation(Summary = "이력 상세 조회", Description = "특정 메시지의 발송 이력 상세(기본정보+집계+실패사유+본문)를 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스에서 검색합니다.")]
|
|
public async Task<IActionResult> GetHistoryDetailAsync([FromBody] HistoryDetailRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetHistoryDetailAsync(serviceId, request);
|
|
return Ok(ApiResponse<HistoryDetailResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
[HttpPost("history/export")]
|
|
[SwaggerOperation(Summary = "이력 엑셀 내보내기", Description = "이력 목록과 동일한 필터 기준으로 발송 이력을 엑셀(.xlsx)로 내보냅니다. X-Service-Code 헤더 미지정 시 전체 서비스 이력을 내보냅니다.")]
|
|
public async Task<IActionResult> ExportHistoryAsync([FromBody] HistoryExportRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var fileBytes = await _statsService.ExportHistoryAsync(serviceId, request);
|
|
var fileName = $"history_export_{DateTime.UtcNow:yyyyMMdd}.xlsx";
|
|
return File(fileBytes, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
|
|
}
|
|
|
|
[HttpPost("send-log")]
|
|
[SwaggerOperation(Summary = "발송 상세 로그 조회", Description = "특정 메시지의 개별 디바이스별 발송 상세 로그를 조회합니다. X-Service-Code 헤더 미지정 시 전체 서비스 통계를 조회합니다.")]
|
|
public async Task<IActionResult> GetSendLogDetailAsync([FromBody] SendLogDetailRequestDto request)
|
|
{
|
|
var serviceId = GetOptionalServiceId();
|
|
var result = await _statsService.GetSendLogDetailAsync(serviceId, request);
|
|
return Ok(ApiResponse<SendLogDetailResponseDto>.Success(result, "조회 성공"));
|
|
}
|
|
|
|
private long? GetOptionalServiceId()
|
|
{
|
|
if (HttpContext.Items.TryGetValue("ServiceId", out var obj) && obj is long id)
|
|
return id;
|
|
return null;
|
|
}
|
|
}
|