LabelReportDateRangeHelper.cs 3.17 KB
using Volo.Abp;

namespace FoodLabeling.Application.Helpers;

/// <summary>
/// Label Report 统计区间解析(App 7d / 30d / 90d / 自定义)。
/// </summary>
public static class LabelReportDateRangeHelper
{
    /// <summary>趋势按日汇总允许的最大天数</summary>
    public const int MaxRangeDays = 366;

    /// <summary>
    /// 解析查询区间。结束日包含当天(闭区间),内部以次日 0 点为区间上界(不含)。
    /// </summary>
    public static LabelReportResolvedRange Resolve(string? period, DateTime? startDate, DateTime? endDate)
    {
        var normalized = NormalizePeriod(period);
        var endDay = (endDate ?? DateTime.Today).Date;
        var endExcl = endDay.AddDays(1);
        DateTime startDay;

        switch (normalized)
        {
            case "7d":
                startDay = endDay.AddDays(-6);
                break;
            case "30d":
                startDay = endDay.AddDays(-29);
                break;
            case "90d":
                startDay = endDay.AddDays(-89);
                break;
            case "custom":
                if (!startDate.HasValue || !endDate.HasValue)
                {
                    throw new UserFriendlyException("自定义日期须同时传入 startDate 与 endDate");
                }

                startDay = startDate.Value.Date;
                endDay = endDate.Value.Date;
                endExcl = endDay.AddDays(1);
                if (startDay > endDay)
                {
                    throw new UserFriendlyException("开始日期不能晚于结束日期");
                }

                break;
            default:
                startDay = (startDate ?? endDay.AddDays(-6)).Date;
                normalized = startDate.HasValue || endDate.HasValue ? "custom" : "7d";
                break;
        }

        if (startDay >= endExcl)
        {
            startDay = endExcl.AddDays(-1);
        }

        var dayCount = Math.Max(1, (int)Math.Ceiling((endExcl - startDay).TotalDays));
        if (dayCount > MaxRangeDays)
        {
            throw new UserFriendlyException($"统计区间不能超过 {MaxRangeDays} 天");
        }

        return new LabelReportResolvedRange
        {
            Period = normalized,
            RangeStart = startDay,
            RangeEndExcl = endExcl,
            RangeEndInclusive = endDay,
            DayCount = dayCount
        };
    }

    private static string NormalizePeriod(string? period)
    {
        var p = (period ?? "7d").Trim().ToLowerInvariant();
        return p switch
        {
            "7" or "7d" or "last7days" or "last_7_days" => "7d",
            "30" or "30d" or "last30days" or "last_30_days" => "30d",
            "90" or "90d" or "last90days" or "last_90_days" => "90d",
            "custom" => "custom",
            _ => p
        };
    }
}

/// <summary>
/// Label Report 已解析的日期区间。
/// </summary>
public sealed class LabelReportResolvedRange
{
    public string Period { get; init; } = "7d";

    public DateTime RangeStart { get; init; }

    public DateTime RangeEndExcl { get; init; }

    public DateTime RangeEndInclusive { get; init; }

    public int DayCount { get; init; }
}