订单任务,现已修改成全局任务列表 包括 订单任务和礼品单任务
订单列表动态展示礼品单状态
This commit is contained in:
1 parent
78dc8a5d03
commit
7998a753cc
20 files changed
+2820
-2627
No files matched your search
@@ -28,6 +28,7 @@
|
||||
<PackageReference Include="chromiumembeddedframework.runtime.win-x64" Version="138.0.34" />
|
||||
<PackageReference Include="chromiumembeddedframework.runtime.win-x86" Version="138.0.34" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
|
||||
<PackageReference Include="WPFCommon" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -6,7 +6,7 @@ using Work.ERP.API;
|
||||
namespace _29WxOrderWpf.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// 订单任务状态转换:<see cref="Work.KJDServer.API.Models.OrderTask.Status"/> (int) → 中文描述。
|
||||
/// 订单任务状态转换:<see cref="Work.KJDServer.API.Models.TaskItem.Status"/> (int) → 中文描述。
|
||||
/// 1=执行中,2=已完成,3=已人为中断。
|
||||
/// </summary>
|
||||
public class OrderTaskStatusConverter : IValueConverter
|
||||
|
||||
@@ -46,6 +46,7 @@ using TemuKJD.ToolForms;
|
||||
using Work;
|
||||
using Work._29Tools.BLL;
|
||||
using Work.BuyUsers;
|
||||
using Work.KJDServer.API.Models;
|
||||
using WPFCommon.Helpers;
|
||||
using static _29WxOrderWpf.Services.ShipGiftService;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
@@ -62,7 +63,9 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
public OrderFilterConfig orderFilterConfig
|
||||
{
|
||||
get { return _orderFilterConfig; }
|
||||
set { if (_orderFilterConfig != value)
|
||||
set
|
||||
{
|
||||
if (_orderFilterConfig != value)
|
||||
_orderFilterConfig = value;
|
||||
OnPropertyChanged(new PropertyChangedEventArgs("orderFilterConfig"));
|
||||
}
|
||||
@@ -76,7 +79,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
_shipGiftService = new ShipGiftService();
|
||||
_shipGiftService = ShipGiftService.Instance;
|
||||
}
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
@@ -103,8 +106,13 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
borderFilterRemarkSelect.Visibility = Visibility.Collapsed;
|
||||
|
||||
AutoGetOrder();
|
||||
|
||||
TaskService.Instance.Start();
|
||||
TaskService.Instance.TaskChanged += Instance_TaskChanged;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public void GetOrderTest()
|
||||
//{
|
||||
// for (int i = 0; i < 10000; i++)
|
||||
@@ -837,7 +845,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
{
|
||||
|
||||
}
|
||||
if (orderItem.TransitRefundStatusStr.ParseToString().Contains("需手动申请售后") &&
|
||||
if (orderItem.TransitRefundStatusStr.ParseToString().Contains("需手动申请售后") &&
|
||||
orderItem.ItemTransitOrderWithVoid?.has_reject == 3 && orderItem.ItemTransitOrderWithVoid?.platform != "XDYYWC") // 义乌仓不支持拒收,等于3也是失败
|
||||
{
|
||||
// 拒收后24小时才去总店填拒收退货
|
||||
@@ -1043,7 +1051,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
var type = 4;
|
||||
if (chkRst.Contains("\"interactType\":0"))
|
||||
type = 2;
|
||||
var result = AddReturnPddShopPackageInfo(buyer, orderSn, afterSalesId, waybillId,"韵达快递", "121", type.ToString());
|
||||
var result = AddReturnPddShopPackageInfo(buyer, orderSn, afterSalesId, waybillId, "韵达快递", "121", type.ToString());
|
||||
if (!result.Contains("\"result\":\"ok\""))
|
||||
{
|
||||
type = type == 4 ? 2 : 4;
|
||||
@@ -1096,7 +1104,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
|
||||
TabItem tabItem = null;
|
||||
List<TabItem> tabItems = this.tabOrderType.Items.Cast<TabItem>().ToList();
|
||||
Dispatcher.Invoke(new Action(() => { tabItem = tabItems.FirstOrDefault(t => t.Header.ParseToString().StartsWith("待采购")); }));
|
||||
Dispatcher.Invoke(new Action(() => { tabItem = tabItems.FirstOrDefault(t => t.Header.ParseToString().StartsWith("待采购")); }));
|
||||
if (tabItem != null)
|
||||
{
|
||||
var filteLstTmp = userOrderLst.Where(o => !GetOrderIsFilter(o, "待采购")).ToList();
|
||||
@@ -1513,7 +1521,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
{
|
||||
Thread.Sleep(5000);
|
||||
Dispatcher.Invoke(new Action(() => { this.btnSearch.IsEnabled = true; }));
|
||||
});
|
||||
});
|
||||
//Task.Run(() =>
|
||||
//{
|
||||
// GetOrder();
|
||||
@@ -1902,7 +1910,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
public async Task DoReturnOrderBuyerRefendSlient()
|
||||
{
|
||||
List<oms_wei_order_info> emergencyRefundOrders = new List<oms_wei_order_info>();
|
||||
Dispatcher.Invoke(new Action(() =>
|
||||
Dispatcher.Invoke(new Action(() =>
|
||||
{
|
||||
emergencyRefundOrders = GlobalConfig.lstOrder.Where(o => o.IsEmergency).ToList();
|
||||
}));
|
||||
@@ -2281,7 +2289,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
FilterOrders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
@@ -2398,7 +2406,27 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
// set => SetProperty(ref _IsShipGift, value);
|
||||
//}
|
||||
|
||||
private void Instance_TaskChanged(object sender, IEnumerable<Work.KJDServer.API.Models.TaskItem> data)
|
||||
{
|
||||
var giftTaks = data.Where(a => a.TaskType == Work.KJDServer.API.Models.TaskType.Gifts && a.SubTasks != null)
|
||||
.SelectMany(a => a.SubTasks)
|
||||
.GroupBy(a => a.ObjectId)
|
||||
.Select(a => a.OrderByDescending(b => b.CreateTime).First())
|
||||
.ToList();
|
||||
|
||||
foreach (TaskSubItem item in giftTaks)
|
||||
{
|
||||
oms_wei_order_info order = GlobalConfig.lstOrder.FirstOrDefault(a => a.order_id == item.ObjectId);
|
||||
if (order != null)
|
||||
{
|
||||
order.GiftSuccessed = item.Status == 1;
|
||||
if (order.GiftSuccessed == false)
|
||||
{
|
||||
order.GiftErrorMsg = item.SysMsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class OrderFilterConfig : PropertyNotifyObject
|
||||
@@ -2408,7 +2436,7 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
|
||||
/// <summary>
|
||||
/// 隐藏标记
|
||||
/// </summary>
|
||||
public bool chkHideGreenFlagIsChecked
|
||||
public bool chkHideGreenFlagIsChecked
|
||||
{
|
||||
get { return this.GetValue(x => x.chkHideGreenFlagIsChecked); }
|
||||
set { this.SetValue(x => x.chkHideGreenFlagIsChecked, value); }
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,22 +2,29 @@
|
||||
x:Class="_29WxOrderWpf.Ctrls.OrderCtrls.OrderTaskDialogView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:comn="clr-namespace:_29WxOrderWpf.Common"
|
||||
xmlns:converters="clr-namespace:_29WxOrderWpf.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:_29WxOrderWpf.Ctrls.OrderCtrls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:wpf="clr-namespace:_29WxOrderWpf.Common"
|
||||
xmlns:wpf1="WPFCommon"
|
||||
xmlns:md="clr-namespace:Work.KJDServer.API.Models;assembly=29WxOrderWork"
|
||||
xmlns:wpf="WPFCommon"
|
||||
xmlns:wpfex="clr-namespace:WPFCommon.Extensions;assembly=WPFCommon"
|
||||
comn:DialogWindowProperty.Height="600"
|
||||
comn:DialogWindowProperty.ResizeMode="CanResizeWithGrip"
|
||||
comn:DialogWindowProperty.ShowMinButton="False"
|
||||
comn:DialogWindowProperty.Width="1300"
|
||||
d:Background="White"
|
||||
d:DataContext="{d:DesignInstance Type=local:OrderTaskDialogViewModel}"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="1300"
|
||||
wpf:DialogWindowProperty.Height="600"
|
||||
wpf:DialogWindowProperty.ResizeMode="CanResizeWithGrip"
|
||||
wpf:DialogWindowProperty.ShowMinButton="False"
|
||||
wpf:DialogWindowProperty.Width="1300"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
|
||||
<Style BasedOn="{StaticResource TitleContentBaseStyle}" TargetType="wpf:TitleContent">
|
||||
<Setter Property="Placement" Value="Left" />
|
||||
<Setter Property="TitleVerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
<!-- 单元格文字居中 -->
|
||||
<Style x:Key="CenterCellTextStyle" TargetType="TextBlock">
|
||||
<Setter Property="TextAlignment" Value="Center" />
|
||||
@@ -98,14 +105,30 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Style="{StaticResource PanelTitleStyle}" Text="订单同步任务列表" />
|
||||
<CheckBox
|
||||
Margin="20,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Content="查看全部"
|
||||
IsChecked="{Binding IsShowAll}" />
|
||||
</StackPanel>
|
||||
<wpf:SpacingStackPanel HorizontalSpacing="10" Orientation="Horizontal">
|
||||
<wpf:TitleContent Title="开始时间:">
|
||||
<DatePicker
|
||||
Width="100"
|
||||
BorderBrush="{StaticResource pageColorBrush}"
|
||||
Text="{Binding StartDate}" />
|
||||
</wpf:TitleContent>
|
||||
<wpf:TitleContent Title="结束时间:">
|
||||
<DatePicker
|
||||
Width="100"
|
||||
BorderBrush="{StaticResource pageColorBrush}"
|
||||
Text="{Binding EndDate}" />
|
||||
</wpf:TitleContent>
|
||||
<wpf:TitleContent Title="任务类型:">
|
||||
<ComboBox
|
||||
Width="100"
|
||||
wpf:EnumBindingExtension.SelectedEnum="{Binding SelectedTaskType}"
|
||||
ItemsSource="{wpf:EnumBindingMarkup EnumType=md:TaskType,
|
||||
Converter={StaticResource EnumDisplayConverter}}" />
|
||||
</wpf:TitleContent>
|
||||
<wpf:TitleContent Title="所有状态:" VerticalContentAlignment="Center">
|
||||
<CheckBox VerticalAlignment="Center" IsChecked="{Binding IsShowAll}" />
|
||||
</wpf:TitleContent>
|
||||
</wpf:SpacingStackPanel>
|
||||
<!--<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Button
|
||||
Command="{Binding ClearFinishedCommand}"
|
||||
@@ -122,7 +145,7 @@
|
||||
<!-- ============ 任务列表 ============ -->
|
||||
<DataGrid
|
||||
Grid.Row="1"
|
||||
Margin="10,10,10,0"
|
||||
Margin="10,10,10,10"
|
||||
d:ItemsSource="{d:SampleData ItemCount=10}"
|
||||
AlternatingRowBackground="#FAFAFA"
|
||||
AutoGenerateColumns="False"
|
||||
@@ -141,7 +164,7 @@
|
||||
HorizontalGridLinesBrush="#EEEEEE"
|
||||
IsReadOnly="True"
|
||||
ItemsSource="{Binding TasksView}"
|
||||
RowHeight="40"
|
||||
RowHeight="35"
|
||||
ScrollViewer.CanContentScroll="True"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
||||
@@ -153,9 +176,9 @@
|
||||
<DataGridTextColumn
|
||||
Width="1.5*"
|
||||
MinWidth="120"
|
||||
Binding="{Binding TaskDescribe}"
|
||||
Binding="{Binding TaskType, Converter={StaticResource EnumDisplayConverter}}"
|
||||
ElementStyle="{StaticResource CenterCellTextStyle}"
|
||||
Header="任务描述" />
|
||||
Header="任务类型" />
|
||||
<!-- 店铺 -->
|
||||
<DataGridTextColumn
|
||||
Width="1*"
|
||||
@@ -164,7 +187,12 @@
|
||||
ElementStyle="{StaticResource CenterCellTextStyle}"
|
||||
Header="店铺" />
|
||||
|
||||
|
||||
<DataGridTextColumn
|
||||
Width="2*"
|
||||
MinWidth="100"
|
||||
Binding="{Binding ObjectIds}"
|
||||
ElementStyle="{StaticResource CenterCellTextStyle}"
|
||||
Header="订单号" />
|
||||
<!-- 状态 -->
|
||||
<DataGridTemplateColumn
|
||||
Width="1*"
|
||||
@@ -236,8 +264,8 @@
|
||||
<Grid VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Right"
|
||||
d:Text="距离下次刷新10秒"
|
||||
Text="{Binding RefreshTime, StringFormat='距离下次刷新:{0}秒'}" />
|
||||
d:Text="刷新10秒"
|
||||
Text="{Binding RefreshTime, StringFormat='刷新:{0}秒'}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
@@ -44,7 +45,7 @@ public partial class OrderTaskDialogView : UserControl
|
||||
|
||||
private async void OrderTaskDialogView_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _viewModel.LoadTasks();
|
||||
_viewModel.LoadTasks();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,75 +55,103 @@ public partial class OrderTaskDialogView : UserControl
|
||||
public class OrderTaskDialogViewModel : BindableBaseEx, IDisposable
|
||||
{
|
||||
private DispatcherTimer _timer;
|
||||
private const int RefreshIntervals = 10;
|
||||
private int _timeCount = 0;
|
||||
private readonly PullWXOrderService _service;
|
||||
private readonly NotifyCollectionChangedEventHandler _collectionChangedHandler;
|
||||
|
||||
private readonly TaskService _taskService;
|
||||
|
||||
public OrderTaskDialogViewModel()
|
||||
: this(PullWXOrderService.Instance)
|
||||
: this(TaskService.Instance)
|
||||
{
|
||||
_timer = new DispatcherTimer();
|
||||
_timer.Interval = TimeSpan.FromSeconds(1);
|
||||
_timer.Tick += _timer_Tick;
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
private async void _timer_Tick(object sender, EventArgs e)
|
||||
public OrderTaskDialogViewModel(TaskService taskService)
|
||||
{
|
||||
_timeCount++;
|
||||
if (_timeCount % RefreshIntervals == 0)
|
||||
{
|
||||
await LoadTasks();
|
||||
_timeCount = 0;
|
||||
}
|
||||
RefreshTime = RefreshIntervals - _timeCount;
|
||||
}
|
||||
|
||||
public OrderTaskDialogViewModel(PullWXOrderService service)
|
||||
{
|
||||
_service = service ?? PullWXOrderService.Instance;
|
||||
Tasks = _service.Tasks;
|
||||
_collectionChangedHandler = OnTasksCollectionChanged;
|
||||
Tasks.CollectionChanged += _collectionChangedHandler;
|
||||
_taskService = taskService;
|
||||
|
||||
|
||||
ClearFinishedCommand = new DelegateCommand(ClearFinished);
|
||||
ClearAllCommand = new DelegateCommand(ClearAll);
|
||||
StartDate = _taskService.StartDate;
|
||||
EndDate = _taskService.EndDate;
|
||||
|
||||
UpdateSummary();
|
||||
|
||||
|
||||
Tasks = new ObservableCollection<TaskItem>();
|
||||
|
||||
TasksView = CollectionViewSource.GetDefaultView(Tasks);
|
||||
TasksView.Filter = FilterTaskStatus;
|
||||
|
||||
_taskService.TaskChanged += TaskChanged;
|
||||
}
|
||||
private async void _timer_Tick(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
RefreshTime = _taskService.ResetCountdown;
|
||||
}
|
||||
|
||||
public async Task LoadTasks()
|
||||
|
||||
public TaskType SelectedTaskType
|
||||
{
|
||||
await _service.GetTaskStatus();
|
||||
get => GetValue<TaskType>();
|
||||
set
|
||||
{
|
||||
SetValue(value);
|
||||
TasksView.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void TaskChanged(object sender, IEnumerable<TaskItem> data)
|
||||
{
|
||||
LoadTasks();
|
||||
}
|
||||
|
||||
public void LoadTasks()
|
||||
{
|
||||
System.Windows.Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Tasks.Clear();
|
||||
foreach (var item in TaskService.Instance.Tasks)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(item.TaskFailReason))
|
||||
{
|
||||
if (item.TaskFailReason.Contains("任务执行异常"))
|
||||
{
|
||||
item.Status = 4;
|
||||
}
|
||||
}
|
||||
Tasks.Add(item);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 过滤
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
private bool FilterTaskStatus(object obj)
|
||||
{
|
||||
if (obj is not OrderTask task)
|
||||
if (obj is not TaskItem task)
|
||||
return false;
|
||||
|
||||
if (IsShowAll == true)
|
||||
return true;
|
||||
// Status 维度筛选
|
||||
bool statusMatch = IsShowAll || task.Status != 2;
|
||||
// 如果 IsShowAll=true,表示显示所有状态;否则只显示特定状态
|
||||
|
||||
return task.Status !=2;
|
||||
// TaskType 维度筛选
|
||||
bool typeMatch = SelectedTaskType == TaskType.ALL ? true : SelectedTaskType == task.TaskType;
|
||||
bool timeMatch = StartDate <= task.CreateTime && task.CreateTime <= EndDate;
|
||||
|
||||
// 如果 SelectedTaskType==null,表示显示所有类型;否则只显示特定类型
|
||||
return statusMatch && typeMatch && timeMatch;
|
||||
}
|
||||
|
||||
/// <summary>任务列表</summary>
|
||||
public ObservableCollection<OrderTask> Tasks { get; }
|
||||
public ObservableCollection<TaskItem> Tasks { get; }
|
||||
|
||||
public ICollectionView TasksView { get; }
|
||||
|
||||
/// <summary>清空已完成/失败任务</summary>
|
||||
public ICommand ClearFinishedCommand { get; }
|
||||
|
||||
/// <summary>清空全部任务</summary>
|
||||
public ICommand ClearAllCommand { get; }
|
||||
|
||||
/// <summary>汇总文字(总数/执行中/成功/失败)</summary>
|
||||
public string SummaryText
|
||||
{
|
||||
@@ -134,6 +163,19 @@ public class OrderTaskDialogViewModel : BindableBaseEx, IDisposable
|
||||
get => GetValue<int>();
|
||||
set => SetValue(value);
|
||||
}
|
||||
|
||||
|
||||
public DateTime StartDate
|
||||
{
|
||||
get => GetValue<DateTime>();
|
||||
set => SetValue(value);
|
||||
}
|
||||
public DateTime EndDate
|
||||
{
|
||||
get => GetValue<DateTime>();
|
||||
set => SetValue(value);
|
||||
}
|
||||
|
||||
public bool IsShowAll
|
||||
{
|
||||
get => GetValue<bool>();
|
||||
@@ -144,38 +186,7 @@ public class OrderTaskDialogViewModel : BindableBaseEx, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearFinished()
|
||||
{
|
||||
_service.ClearFinished();
|
||||
}
|
||||
|
||||
private void ClearAll()
|
||||
{
|
||||
if (System.Windows.MessageBox.Show("确定清空全部任务吗?", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Question) != MessageBoxResult.OK)
|
||||
return;
|
||||
_service.ClearAll();
|
||||
}
|
||||
|
||||
private void OnTasksCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
UpdateSummary();
|
||||
}
|
||||
|
||||
private void OnTaskPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(OrderTask.Status))
|
||||
UpdateSummary();
|
||||
}
|
||||
|
||||
private void UpdateSummary()
|
||||
{
|
||||
var items = Tasks;
|
||||
//int running = items.Count(t => t.Status == OrderTask.Running);
|
||||
//int success = items.Count(t => t.Status == OrderTask.Success);
|
||||
//int failed = items.Count(t => t.Status == OrderTask.Failed);
|
||||
//string.Format("任务总数:{0} 执行中:{1} 成功:{2} 失败:{3}",
|
||||
//items.Length, running, success, failed);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
@@ -17,34 +17,24 @@ namespace _29WxOrderWpf.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// 拉取微信订单 - 任务数据服务。
|
||||
/// 维护一个任务列表,每次拉取操作都会记录为一条任务,供"任务列表"界面展示;
|
||||
/// 拉取请求通过 <see cref="PullWXOrderServiceApi"/> 提交,提交后返回服务器任务ID;
|
||||
/// 随后循环查询任务状态,直到完成/中断/超时。任务状态查询是另一个独立API
|
||||
/// (查询 task 表),见 <see cref="QueryTaskAsync"/>(占位,需自行实现)。
|
||||
/// </summary>
|
||||
public class PullWXOrderService
|
||||
{
|
||||
/// <summary>循环查询服务器任务状态的间隔(秒)</summary>
|
||||
private const int TaskStatusPollIntervalSeconds = 30;
|
||||
|
||||
/// <summary>循环查询服务器任务状态的最大等待时间</summary>
|
||||
private static readonly TimeSpan TaskStatusMaxWait = TimeSpan.FromMinutes(10);
|
||||
private static readonly Lazy<PullWXOrderService> _lazy = new Lazy<PullWXOrderService>(() => new PullWXOrderService());
|
||||
|
||||
/// <summary>单例(全局共享同一份任务列表)</summary>
|
||||
public static PullWXOrderService Instance => _lazy.Value;
|
||||
|
||||
private readonly PullWXOrderServiceApi _erpApi = new PullWXOrderServiceApi();
|
||||
private readonly WxOrderServiceApi _kjdApi = new WxOrderServiceApi();
|
||||
private long _seq;
|
||||
|
||||
public PullWXOrderService()
|
||||
{
|
||||
Tasks = new ObservableCollection<OrderTask>();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>任务列表(线程安全,界面可直接绑定)</summary>
|
||||
public ObservableCollection<OrderTask> Tasks { get; }
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 拉取指定店铺的指定订单
|
||||
@@ -54,14 +44,6 @@ namespace _29WxOrderWpf.Services
|
||||
return await _erpApi.PullOrderDetail(shopId, orderId);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 拉取指定店铺的多个订单
|
||||
///// </summary>
|
||||
//public Task<PullWXOrderTaskItem> PullOrdersDetailAsync(long shopId, string[] orderIds)
|
||||
//{
|
||||
// return RunTaskAsync("批量拉取订单", shopId.ToString(), string.Join(",", orderIds ?? new string[0]),
|
||||
// () => _erpApi.PullOrdersDetail(shopId, orderIds));
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 按店铺与时间范围拉取订单
|
||||
@@ -86,110 +68,5 @@ namespace _29WxOrderWpf.Services
|
||||
{
|
||||
return _erpApi.PullAfterSaleOrders(shopId, afterSaleOrderIds);
|
||||
}
|
||||
|
||||
|
||||
public async Task GetTaskStatus()
|
||||
{
|
||||
var tasks = await _kjdApi.GetWxTaskStatus();
|
||||
|
||||
if (tasks != null)
|
||||
{
|
||||
Tasks.Clear();
|
||||
tasks.ForEach(a =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(a.TaskFailReason))
|
||||
{
|
||||
if (a.TaskFailReason.Contains("任务执行异常"))
|
||||
{
|
||||
a.Status = 4;
|
||||
}
|
||||
}
|
||||
Tasks.Add(a);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空已完成/失败的任务(保留执行中的任务)
|
||||
/// </summary>
|
||||
public void ClearFinished()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有任务
|
||||
/// </summary>
|
||||
public void ClearAll()
|
||||
{
|
||||
Tasks.Clear();
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// 创建一个任务并执行:提交拉取请求获取服务器任务ID,再循环查询任务状态直至完成。
|
||||
///// </summary>
|
||||
//private async Task<PullWXOrderTaskItem> RunTaskAsync(string taskName, string shopIds, string orderIds, Func<Task<long>> action)
|
||||
//{
|
||||
// var task = new PullWXOrderTaskItem
|
||||
// {
|
||||
// Id = Interlocked.Increment(ref _seq),
|
||||
// TaskName = taskName,
|
||||
// ShopIds = shopIds,
|
||||
// OrderIds = orderIds,
|
||||
// StartTime = DateTime.Now,
|
||||
// Status = PullWXOrderTaskStatus.Running
|
||||
// };
|
||||
// Tasks.Add(task);
|
||||
// try
|
||||
// {
|
||||
// long serverTaskId = await action();
|
||||
// task.ServerTaskId = serverTaskId;
|
||||
// if (serverTaskId > 0)
|
||||
// {
|
||||
// await PollTaskStatusAsync(task, serverTaskId);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // 服务器直接完成,无需轮询
|
||||
// task.EndTime = DateTime.Now;
|
||||
// task.Message = "成功";
|
||||
// task.Status = PullWXOrderTaskStatus.Success;
|
||||
// }
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// task.EndTime = DateTime.Now;
|
||||
// task.Message = ex.Message;
|
||||
// task.Status = PullWXOrderTaskStatus.Failed;
|
||||
// }
|
||||
// return task;
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// 循环查询服务器任务状态,直到完成/中断/超时。
|
||||
/// 每次查询都会用 task 表的可用字段刷新任务列表展示内容(任务描述/进度/失败原因等)。
|
||||
/// </summary>
|
||||
private async Task PollTaskStatusAsync(OrderTask task, long serverTaskId)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 查询服务器任务信息(对应 task 表,任务状态查询接口返回的数据)。
|
||||
/// TODO:任务状态查询是另一个独立API,请在这里接入你自己的查询实现,
|
||||
/// 返回 <see cref="TaskInfo"/>;task 表 status 字段:1=执行中(Executing),2=已完成(Completed),3=已人为中断(ManuallyInterrupted)。
|
||||
/// </summary>
|
||||
//private async Task<TaskInfo> QueryTaskAsync()
|
||||
//{
|
||||
// await _kjdApi.GetWxTaskStatus();
|
||||
// // ===================== 请在这里接入你自己的任务状态查询API =====================
|
||||
// // 示例:
|
||||
// // TaskInfo info = await 你的查询API.QueryTask(taskId);
|
||||
// // return info;
|
||||
// // ===============================================================================
|
||||
// throw new NotImplementedException("任务状态查询API尚未实现,请在 PullWXOrderService.QueryTaskAsync 中接入");
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using Work._29Tools.BLL;
|
||||
using Work.ERP.API.Orders;
|
||||
using WxOrder.Framework;
|
||||
|
||||
namespace _29WxOrderWpf.Services;
|
||||
|
||||
@@ -19,7 +20,7 @@ namespace _29WxOrderWpf.Services;
|
||||
/// 礼物单服务
|
||||
///
|
||||
/// </summary>
|
||||
public class ShipGiftService
|
||||
public class ShipGiftService: SingleInstance<ShipGiftService>
|
||||
{
|
||||
public enum GiftType
|
||||
{
|
||||
@@ -27,7 +28,7 @@ public class ShipGiftService
|
||||
_160 = 5
|
||||
}
|
||||
private ShipGiftServiceApi _api;
|
||||
public ShipGiftService()
|
||||
private ShipGiftService()
|
||||
{
|
||||
_api = new ShipGiftServiceApi();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
using _29WxOrderWpf.Ctrls.Statistics.Models;
|
||||
using AllBase;
|
||||
using AllBase.Helper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.ComTypes;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Work;
|
||||
using Work.KJDServer.API.Models;
|
||||
using Work.KJDServer.API.WXOrder;
|
||||
using WPFCommon.Events;
|
||||
using WxOrder.Framework;
|
||||
|
||||
namespace _29WxOrderWpf.Services;
|
||||
|
||||
|
||||
public class TaskService : SingleInstance<TaskService>
|
||||
{
|
||||
/// <summary>循环查询服务器任务状态的间隔(秒)</summary>
|
||||
private const int TaskStatusPollIntervalSeconds = 10;
|
||||
private readonly System.Timers.Timer _timer;
|
||||
private readonly WxOrderServiceApi _kjdApi = new WxOrderServiceApi();
|
||||
|
||||
public List<TaskItem> Tasks { get; }
|
||||
/// <summary>
|
||||
/// 刷新倒计时
|
||||
/// </summary>
|
||||
public int ResetCountdown { get; private set; }
|
||||
|
||||
private TaskService()
|
||||
{
|
||||
_timer = new System.Timers.Timer();
|
||||
_timer.Interval = 1000;
|
||||
_timer.Elapsed += _timer_Elapsed;
|
||||
Tasks = new List<TaskItem>();
|
||||
}
|
||||
private int _timeCount = 0;
|
||||
private void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
_timeCount++;
|
||||
if (_timeCount % TaskStatusPollIntervalSeconds == 0)
|
||||
{
|
||||
_timeCount = 0;
|
||||
_ = QueryTaskAsync();
|
||||
}
|
||||
ResetCountdown = TaskStatusPollIntervalSeconds - _timeCount;
|
||||
|
||||
|
||||
}
|
||||
public delegate void TaskEventHandler<TEventArgs>(object sender, TEventArgs data);
|
||||
|
||||
public event TaskEventHandler<IEnumerable<TaskItem>> TaskChanged;
|
||||
|
||||
public DateTime StartDate { get; private set; } = DateTime.Now.AddMonths(-3);
|
||||
public DateTime EndDate { get; private set; } = DateTime.Now.Date.AddDays(1).AddSeconds(-1);
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_timer.Start();
|
||||
}
|
||||
public void Stop()
|
||||
{
|
||||
_timer.Stop();
|
||||
}
|
||||
|
||||
public void SetQueryParameters(DateTime startDate, DateTime endDate)
|
||||
{
|
||||
StartDate = startDate;
|
||||
EndDate = endDate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询服务器任务信息
|
||||
/// </summary>
|
||||
public async Task QueryTaskAsync()
|
||||
{
|
||||
|
||||
var tasks = await _kjdApi.GetWxTaskStatus(GlobalConfig.ShopLoginList.Select(a => a.ErpShopId), StartDate, EndDate);
|
||||
|
||||
if (tasks != null)
|
||||
{
|
||||
foreach (var item in tasks)
|
||||
{
|
||||
if (item.TaskType == TaskType.Gifts)
|
||||
{
|
||||
if (item.SubTasks?.Any() ?? false)
|
||||
{
|
||||
item.ObjectIds = string.Join(";", item.SubTasks.Select(a => a.ObjectId));
|
||||
var subTask = item.SubTasks.First();
|
||||
if (subTask.Status == 2)
|
||||
{
|
||||
item.TaskFailReason = subTask.SysMsg;
|
||||
item.Status = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tasks.Clear();
|
||||
Tasks.AddRange(tasks);
|
||||
}
|
||||
TaskChanged?.Invoke(this, this.Tasks);
|
||||
}
|
||||
}
|
||||
@@ -25,9 +25,12 @@ namespace _29WxOrderWpf
|
||||
GlobalConfig.lstWXShopTokenInfo = ConfigHelper.LoadConfig<ConcurrentList<WXShopTokenInfo>>("wx_shop_token_list");
|
||||
if (GlobalConfig.lstWXShopTokenInfo == null)
|
||||
GlobalConfig.lstWXShopTokenInfo = new ConcurrentList<WXShopTokenInfo>();
|
||||
|
||||
|
||||
new WxOrder.Framework.Startup();
|
||||
}
|
||||
|
||||
public static void SaveBuyConfig()
|
||||
public static void SaveBuyConfig()
|
||||
{
|
||||
ConfigHelper.SaveConfig("buy_config_260708", GlobalConfig.BuyConfig);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -126,6 +126,9 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="WPFCommon, Version=1.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\WPFCommon.1.1.0\lib\net462\WPFCommon.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AddressSetIni.cs" />
|
||||
|
||||
@@ -23,12 +23,12 @@ namespace Work.KJDServer.API
|
||||
data = $"{sign}&{data}";
|
||||
return await _postAsync(url, data);
|
||||
}
|
||||
public static async Task<T> PostAsync<T>(string url, string data) where T : Result, new()
|
||||
public static async Task<T> PostAsync<T>(string url, string data, JsonSerializerSettings settings = null) where T : Result, new()
|
||||
{
|
||||
try
|
||||
{
|
||||
string result = await PostAsync(url, data);
|
||||
return JsonConvert.DeserializeObject<T>(result);
|
||||
return JsonConvert.DeserializeObject<T>(result, settings);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
|
||||
@@ -1,16 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WPFCommon.Attributes;
|
||||
|
||||
namespace Work.KJDServer.API.Models
|
||||
{
|
||||
public class OrderTask
|
||||
public enum TaskType
|
||||
{
|
||||
[Description("全部")]
|
||||
ALL =0,
|
||||
/// <summary>
|
||||
/// 普通订单任务
|
||||
/// </summary>
|
||||
[Description("订单拉取")]
|
||||
WXORD = 25,
|
||||
/// <summary>
|
||||
/// 售后订单任务
|
||||
/// </summary>
|
||||
[Description("售后拉取")]
|
||||
WXASO = 31,
|
||||
[Description("礼物发货")]
|
||||
Gifts = 36
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Task 任务
|
||||
/// </summary>
|
||||
public class TaskItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public int TaskType { get; set; }
|
||||
public TaskType TaskType { get; set; }
|
||||
|
||||
public string TaskDescribe { get; set; }
|
||||
|
||||
@@ -38,6 +61,23 @@ namespace Work.KJDServer.API.Models
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
public List<TaskSubItem> SubTasks { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Task 子任务
|
||||
/// </summary>
|
||||
public class TaskSubItem
|
||||
{
|
||||
public string ObjectId { get; set; }
|
||||
/// <summary>
|
||||
/// 0:待执行,1:成功,2:失败,3:人为终止
|
||||
/// </summary>
|
||||
public int Status { get; set; }
|
||||
public string SysMsg { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using AllBase;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -17,9 +18,19 @@ namespace Work.KJDServer.API.WXOrder
|
||||
|
||||
}
|
||||
|
||||
public async Task<List<OrderTask>> GetWxTaskStatus()
|
||||
public async Task<List<TaskItem>> GetWxTaskStatus(IEnumerable<string> shopIds,DateTime startTime,DateTime endTime)
|
||||
{
|
||||
var ret = await KJDServerHttp.PostAsync<Result<List<OrderTask>>>("order/wx_get_task_status_list", "");
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("&shop_ids=").Append(string.Join(",", shopIds));
|
||||
sb.Append("&start_time=").Append(BaseClass.ConvertDateTimeLong(startTime));
|
||||
sb.Append("&end_time=").Append(BaseClass.ConvertDateTimeLong(endTime));
|
||||
var ret = await KJDServerHttp.PostAsync<Result<List<TaskItem>>>("order/wx_get_task_status_list", sb.ToString(),new Newtonsoft.Json.JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new SnakeCaseNamingStrategy()
|
||||
}
|
||||
});
|
||||
if (ret.Code == 200)
|
||||
{
|
||||
return ret.Data;
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
<package id="chromiumembeddedframework.runtime.win-x64" version="138.0.34" targetFramework="net462" />
|
||||
<package id="chromiumembeddedframework.runtime.win-x86" version="138.0.34" targetFramework="net462" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net462" />
|
||||
<package id="WPFCommon" version="1.1.0" targetFramework="net462" />
|
||||
</packages>
|
||||
@@ -10,7 +10,7 @@ namespace WxOrder.Framework.Commons
|
||||
{
|
||||
public Result()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
public Result(int code, string msg)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace WxOrder.Framework;
|
||||
|
||||
/// <summary>
|
||||
/// 单例,需要在当前类中定义
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public class SingleInstance<T> where T : class
|
||||
{
|
||||
private static readonly object lockObj = new();
|
||||
private static T mySelf;//= default(T);
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (lockObj)
|
||||
{
|
||||
mySelf ??= InstanceCreator.CreateInstance<T>();
|
||||
}
|
||||
|
||||
return mySelf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstanceCreator
|
||||
{
|
||||
public static T CreateInstance<T>()
|
||||
{
|
||||
Type type = typeof(T);
|
||||
try
|
||||
{
|
||||
return (T)type.Assembly.CreateInstance(type.FullName, true, BindingFlags.NonPublic | BindingFlags.Instance, null, null, null, null);
|
||||
}
|
||||
catch (MissingMethodException ex)
|
||||
{
|
||||
throw new Exception($"{ex.Message}\n(单例模式下,构造函数必须为 private)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WPFCommon.Converters;
|
||||
using WPFCommon.Utilities;
|
||||
|
||||
namespace WxOrder.Framework;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
public Startup()
|
||||
{
|
||||
EnumDisplayConverter.EnumDisplayManager = new EnumDisplayManagerWPF(null);
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Fonts\iconfont.ttf" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Fonts\iconfont.ttf" />
|
||||
</ItemGroup>
|
||||
@@ -45,4 +44,9 @@
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\" />
|
||||
<Folder Include="Controls\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in new issue
Block a user