using WxOrder.Framework.Commons;
using _29WxOrderWpf.Ctrls.Statistics.Models;
using _29WxOrderWpf.Ctrls.Statistics.Services;
using AllBase.Model.MvvmBaseClasses;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using WxOrder.Framework.Commons;
namespace _29WxOrderWpf.Ctrls.Statistics.ViewModels
{
///
/// 天/周/月周期统计 - 页面 ViewModel(MVVM)。
/// 通过 PeriodStatisticType 指定统计周期(Day/Week/Month),
/// 页面统一展示:筛选条件 + 周期×店铺统计表格 + 分页。
///
public class PeriodRevenueStatisticsViewModel : PropertyNotifyObject
{
/// 每页行数
private const int PageSize = 50;
private readonly IShopRevenueStatisticsService _service;
private readonly PeriodStatisticType _periodType;
private readonly DelegateCommand _firstPageCommand;
private readonly DelegateCommand _prevPageCommand;
private readonly DelegateCommand _nextPageCommand;
private readonly DelegateCommand _lastPageCommand;
private ObservableCollection _selectedShops;
private ShopRevenueSummary _summary;
private ObservableCollection _statistics;
private List _allItems = new List();
private int _pageIndex = 1;
private int _totalPages = 1;
private int _totalCount;
private string _pagerText = string.Empty;
/// 是否已完成首次初始化(用于避免页签来回切换时重复初始化、重复查询)
private bool _initialized;
/// 上一次真正生效(并据此计算过日期)的时间范围选项,避免同一个选项被重复应用
private TimeRangeOption _appliedTimeRange;
public PeriodRevenueStatisticsViewModel(PeriodStatisticType periodType)
: this(periodType, new ShopRevenueStatisticsService())
{
}
public PeriodRevenueStatisticsViewModel(PeriodStatisticType periodType, IShopRevenueStatisticsService service)
{
_periodType = periodType;
_service = service ?? new ShopRevenueStatisticsService();
PageTitle = GetPageTitle(periodType);
PeriodColumnHeader = GetPeriodColumnHeader(periodType);
TimeRangeOptions = new ObservableCollection(GetTimeRangeOptions(periodType));
ShopOptions = new ObservableCollection();
QueryCommand = new DelegateCommand(async () => await LoadAsync());
ResetCommand = new DelegateCommand(Reset);
_firstPageCommand = new DelegateCommand(() => GoToPage(1), () => HasPrevPage);
_prevPageCommand = new DelegateCommand(() => GoToPage(PageIndex - 1), () => HasPrevPage);
_nextPageCommand = new DelegateCommand(() => GoToPage(PageIndex + 1), () => HasNextPage);
_lastPageCommand = new DelegateCommand(() => GoToPage(TotalPages), () => HasNextPage);
}
///
/// 页面首次显示时初始化查询条件并加载数据(由外层 TabControl 的选中事件调用)。
/// 重复调用(在“综合统计 / 天统计 / 周统计 / 月统计”页签之间来回切换)会被忽略:
/// 否则每次切回来都会把时间范围和店铺重置成默认值,并重新发起一次查询。
/// 需要刷新数据时点“查询”按钮即可。
///
public void Init()
{
if (_initialized)
return;
_initialized = true;
InitializeAsync();
}
#region 页面标题
/// 页面标题(天统计/周统计/月统计)
public string PageTitle { get; }
/// 周期列表头(日期/周/月份)
public string PeriodColumnHeader { get; }
private static string GetPageTitle(PeriodStatisticType periodType)
{
switch (periodType)
{
case PeriodStatisticType.Week:
return "周统计";
case PeriodStatisticType.Month:
return "月统计";
default:
return "天统计";
}
}
private static string GetPeriodColumnHeader(PeriodStatisticType periodType)
{
switch (periodType)
{
case PeriodStatisticType.Week:
return "周";
case PeriodStatisticType.Month:
return "月份";
default:
return "日期";
}
}
#endregion
#region 时间范围选项
/// 按统计周期返回对应的时间范围选项
private static List GetTimeRangeOptions(PeriodStatisticType periodType)
{
switch (periodType)
{
case PeriodStatisticType.Week:
return new List
{
new TimeRangeOption { Text = "本周", Value = "week" },
new TimeRangeOption { Text = "上周", Value = "lastweek" },
new TimeRangeOption { Text = "最近2周", Value = "last2weeks" },
new TimeRangeOption { Text = "最近4周", Value = "last4weeks" },
new TimeRangeOption { Text = "自定义", Value = "custom" }
};
case PeriodStatisticType.Month:
return new List
{
new TimeRangeOption { Text = "本月", Value = "month" },
new TimeRangeOption { Text = "上月", Value = "lastmonth" },
new TimeRangeOption { Text = "最近3个月", Value = "last3months" },
new TimeRangeOption { Text = "最近6个月", Value = "last6months" },
new TimeRangeOption { Text = "最近12个月", Value = "last12months" },
new TimeRangeOption { Text = "自定义", Value = "custom" }
};
default:
return new List
{
new TimeRangeOption { Text = "最近5天", Value = "last5" },
new TimeRangeOption { Text = "最近10天", Value = "last10" },
new TimeRangeOption { Text = "最近20天", Value = "last20" },
new TimeRangeOption { Text = "最近30天", Value = "last30" },
new TimeRangeOption { Text = "自定义", Value = "custom" }
};
}
}
/// 按统计周期返回默认选中的时间范围值
private static string GetDefaultTimeRangeValue(PeriodStatisticType periodType)
{
switch (periodType)
{
case PeriodStatisticType.Week:
return "week";
case PeriodStatisticType.Month:
return "month";
default:
return "last10";
}
}
#endregion
#region 查询条件
public bool StatPackages
{
get { return this.GetValue(x => x.StatPackages); }
set { this.SetValue(x => x.StatPackages, value); }
}
/// 时间范围选项
public ObservableCollection TimeRangeOptions { get; }
/// 选中的时间范围
public TimeRangeOption SelectedTimeRange
{
get { return this.GetValue(x => x.SelectedTimeRange); }
set
{
this.SetValue(x => x.SelectedTimeRange, value);
// 只有用户真正切换到“另一个”时间范围选项时才重新计算起止日期。
// 页签切换时下拉框会把同一个选项(甚至先 null 再回写)重放一遍,
// 若照样重算,就会把用户手工调过的日期覆盖掉(例如自定义区间被改回“本周”)。
if (value != null && !ReferenceEquals(_appliedTimeRange, value))
{
_appliedTimeRange = value;
ApplyTimeRange();
}
OnPropertyChanged(nameof(IsCustomDateRange));
}
}
/// 是否为自定义时间范围
public bool IsCustomDateRange
{
get { return SelectedTimeRange != null && SelectedTimeRange.Value == "custom"; }
}
/// 开始日期
public DateTime StartDate
{
get { return this.GetValue(x => x.StartDate); }
set { this.SetValue(x => x.StartDate, value); }
}
/// 结束日期
public DateTime EndDate
{
get { return this.GetValue(x => x.EndDate); }
set { this.SetValue(x => x.EndDate, value); }
}
/// 店铺选项(“全部店铺”由多选控件“全部商铺”表示)
public ObservableCollection ShopOptions { get; }
/// 选中的店铺(多选,绑定 ShopFilterComboBox.SelectedItems)
public ObservableCollection SelectedShops
{
get { return _selectedShops; }
set
{
_selectedShops = value;
OnPropertyChanged(nameof(SelectedShops));
}
}
#endregion
#region 统计结果
/// 汇总卡片数据
public ShopRevenueSummary Summary
{
get { return _summary; }
private set
{
_summary = value;
OnPropertyChanged(nameof(Summary));
}
}
/// 当前页的周期×店铺统计表格数据
public ObservableCollection Statistics
{
get { return _statistics; }
private set
{
_statistics = value;
OnPropertyChanged(nameof(Statistics));
}
}
/// 是否正在加载
public bool IsLoading
{
get { return this.GetValue(x => x.IsLoading); }
set { this.SetValue(x => x.IsLoading, value); }
}
#endregion
#region 分页
/// 总行数
public int TotalCount
{
get { return _totalCount; }
private set
{
_totalCount = value;
OnPropertyChanged(nameof(TotalCount));
}
}
/// 当前页码(从 1 开始)
public int PageIndex
{
get { return _pageIndex; }
private set
{
_pageIndex = value;
OnPropertyChanged(nameof(PageIndex));
}
}
/// 总页数
public int TotalPages
{
get { return _totalPages; }
private set
{
_totalPages = value;
OnPropertyChanged(nameof(TotalPages));
}
}
/// 分页提示文本(共 X 条 第 Y / Z 页)
public string PagerText
{
get { return _pagerText; }
private set
{
_pagerText = value;
OnPropertyChanged(nameof(PagerText));
}
}
/// 是否有上一页
public bool HasPrevPage
{
get { return PageIndex > 1; }
}
/// 是否有下一页
public bool HasNextPage
{
get { return PageIndex < TotalPages; }
}
/// 是否多页
public bool HasMultiplePages
{
get { return TotalPages > 1; }
}
/// 首页命令
public ICommand FirstPageCommand
{
get { return _firstPageCommand; }
}
/// 上一页命令
public ICommand PrevPageCommand
{
get { return _prevPageCommand; }
}
/// 下一页命令
public ICommand NextPageCommand
{
get { return _nextPageCommand; }
}
/// 末页命令
public ICommand LastPageCommand
{
get { return _lastPageCommand; }
}
/// 跳转到指定页并刷新当前页数据
private void GoToPage(int page)
{
if (page < 1)
page = 1;
if (page > TotalPages)
page = TotalPages;
PageIndex = page;
ApplyPaging();
}
/// 按当前页码截取当前页数据并刷新分页状态
private void ApplyPaging()
{
var pageItems = _allItems
.Skip((PageIndex - 1) * PageSize)
.Take(PageSize)
.ToList();
Statistics = new ObservableCollection(pageItems);
PagerText = string.Format("共 {0} 条 第 {1} / {2} 页", TotalCount, PageIndex, TotalPages);
OnPropertyChanged(nameof(HasPrevPage));
OnPropertyChanged(nameof(HasNextPage));
OnPropertyChanged(nameof(HasMultiplePages));
_firstPageCommand.RaiseCanExecuteChanged();
_prevPageCommand.RaiseCanExecuteChanged();
_nextPageCommand.RaiseCanExecuteChanged();
_lastPageCommand.RaiseCanExecuteChanged();
}
#endregion
#region 命令
/// 查询命令
public ICommand QueryCommand { get; }
/// 重置命令
public ICommand ResetCommand { get; }
#endregion
#region 初始化
private async void InitializeAsync()
{
try
{
// 店铺选项(全部店铺由多选控件“全部商铺”表示,不再额外加入“全部店铺”项)
var shops = await _service.GetShopOptionsAsync();
foreach (var shop in shops)
ShopOptions.Add(shop);
SelectedShops = new ObservableCollection(ShopOptions);
// 默认时间范围
SelectedTimeRange = TimeRangeOptions.FirstOrDefault(t => t.Value == GetDefaultTimeRangeValue(_periodType));
ApplyTimeRange();
await LoadAsync();
}
catch (Exception ex)
{
MessageBox.Show("初始化数据失败:" + ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
#endregion
#region 业务逻辑
/// 根据时间范围选项计算起止日期
private void ApplyTimeRange()
{
var now = DateTime.Now;
var today = now.Date;
var selected = SelectedTimeRange == null ? string.Empty : SelectedTimeRange.Value;
switch (selected)
{
case "last5":
StartDate = today.AddDays(-4);
EndDate = now;
break;
case "last10":
StartDate = today.AddDays(-9);
EndDate = now;
break;
case "last20":
StartDate = today.AddDays(-19);
EndDate = now;
break;
case "last30":
StartDate = today.AddDays(-29);
EndDate = now;
break;
case "week":
{
int diff = today.DayOfWeek == DayOfWeek.Sunday ? 6 : (int)today.DayOfWeek - 1;
StartDate = today.AddDays(-diff);
EndDate = now;
}
break;
case "lastweek":
{
int diff = today.DayOfWeek == DayOfWeek.Sunday ? 6 : (int)today.DayOfWeek - 1;
var thisWeekStart = today.AddDays(-diff);
StartDate = thisWeekStart.AddDays(-7);
EndDate = thisWeekStart.AddDays(-1).AddHours(23).AddMinutes(59).AddSeconds(59);
}
break;
case "last2weeks":
StartDate = today.AddDays(-13);
EndDate = now;
break;
case "last4weeks":
StartDate = today.AddDays(-27);
EndDate = now;
break;
case "month":
StartDate = new DateTime(today.Year, today.Month, 1);
EndDate = now;
break;
case "lastmonth":
{
var firstOfThisMonth = new DateTime(today.Year, today.Month, 1);
StartDate = firstOfThisMonth.AddMonths(-1);
EndDate = firstOfThisMonth.AddDays(-1).AddHours(23).AddMinutes(59).AddSeconds(59);
}
break;
case "last3months":
StartDate = new DateTime(today.Year, today.Month, 1).AddMonths(-2);
EndDate = now;
break;
case "last6months":
StartDate = new DateTime(today.Year, today.Month, 1).AddMonths(-5);
EndDate = now;
break;
case "last12months":
StartDate = new DateTime(today.Year, today.Month, 1).AddMonths(-11);
EndDate = now;
break;
default:
// 自定义:保持用户选择的日期不变
break;
}
}
///
/// 根据选中店铺生成查询用 ERP 店铺ID 列表(接口 ShopIds 使用 ShopLoginInfo.ErpShopId):
/// 未选/全选/选中“全部店铺”时返回空列表(表示全部店铺)。
///
private List BuildSelectedShopIds()
{
var selected = SelectedShops;
if (selected == null || selected.Count == 0)
return new List();
var ids = selected.Select(s => s == null ? string.Empty : s.ErpShopId).ToList();
if (ids.Any(string.IsNullOrEmpty))
return new List();
if (selected.Count >= ShopOptions.Count)
return new List();
return ids;
}
/// 组装查询参数(起止日期已保证先后顺序)
private ShopRevenueStatisticsQuery BuildQuery()
{
if (StartDate > EndDate)
{
var temp = StartDate;
StartDate = EndDate;
EndDate = temp;
}
return new ShopRevenueStatisticsQuery
{
StartDate = StartDate,
EndDate = EndDate,
ShopIds = BuildSelectedShopIds(),
StatPackages = StatPackages
};
}
/// 执行查询,刷新周期统计表格并回到第一页
private async Task LoadAsync()
{
IsLoading = true;
try
{
var result = await _service.QueryPeriodStatisticsAsync(BuildQuery(), _periodType);
Summary = result.Summary;
_allItems = result.Items ?? new List();
TotalCount = _allItems.Count;
TotalPages = TotalCount == 0 ? 1 : (int)Math.Ceiling(TotalCount / (double)PageSize);
GoToPage(1);
}
catch (Exception ex)
{
// 查询异常:保留上一次数据,并弹框提示
MessageBox.Show("查询失败:" + ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
}
finally
{
IsLoading = false;
}
}
/// 重置查询条件并重新加载
private async void Reset()
{
SelectedShops = new ObservableCollection(ShopOptions);
SelectedTimeRange = TimeRangeOptions.FirstOrDefault(t => t.Value == GetDefaultTimeRangeValue(_periodType));
ApplyTimeRange();
await LoadAsync();
}
#endregion
public ICommand ShowOrderListCommand => new AsyncDelegateCommand(ShowOrderList);
private async Task ShowOrderList(string type)
{
var detailType = ParseDetailType(type);
List showList;
// 明细接口数据量大、耗时长,期间显示页面统一的加载遮罩,避免点了没反应
IsLoading = true;
try
{
showList = await _service.QueryOrderRowsAsync(BuildQuery(), detailType)
?? new List();
}
catch (Exception ex)
{
MessageBox.Show("订单明细查询失败:" + ex.Message, "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
finally
{
IsLoading = false;
}
if (showList.Count == 0)
{
MessageBox.Show("未查询到符合条件的订单明细。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
return;
}
new DialogWindow()
{
Title = "订单列表",
Content = new ShowOrderDialogView(showList, detailType, _service),
DataContext = showList
}.ShowDialog();
}
/// 卡片“明细”按钮参数 → 订单明细类型(对应接口参数 OrderType)
private static ShopOrderDetailType ParseDetailType(string type)
{
switch (type)
{
case "RefundOrderCount":
return ShopOrderDetailType.Refund; //退款订单
case "BuyerRefundRemainingAmount":
return ShopOrderDetailType.BuyerUnrefunded; //买手未退回金额的订单
default:
return ShopOrderDetailType.Valid; //有效订单
}
}
}
}