Orchard商城模块(Commerce)报表部分
展示销售报表相关
图表控件使用 http://www.chartjs.org/
报表需继承此接口
public interface ICommerceReport : IDependency { string Name { get; } string Description { get; } string DescriptionColumnHeader { get; } string ValueColumnHeader { get; } string ValueFormat { get; } ChartType ChartType { get; } ReportData GetData( DateTime startDate, DateTime endDate, TimePeriod granularity); }
具体实现(报表一)
namespace Aivics.Commerce.Reports { /// <summary> /// 报表数据基类 /// </summary> public abstract class BaseSalesReport : ICommerceReport { private readonly IContentManager _contentManager; protected BaseSalesReport(IContentManager contentManager) { _contentManager = contentManager; T = NullLocalizer.Instance; } public Localizer T { get; set; } public abstract string Name { get; } public abstract string Description { get; } public abstract string DescriptionColumnHeader { get; } public abstract string ValueColumnHeader { get; } public abstract string ValueFormat { get; } public abstract ChartType ChartType { get; } public abstract double ComputeResultForInterval(IList<OrderPart> ordersForInterval); public ReportData GetData(DateTime startDate, DateTime endDate, TimePeriod granularity) { startDate = granularity.BeginningDate(startDate); endDate = granularity.EndingDate(endDate); var orders = _contentManager .Query<CommonPart, CommonPartRecord>("Order") .Where(r => r.CreatedUtc >= startDate.ToUniversalTime() && r.CreatedUtc <= endDate.ToUniversalTime()) .OrderBy(r => r.CreatedUtc) .Join<OrderPartRecord>() .Where(order => order.Status != OrderPart.Cancelled) .List() .ToList(); var numberOfPoints = granularity.PeriodCount(startDate, endDate); var results = new List<ReportDataPoint>(numberOfPoints); var intervalStart = startDate; var intervalEnd = startDate + granularity; while (intervalStart < endDate) { var ordersForInterval = orders.Where( common => common.CreatedUtc >= intervalStart && common.CreatedUtc < intervalEnd) .Select(common => common.As<OrderPart>()) .ToList(); results.Add(new ReportDataPoint { Description = granularity.ToString(intervalStart, CultureInfo.CurrentUICulture), Value = ComputeResultForInterval(ordersForInterval) }); intervalStart = intervalEnd; intervalEnd = intervalStart + granularity; } return new ReportData { DataPoints = results }; } } }
报表可根据业务需要扩展。以上为目前报表(重写GetData)
通过以下类控制筛选维度、可筛选一年,一周,一月的数据, 可复用的类
public struct TimePeriod { private readonly int _value; private TimePeriod(int value) { _value = value; } public static TimePeriod Hour = new TimePeriod(0); public static TimePeriod Day = new TimePeriod(1); public static TimePeriod Week = new TimePeriod(2); public static TimePeriod Month = new TimePeriod(3); public static TimePeriod Trimester = new TimePeriod(4); public static TimePeriod Year = new TimePeriod(5); public DateTime BeginningDate(DateTime date, CultureInfo cultureInfo = null) { switch (_value) { case 0: // hour return date.Date.AddHours(date.Hour); case 1: // day return date.Date; case 2: // week var firstDayOfWeek = cultureInfo != null ? cultureInfo.DateTimeFormat.FirstDayOfWeek : DateTimeFormatInfo.CurrentInfo == null ? DayOfWeek.Sunday : DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek; var distanceToMonday = date.DayOfWeek - firstDayOfWeek; if (distanceToMonday < 0) { distanceToMonday += 7; } return date.Date.AddDays(-distanceToMonday); case 3: // month return date.Date.AddDays(1-date.Day); case 4: // trimester var distanceToTrimesterStartMonth = (date.Month - 1)%3; return date.Date.AddMonths(-distanceToTrimesterStartMonth).AddDays(1-date.Day); case 5: //year return date.Date.AddDays(1-date.DayOfYear); } throw new InvalidOperationException("Unknown time period"); } public DateTime EndingDate(DateTime date, CultureInfo cultureInfo = null) { return BeginningDate(date, cultureInfo) + this; } public int PeriodCount(DateTime startDate, DateTime endDate, CultureInfo cultureInfo = null) { startDate = BeginningDate(startDate, cultureInfo); endDate = EndingDate(endDate, cultureInfo); switch (_value) { case 0: // hour return (int) ((endDate.Ticks - startDate.Ticks)/TimeSpan.TicksPerHour); case 1: // day return (int) ((endDate.Ticks - startDate.Ticks)/TimeSpan.TicksPerDay); case 2: // week return (int) ((endDate.Ticks - startDate.Ticks)/TimeSpan.TicksPerDay/7); case 3: // month return (endDate.Year*12 + endDate.Month) - (startDate.Year*12 + startDate.Month); case 4: // trimester return ((endDate.Year*12 + endDate.Month) - (startDate.Year*12 + startDate.Month))/3; case 5: // year return endDate.Year - startDate.Year; } throw new InvalidOperationException("Unknown time period"); } public static TimePeriod Parse(string value) { switch (value.ToLowerInvariant()) { case "hour": return Hour; case "day": return Day; case "week": return Week; case "month": return Month; case "trimester": return Trimester; case "year": return Year; } throw new InvalidOperationException("Unknown time period"); } public static DateTime operator +(DateTime date, TimePeriod period) { switch (period._value) { case 0: // hour return date.AddHours(1); case 1: // day return date.AddDays(1); case 2: // week return date.AddDays(7); case 3: // month return date.AddMonths(1); case 4: // trimester return date.AddMonths(3); case 5: // year return date.AddYears(1); } throw new InvalidOperationException("Unknown time period"); } public static DateTime operator -(DateTime date, TimePeriod period) { switch (period._value) { case 0: // hour return date.AddHours(-1); case 1: // day return date.AddDays(-1); case 2: // week return date.AddDays(-7); case 3: //month return date.AddMonths(-1); case 4: // trimester return date.AddMonths(-3); case 5: // year return date.AddYears(-1); } throw new InvalidOperationException("Unknown time period"); } public static bool operator ==(TimePeriod a, TimePeriod b) { return a._value == b._value; } public static bool operator !=(TimePeriod a, TimePeriod b) { return a._value != b._value; } public override bool Equals(object obj) { if (!(obj is TimePeriod)) return false; return ((TimePeriod) obj)._value == _value; } public override int GetHashCode() { return _value.GetHashCode(); } public override string ToString() { switch (_value) { case 0: return "Hour"; case 1: return "Day"; case 2: return "Week"; case 3: return "Month"; case 4: return "Trimester"; case 5: return "Year"; } throw new InvalidOperationException("Unknown time period"); } public string ToString(DateTime date, CultureInfo culture = null) { if (culture == null) { culture = CultureInfo.CurrentUICulture; } switch (_value) { case 0: // hour return BeginningDate(date, culture) .ToString(date.Hour == 0 ? "g" : "t", culture); case 1: // day return date.ToString("d", culture); case 2: // week var startDate = BeginningDate(date, culture); var endDate = startDate.AddDays(6); return String.Format( culture, startDate.Year == endDate.Year ? startDate.Month == endDate.Month ? "{0:%d} - {1:%d}" : "{0:m} - {1:m}" : "{0:d} - {1:d}" , startDate, endDate); case 3: //month return date.ToString(date.Month == 1 ? "y" : "MMMM", culture); case 4: // trimester var trimester = (date.Month - 1)/3 + 1; return String.Format( culture, trimester == 1 ? "{0:yyyy} Q{1}" : "Q{1}", date, trimester); case 5: // year return date.ToString("yyyy", culture); } throw new InvalidOperationException("Unknown time period"); } }