订单任务,现已修改成全局任务列表 包括 订单任务和礼品单任务

订单列表动态展示礼品单状态
This commit is contained in:
chfei committed 2026-08-24 18:11:44 +08:00
1 parent 78dc8a5d03
commit 7998a753cc
20 files changed
+2820 -2627

No files matched your search

+1
View File
@@ -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()
{
+3 -126
View File
@@ -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 中接入");
//}
}
}
+3 -2
View File
@@ -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();
}
+109
View File
@@ -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);
}
}
+4 -1
View File
@@ -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
+3
View File
@@ -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" />
+2 -2
View File
@@ -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)
{
+42 -2
View File
@@ -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;
+1
View File
@@ -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>
+1 -1
View File
@@ -10,7 +10,7 @@ namespace WxOrder.Framework.Commons
{
public Result()
{
}
public Result(int code, string msg)
{
+42
View File
@@ -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)");
}
}
}
+17
View File
@@ -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);
}
}
+5 -1
View File
@@ -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>