Revert "发票助手"

This reverts commit f2d31c4a42.
This commit is contained in:
chfei committed 2026-08-20 14:57:05 +08:00
1 parent f2d31c4a42
commit 4c82d549ec
10 files changed
+304 -1850

No files matched your search

@@ -1,5 +1,4 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -15,38 +14,27 @@ namespace _29WxOrderWpf.Converters
{
public class ImageUrlToBitmapImageConverter : IValueConverter
{
/// <summary> 缓存上限,防止大量缩略图重复下载导致内存膨胀 </summary>
private const int MaxCacheCount = 200;
private readonly ConcurrentDictionary<string, BitmapImage> _imageCache = new ConcurrentDictionary<string, BitmapImage>();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string url && Uri.IsWellFormedUriString(url, UriKind.Absolute))
{
if (_imageCache.TryGetValue(url, out BitmapImage cached))
{
return cached;
}
try
{
// 直接加载绑定如果遇到有问题的网络图片会直接崩溃。
BitmapImage bitMap = AllBase.ImageBuild.LoadBitmipImageFromUrl(url);
if (bitMap != null)
{
if (_imageCache.Count >= MaxCacheCount)
{
_imageCache.Clear();
}
_imageCache[url] = bitMap;
}
//var bitMap = new BitmapImage(new Uri(url));
BitmapImage bitMap = null;
//bitMap = LoadImageFromUrl(url + "?imageView2/1/w/100/format/webp|imageMogr2/auto-orient=");
bitMap = AllBase.ImageBuild.LoadBitmipImageFromUrl(url);
return bitMap;
//string errStr = "";
//var bitmapImg = GetUrlImg(url, out errStr);
//return bitmapImg;
}
catch
{
}
//return Task.Run(() => new BitmapImage(new Uri(url))); // 使用 Task.Run 来异步加载图片。
}
return null;
}
@@ -1,318 +0,0 @@
using _29WxOrderWpf.BaseWindows;
using _29WxOrderWpf.Commands;
using _29WxOrderWpf.Common;
using _29WxOrderWpf.Ctrls.PDDInvoice;
using _29WxOrderWpf.Ctrls.Statistics;
using _29WxOrderWpf.Services;
using AllBase.Helper;
using AllBase.Model.DBModel;
using NaiBa.Util.Extension;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using Work._29Tools.BLL;
using static _29WxOrderWpf.Services.ShipGiftService;
namespace _29WxOrderWpf.Ctrls.OrderCtrls;
public partial class OrderListCtrl
{
#region 统计
private DialogWindow _statisticsDialog;
public ICommand ShowShopRevenueStatisticsDialogViewCommand => new DelegateCommand(ShowShopRevenueStatisticsDialogView);
private void ShowShopRevenueStatisticsDialogView()
{
if (_statisticsDialog == null)
{
_statisticsDialog = new DialogWindow()
{
Title = "统计",
Content = new ShopRevenueStatisticsView(),
};
_statisticsDialog.Closed += (s, e) => _statisticsDialog = null;
}
_statisticsDialog.Show();
}
#endregion
#region 礼物
public ICommand MultipleShipGiftCommand => new AsyncDelegateCommand(MultipleShipGift);
/// <summary>
/// 批量发送礼品单
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async Task MultipleShipGift()
{
try
{
var list = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList();
int count = list.Count;
if (count == 0)
{
BaseMsgWindow.ShowError("请选取要发货的订单", "Error");
return;
}
GiftType giftType = GiftType._160;
if (cb_gift.SelectedIndex == 0)
{
giftType = GiftType._155;
}
else
{
giftType = GiftType._160;
}
int index = 1;
int sucessCount = 0;
int errorCount = 0;
foreach (oms_wei_order_info item in list)
{
try
{
var rst = await WxApiBLL.WxSearchAndDropshipCancelAsync(item.Shop, item);
if (rst == "success")
{
var ret = await _shipGiftService.Send(item.order_id, giftType);
if (ret)
{
sucessCount++;
item.gift_order_status = 1;
this.FilterOneOrder(item, true);
}
else
{
errorCount++;
}
}
else
{
errorCount++;
}
}
catch (Exception ex)
{
errorCount++;
}
finally
{
item.IsSelect = false;
}
SetProgress(index, count);
BottomMsg = $"礼品单发送进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}";
index++;
}
BottomMsg = $"礼品单发送完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}";
}
catch (Exception ex)
{
BaseMsgWindow.ShowError("礼品单发货失败\n" + ex.Message, "Error");
}
finally
{
}
}
#endregion
#region 同步订单
/// <summary>
/// 拉取微信订单到任务列表
/// </summary>
public ICommand PullWXOrderCommand => new AsyncDelegateCommand(PullWXOrder);
private async Task PullWXOrder()
{
try
{
var isAfterSales = GlobalConfig.OrderTabHeaderStr.StartsWith("需处理售后单");//是否售后
var selectedShops = GlobalConfig.ShopLoginList.Where(a => a.IsSelect).ToList();
if (selectedShops.Count == 0)
{
selectedShops = GlobalConfig.ShopLoginList.ToList();
}
var selectedOrders = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList();
int count = selectedOrders.Count;
if (count > 0 && isAfterSales == false)//非售后订单
{
if (BaseMsgWindow.ShowConfirm($"已选取:{count}个订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return;
BottomMsg = $"订单同步进度....";
int index = 1;
int sucessCount = 0;
int errorCount = 0;
foreach (var item in selectedOrders)
{
var ret = await PullWXOrderService.Instance.PullOrderDetailAsync(item.shop_id, item.order_id); ;
if (ret)
{
sucessCount++;
this.GetOrder(item.order_id);
SetProgress(index, count);
item.IsSelect = false;
}
else
{
errorCount++;
}
BottomMsg = $"订单同步进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}";
index++;
}
BottomMsg = $"订单同步进度完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}";
}
else if (count > 0 && isAfterSales == true)//售后订单
{
if (BaseMsgWindow.ShowConfirm($"已选取:{count}个售后订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return;
//var dictionaryResult = selectedOrders
// .Where(o => o?.refundItems != null)
// .SelectMany(o => o.refundItems
// .Where(item => item != null)
// .Select(item => new { o.shop_id, item.after_sale_order_id }))
// .GroupBy(x => x.shop_id)
// .ToDictionary(
// g => g.Key,
// g => g.Select(x => x.after_sale_order_id).ToArray()
// );
//BottomMsg = $"售后订单同步进度....";
//foreach (var item in dictionaryResult)
//{
// var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(item.Key, item.Value);
//}
//BottomMsg = $"售后同步任务已发送,等待同步完成";
int index = 1;
int sucessCount = 0;
int errorCount = 0;
BottomMsg = $"售后订单同步进度....";
foreach (KeyValuePair<long, List<oms_wei_order_info>> item in selectedOrders.GroupBy(a => a.shop_id).ToDictionary(a => a.Key, a => a.ToList()))
{
long shopid = item.Key;
string shopName = item.Value.FirstOrDefault()?.shop_name ?? "";
string[] afterSaleOrderIds = item.Value.SelectMany(a => a.refundItems).Where(a => a != null).Select(a => a.after_sale_order_id).ToArray();
var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(shopid, afterSaleOrderIds);
if (ret)
{
sucessCount++;
SetProgress(index, count);
item.Value.ForEach(a => a.IsSelect = false);
}
else
{
errorCount++;
}
BottomMsg = $"售后订单同步进度:{index}/{count}\t\t{shopName}";
index++;
}
BottomMsg = $"售后同步任务已发送,等待同步完成";
}
else
{
count = selectedShops.Count;
string prefix = $"已选取:{count}个商铺";
if (count == GlobalConfig.ShopLoginList.Count)
{
prefix = "已选取全部商铺";
}
var startTime = dateStart.SelectedDate.Value;
var endTime = dateEnd.SelectedDate.Value;
string msg = "";
if (isAfterSales)
{
msg = $"{prefix}";
}
else
{
msg = $"{prefix}\n\n时间范围:{startTime.ToString("yyyy-MM-dd")}-{endTime.ToString("yyyy-MM-dd")}";
}
if (BaseMsgWindow.ShowConfirm(msg, $"{(isAfterSales ? "售后" : "")}同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return;
if ((endTime - startTime).Days > 7)
{
throw new Exception("时间范围最大7天");
}
var ret = false;
if (isAfterSales)
{
ret = await PullWXOrderService.Instance.PullRefundOrderByShopsAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime);
}
else
{
ret = await PullWXOrderService.Instance.PullOrderByShopIdsAndTimeRangeAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime);
}
if (ret)
{
BaseMsgWindow.ShowInfo("同步任务已发送,等待同步完成\n任务详情查看任务列表");
}
else
{
BaseMsgWindow.ShowError("同步任务失败");
}
}
}
catch (Exception ex)
{
BaseMsgWindow.ShowError("同步订单失败\n" + ex.Message, "Error");
}
//var service = PullWXOrderService.Instance;
//foreach (var item in list)
//{
// await service.PullOrderDetailAsync(item.shop_id, item.order_id);
//}
}
#endregion
#region 显示任务列表
private DialogWindow _taskDialog;
public ICommand ShowTaskDialogViewCommand => new DelegateCommand(ShowTaskDialogView);
private void ShowTaskDialogView()
{
if (_taskDialog == null)
{
_taskDialog = new DialogWindow()
{
Title = "任务列表",
Content = new OrderTaskDialogView(),
};
_taskDialog.Closed += (s, e) => _taskDialog = null;
}
_taskDialog.Show();
}
#endregion
#region 拼多多发票
public ICommand ShowPDDInvoiceDialogCommand => new DelegateCommand(ShowPDDInvoiceDialog);
private void ShowPDDInvoiceDialog()
{
new DialogWindow
{
Title = "发票助手",
Content = new PDDInvoiceView()
}.ShowDialog();
}
#endregion
}
@@ -25,8 +25,7 @@
<RowDefinition Height="*" />
<RowDefinition Height="18" />
</Grid.RowDefinitions>
<Grid x:Name="gridSearch" Margin="8,0,290,-2">
<Grid x:Name="gridSearch" Margin="8,0,8,-2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1.2*" />
@@ -41,8 +40,11 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="1.4*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
@@ -203,8 +205,7 @@
Padding="4"
Click="btnFilter_Click"
Content="过滤"
Style="{StaticResource BasePageButtonStyle}"
ToolTip="过滤" />
Style="{StaticResource BasePageButtonStyle}" />
<Button
x:Name="btnSearch"
Grid.Column="10"
@@ -273,29 +274,16 @@
IsChecked="true" />
</WrapPanel>
<wpf:SpacingStackPanel Grid.Column="13" HorizontalSpacing="5">
<Button
Width="30"
Height="28"
Padding="4"
HorizontalAlignment="Center"
Command="{Binding ShowShopRevenueStatisticsDialogViewCommand}"
Style="{StaticResource BasePageButtonStyle}"
ToolTip="利润统计">
<TextBlock Style="{StaticResource TextBlockIcon}" Text="{StaticResource txt-data_pie}" />
</Button>
<Button
Width="30"
Height="28"
Padding="4"
HorizontalAlignment="Center"
Command="{Binding ShowPDDInvoiceDialogCommand}"
Style="{StaticResource BasePageButtonStyle}"
ToolTip="发票助手">
<TextBlock Style="{StaticResource TextBlockIcon}" Text="{StaticResource txt-fapiao}" />
</Button>
</wpf:SpacingStackPanel>
<Button
Grid.Column="13"
Width="60"
Height="28"
Padding="4"
HorizontalAlignment="Center"
Click="btn_ShowShopRevenueStatisticsView"
Content="利润统计"
Style="{StaticResource BasePageButtonStyle}" />
</Grid>
<Border
@@ -1947,7 +1947,22 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
FilterOrders();
}
private DialogWindow _statisticsWindow;
private void btn_ShowShopRevenueStatisticsView(object sender, RoutedEventArgs e)
{
if (_statisticsWindow == null)
{
_statisticsWindow = new DialogWindow()
{
Title = "统计",
Content = new ShopRevenueStatisticsView(),
};
_statisticsWindow.Closed += (s, e) => _statisticsWindow = null;
}
_statisticsWindow.Show();
}
/// <summary>
///
@@ -2051,7 +2066,263 @@ namespace _29WxOrderWpf.Ctrls.OrderCtrls
// set => SetProperty(ref _IsShipGift, value);
//}
public ICommand MultipleShipGiftCommand => new AsyncDelegateCommand(MultipleShipGift);
/// <summary>
/// 批量发送礼品单
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async Task MultipleShipGift()
{
try
{
var list = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList();
int count = list.Count;
if (count == 0)
{
BaseMsgWindow.ShowError("请选取要发货的订单", "Error");
return;
}
GiftType giftType = GiftType._160;
if (cb_gift.SelectedIndex == 0)
{
giftType = GiftType._155;
}
else
{
giftType = GiftType._160;
}
int index = 1;
int sucessCount = 0;
int errorCount = 0;
foreach (oms_wei_order_info item in list)
{
try
{
var rst = await WxApiBLL.WxSearchAndDropshipCancelAsync(item.Shop, item);
if (rst == "success")
{
var ret = await _shipGiftService.Send(item.order_id, giftType);
if (ret)
{
sucessCount++;
item.gift_order_status = 1;
this.FilterOneOrder(item, true);
}
else
{
errorCount++;
}
}
else
{
errorCount++;
}
}
catch (Exception ex)
{
errorCount++;
}
finally
{
item.IsSelect = false;
}
SetProgress(index, count);
BottomMsg = $"礼品单发送进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}";
index++;
}
BottomMsg = $"礼品单发送完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}";
}
catch (Exception ex)
{
BaseMsgWindow.ShowError("礼品单发货失败\n" + ex.Message, "Error");
}
finally
{
}
}
/// <summary>
/// 拉取微信订单到任务列表
/// </summary>
public ICommand PullWXOrderCommand => new AsyncDelegateCommand(PullWXOrder);
private async Task PullWXOrder()
{
try
{
var isAfterSales = GlobalConfig.OrderTabHeaderStr.StartsWith("需处理售后单");//是否售后
var selectedShops = GlobalConfig.ShopLoginList.Where(a => a.IsSelect).ToList();
if (selectedShops.Count == 0)
{
selectedShops = GlobalConfig.ShopLoginList.ToList();
}
var selectedOrders = GlobalConfig.lstFilterOrder.Where(a => a.IsSelect).ToList();
int count = selectedOrders.Count;
if (count > 0 && isAfterSales == false)//非售后订单
{
if (BaseMsgWindow.ShowConfirm($"已选取:{count}个订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return;
BottomMsg = $"订单同步进度....";
int index = 1;
int sucessCount = 0;
int errorCount = 0;
foreach (var item in selectedOrders)
{
var ret = await PullWXOrderService.Instance.PullOrderDetailAsync(item.shop_id, item.order_id); ;
if (ret)
{
sucessCount++;
this.GetOrder(item.order_id);
SetProgress(index, count);
item.IsSelect = false;
}
else
{
errorCount++;
}
BottomMsg = $"订单同步进度:{index}/{count}\t\t{item.orderItems.FirstOrDefault()?.title ?? ""}";
index++;
}
BottomMsg = $"订单同步进度完成 成功:{sucessCount} 失败:{errorCount} 总数:{count}";
}
else if (count > 0 && isAfterSales == true)//售后订单
{
if (BaseMsgWindow.ShowConfirm($"已选取:{count}个售后订单", "同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return;
//var dictionaryResult = selectedOrders
// .Where(o => o?.refundItems != null)
// .SelectMany(o => o.refundItems
// .Where(item => item != null)
// .Select(item => new { o.shop_id, item.after_sale_order_id }))
// .GroupBy(x => x.shop_id)
// .ToDictionary(
// g => g.Key,
// g => g.Select(x => x.after_sale_order_id).ToArray()
// );
//BottomMsg = $"售后订单同步进度....";
//foreach (var item in dictionaryResult)
//{
// var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(item.Key, item.Value);
//}
//BottomMsg = $"售后同步任务已发送,等待同步完成";
int index = 1;
int sucessCount = 0;
int errorCount = 0;
BottomMsg = $"售后订单同步进度....";
foreach (KeyValuePair<long, List<oms_wei_order_info>> item in selectedOrders.GroupBy(a => a.shop_id).ToDictionary(a => a.Key, a => a.ToList()))
{
long shopid = item.Key;
string shopName = item.Value.FirstOrDefault()?.shop_name ?? "";
string[] afterSaleOrderIds = item.Value.SelectMany(a => a.refundItems).Where(a => a != null).Select(a => a.after_sale_order_id).ToArray();
var ret = await PullWXOrderService.Instance.PullAfterSaleOrdersAsync(shopid, afterSaleOrderIds);
if (ret)
{
sucessCount++;
SetProgress(index, count);
item.Value.ForEach(a => a.IsSelect = false);
}
else
{
errorCount++;
}
BottomMsg = $"售后订单同步进度:{index}/{count}\t\t{shopName}";
index++;
}
BottomMsg = $"售后同步任务已发送,等待同步完成";
}
else
{
count = selectedShops.Count;
string prefix = $"已选取:{count}个商铺";
if (count == GlobalConfig.ShopLoginList.Count)
{
prefix = "已选取全部商铺";
}
var startTime = dateStart.SelectedDate.Value;
var endTime = dateEnd.SelectedDate.Value;
string msg = "";
if (isAfterSales)
{
msg = $"{prefix}";
}
else
{
msg = $"{prefix}\n\n时间范围:{startTime.ToString("yyyy-MM-dd")}-{endTime.ToString("yyyy-MM-dd")}";
}
if (BaseMsgWindow.ShowConfirm(msg, $"{(isAfterSales ? "售后" : "")}同步订单", MainWindow.Instance, MsgWindowLevel.MEDIUM).DialogResult == false) return;
if ((endTime - startTime).Days > 7)
{
throw new Exception("时间范围最大7天");
}
var ret = false;
if (isAfterSales)
{
ret = await PullWXOrderService.Instance.PullRefundOrderByShopsAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime);
}
else
{
ret = await PullWXOrderService.Instance.PullOrderByShopIdsAndTimeRangeAsync(selectedShops.Select(a => a.ErpShopId.ParseToLong()).ToArray(), startTime, endTime);
}
if (ret)
{
BaseMsgWindow.ShowInfo("同步任务已发送,等待同步完成\n任务详情查看任务列表");
}
else
{
BaseMsgWindow.ShowError("同步任务失败");
}
}
}
catch (Exception ex)
{
BaseMsgWindow.ShowError("同步订单失败\n" + ex.Message, "Error");
}
//var service = PullWXOrderService.Instance;
//foreach (var item in list)
//{
// await service.PullOrderDetailAsync(item.shop_id, item.order_id);
//}
}
private DialogWindow _taskDialog;
public ICommand ShowTaskDialogViewCommand => new DelegateCommand(ShowTaskDialogView);
private void ShowTaskDialogView()
{
if (_taskDialog == null)
{
_taskDialog = new DialogWindow()
{
Title = "任务列表",
Content = new OrderTaskDialogView(),
};
_taskDialog.Closed += (s, e) => _taskDialog = null;
}
_taskDialog.Show();
}
}
public class OrderFilterConfig
@@ -1,800 +0,0 @@
<UserControl
x:Class="_29WxOrderWpf.Ctrls.PDDInvoice.PDDInvoiceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:comm="clr-namespace:_29WxOrderWpf.Common"
xmlns:common="clr-namespace:_29WxOrderWpf.Common"
xmlns:converters="clr-namespace:_29WxOrderWpf.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:_29WxOrderWpf.Ctrls.PDDInvoice.ViewModels"
xmlns:wpf="clr-namespace:WPFCommon.Controls;assembly=WPFCommon"
comm:DialogWindowProperty.ResizeMode="CanResizeWithGrip"
comm:DialogWindowProperty.ShowMinButton="False"
common:DialogWindowProperty.Height="720"
common:DialogWindowProperty.Width="1160"
d:DataContext="{d:DesignInstance Type=vm:PDDInvoiceViewModel,
IsDesignTimeCreatable=True}"
d:DesignHeight="720"
d:DesignWidth="1160"
Background="White"
mc:Ignorable="d">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
<converters:ImageUrlToBitmapImageConverter x:Key="ImageUrlToBitmapImage" />
<converters:InverseVisibleToVisibilityConverter x:Key="InverseBooleanToVisibility" />
<!-- 原型配色 -->
<SolidColorBrush x:Key="PageBgBrush" Color="#F5F6F8" />
<SolidColorBrush x:Key="CardBgBrush" Color="#FFFFFF" />
<SolidColorBrush x:Key="RowBgBrush" Color="#FAFAFA" />
<SolidColorBrush x:Key="SplitLineBrush" Color="#EBEEF5" />
<SolidColorBrush x:Key="InputBorderBrush" Color="#DCDFE6" />
<SolidColorBrush x:Key="PrimaryBrush" Color="#409EFF" />
<SolidColorBrush x:Key="PrimaryHoverBrush" Color="#66B1FF" />
<SolidColorBrush x:Key="TextPrimaryBrush" Color="#333333" />
<SolidColorBrush x:Key="TextNormalBrush" Color="#666666" />
<SolidColorBrush x:Key="TextSecondaryBrush" Color="#909399" />
<SolidColorBrush x:Key="TextPlaceholderBrush" Color="#C0C4CC" />
<SolidColorBrush x:Key="AmountBrush" Color="#F56C6C" />
<SolidColorBrush x:Key="SuccessBrush" Color="#67C23A" />
<SolidColorBrush x:Key="WarningBrush" Color="#E6A23C" />
<!-- 表头单元格 -->
<Style x:Key="HeaderCellTextStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="{StaticResource TextNormalBrush}" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<!-- 搜索 / 表单输入框 -->
<Style x:Key="SearchTextBoxStyle" TargetType="TextBox">
<Setter Property="Height" Value="36" />
<Setter Property="Padding" Value="12,0" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderBrush" Value="{StaticResource InputBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border
x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<ScrollViewer x:Name="PART_ContentHost" Margin="{TemplateBinding Padding}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource PrimaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Opacity" Value="0.6" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 主按钮 -->
<Style x:Key="PrimaryButtonStyle" TargetType="Button">
<Setter Property="Height" Value="36" />
<Setter Property="Padding" Value="18,0" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="{StaticResource PrimaryBrush}" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
x:Name="border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="{StaticResource PrimaryHoverBrush}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Opacity" Value="0.8" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="border" Property="Opacity" Value="0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 默认按钮 -->
<Style x:Key="DefaultButtonStyle" TargetType="Button">
<Setter Property="Height" Value="36" />
<Setter Property="Padding" Value="18,0" />
<Setter Property="Foreground" Value="{StaticResource TextNormalBrush}" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderBrush" Value="{StaticResource InputBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
x:Name="border"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#F5F7FA" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Opacity" Value="0.8" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 文字链接按钮 -->
<Style x:Key="LinkButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{StaticResource PrimaryBrush}" />
<Setter Property="FontSize" Value="13" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{StaticResource PrimaryHoverBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 弹窗遮罩 -->
<Style x:Key="ModalMaskStyle" TargetType="Border">
<Setter Property="Background" Value="#80000000" />
<Setter Property="Panel.ZIndex" Value="100" />
</Style>
<!-- 发票详情 标签 / 值 -->
<Style x:Key="DetailLabelStyle" TargetType="TextBlock">
<Setter Property="Width" Value="100" />
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="{StaticResource TextSecondaryBrush}" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style x:Key="DetailValueStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="{StaticResource TextPrimaryBrush}" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</UserControl.Resources>
<Border Padding="10,10,10,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<!-- 功能区域 -->
<Border Grid.Row="0">
<wpf:SpacingStackPanel Background="{StaticResource CardBgBrush}" HorizontalSpacing="10">
<Grid Width="300">
<TextBox
x:Name="txtSearch"
Height="30"
Padding="5,0,0,0"
KeyDown="txtSearch_KeyDown"
Style="{StaticResource SearchTextBoxStyle}"
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock
Padding="12,0,0,0"
VerticalAlignment="Center"
FontSize="13"
Foreground="{StaticResource TextPlaceholderBrush}"
IsHitTestVisible="False"
Text="请输入订单号 / 商品名称"
Visibility="{Binding Text, ElementName=txtSearch, Converter={StaticResource NotHasTextVisibility}}" />
</Grid>
<Button
Width="50"
Height="30"
Command="{Binding SearchCommand}"
Content="搜索"
Style="{StaticResource BasePageButtonStyle}" />
<Button
Height="30"
Command="{Binding ResetCommand}"
Content="重置"
Style="{StaticResource DefaultButtonStyle}" />
<wpf:TitleContent
Title="买手号:"
Placement="Left"
TitleVerticalAlignment="Center">
<ComboBox
Width="150"
Height="28"
DisplayMemberPath="buyer_nick"
ItemsSource="{Binding BuyerLoginList}"
SelectedItem="{Binding SelectedBuyer}"
Style="{StaticResource RoundedComboBox}" />
</wpf:TitleContent>
<Button
Height="30"
Padding="5,0"
Command="{Binding ReadOrderCommand}"
Content="读取订单"
Style="{StaticResource BasePageButtonStyle}" />
</wpf:SpacingStackPanel>
</Border>
<!-- 订单列表(已移除分页与订单分组) -->
<Border
Grid.Row="1"
Height="Auto"
Margin="0,10,0,0"
VerticalAlignment="Stretch"
Background="{StaticResource CardBgBrush}"
CornerRadius="6">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- 表头 -->
<Border
Grid.Row="0"
Padding="20,14"
Background="{StaticResource RowBgBrush}"
BorderBrush="{StaticResource SplitLineBrush}"
BorderThickness="0,0,0,1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1.2*" />
<ColumnDefinition Width="1.5*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0"
Style="{StaticResource HeaderCellTextStyle}"
Text="商品信息" />
<TextBlock
Grid.Column="2"
Style="{StaticResource HeaderCellTextStyle}"
Text="数量" />
<TextBlock
Grid.Column="3"
Style="{StaticResource HeaderCellTextStyle}"
Text="实付金额" />
<TextBlock
Grid.Column="4"
Style="{StaticResource HeaderCellTextStyle}"
Text="发票" />
<TextBlock
Grid.Column="5"
Style="{StaticResource HeaderCellTextStyle}"
Text="操作" />
</Grid>
</Border>
<Grid Grid.Row="1">
<Border Background="White">
<!-- 列表(虚拟化滚动加载) -->
<ItemsControl
Margin="0,2,0,-2"
Padding="0"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding Orders}">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<ScrollViewer
CanContentScroll="True"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel
CacheLength="1,1"
CacheLengthUnit="Page"
IsVirtualizing="True"
ScrollUnit="Pixel"
VirtualizationMode="Recycling" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="{StaticResource SplitLineBrush}" BorderThickness="0,0,0,1">
<StackPanel>
<!-- 订单信息栏 -->
<Border Padding="20,12" Background="{StaticResource RowBgBrush}">
<StackPanel Orientation="Horizontal">
<TextBlock
FontSize="12"
Foreground="{StaticResource TextNormalBrush}"
Text="{Binding order_sn, StringFormat=订单号:{0}}" />
<TextBlock
Margin="28,0,0,0"
FontSize="12"
Foreground="{StaticResource TextNormalBrush}"
Text="{Binding OrderTime, StringFormat=下单时间:{0:yyyy-MM-dd}}" />
<TextBlock
Margin="28,0,0,0"
FontSize="12"
Foreground="{StaticResource TextNormalBrush}"
Text="{Binding order_status_prompt}" />
</StackPanel>
</Border>
<!-- 订单内容 -->
<Border Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1.2*" />
<ColumnDefinition Width="1.5*" />
</Grid.ColumnDefinitions>
<!-- 商品 -->
<Grid Grid.Column="0" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="72" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border
Width="72"
Height="72"
Background="#EEEEEE"
CornerRadius="5">
<Image Source="{Binding ThumbUrl, Converter={StaticResource ImageUrlToBitmapImage}, IsAsync=True}" Stretch="UniformToFill" />
</Border>
<StackPanel
Grid.Column="1"
Margin="14,0,0,0"
VerticalAlignment="Center">
<TextBlock
MaxHeight="44"
FontSize="14"
Foreground="{StaticResource TextPrimaryBrush}"
LineHeight="22"
Text="{Binding GoodsName}"
TextTrimming="CharacterEllipsis"
TextWrapping="Wrap" />
</StackPanel>
</Grid>
<!-- 数量 -->
<TextBlock
Grid.Column="2"
VerticalAlignment="Center"
FontSize="13"
Foreground="{StaticResource TextPrimaryBrush}"
Text="{Binding Quantity, StringFormat=×{0}}" />
<!-- 实付金额 -->
<TextBlock
Grid.Column="3"
VerticalAlignment="Center"
FontSize="16"
FontWeight="SemiBold"
Foreground="{StaticResource AmountBrush}"
Text="{Binding DisplayAmount}" />
<!-- 发票 -->
<StackPanel Grid.Column="4" VerticalAlignment="Center">
<TextBlock FontSize="13" Text="{Binding InvoiceStatusText}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource WarningBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsInvoiced}" Value="True">
<Setter Property="Foreground" Value="{StaticResource SuccessBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
<!-- 操作 -->
<StackPanel Grid.Column="5" VerticalAlignment="Center">
<Button
d:Visibility="Visible"
Command="{Binding DataContext.ShowInvoiceCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}"
Content="查看发票"
Style="{StaticResource LinkButtonStyle}"
Visibility="{Binding IsInvoiced, Converter={StaticResource BooleanToVisibility}}" />
<Button
Margin="0,5"
Command="{Binding DataContext.OpenInvoiceCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}"
Content="申请开票"
Style="{StaticResource LinkButtonStyle}"
Visibility="{Binding IsInvoiced, Converter={StaticResource InverseBooleanToVisibility}}" />
<Button
Command="{Binding DataContext.ViewOrderCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding}"
Content="查看订单"
Style="{StaticResource LinkButtonStyle}" />
</StackPanel>
</Grid>
</Border>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
<Border
Grid.Row="1"
Panel.ZIndex="{Binding BrowserZIndex}"
d:Panel.ZIndex="-10"
Style="{StaticResource ModalMaskStyle}">
<Grid>
<ContentControl
Grid.Row="0"
Width="400"
Height="600"
Background="White"
Content="{Binding Browser}" />
<StackPanel
Grid.Row="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button
Command="{Binding CloseOrderBrowserCommand}"
Content="隐藏"
Style="{StaticResource DefaultButtonStyle}" />
</StackPanel>
</Grid>
</Border>
<Border
Grid.Row="1"
Panel.ZIndex="{Binding BrowserDetailZIndex}"
d:Panel.ZIndex="-10"
Style="{StaticResource ModalMaskStyle}">
<Grid>
<!--<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>-->
<ContentControl
Grid.Row="0"
Width="400"
Height="600"
Background="White"
Content="{Binding BrowserDetail}" />
<StackPanel
Grid.Row="1"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Orientation="Horizontal">
<Button
Command="{Binding CloseInvoiceDetailCommand}"
Content="关闭"
Style="{StaticResource DefaultButtonStyle}" />
</StackPanel>
</Grid>
</Border>
</Grid>
</Grid>
</Border>
<Grid
Grid.Row="2"
Margin="-10,0"
Background="{StaticResource pageColorBrush}">
<ProgressBar
VerticalAlignment="Stretch"
d:IsIndeterminate="False"
d:Maximum="100"
d:Value="10"
Background="Transparent"
BorderThickness="0"
Foreground="#FFA680"
Maximum="{Binding ProgressMaximum}"
Value="{Binding ProgressValue}" />
<Grid Margin="10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="100*" />
</Grid.ColumnDefinitions>
<TextBox
Grid.Row="2"
Grid.Column="1"
Margin="4,0,0,0"
VerticalAlignment="Center"
d:Text="共计:{}"
Background="Transparent"
BorderThickness="0"
Foreground="White"
IsReadOnly="True"
Text="{Binding BottomMsg}" />
</Grid>
<Button
HorizontalAlignment="Right"
Background="Transparent"
Command="{Binding ShowTaskDialogViewCommand}"
Foreground="White"
ToolTip="任务列表">
<Button.Content>
<TextBlock Style="{StaticResource TextBlockIcon}" Text="{StaticResource txt-task_list_square_ltr}" />
</Button.Content>
</Button>
</Grid>
<!-- 开票弹窗 -->
<!--<Border
Grid.RowSpan="3"
Style="{StaticResource ModalMaskStyle}"
Visibility="{Binding IsInvoiceDialogOpen, Converter={StaticResource BooleanToVisibility}}">
<Border
Width="520"
Padding="24"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
CornerRadius="8">
<StackPanel>
<TextBlock
Margin="0,0,0,24"
FontSize="18"
FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}"
Text="开具发票" />
<Grid Margin="0,0,0,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
VerticalAlignment="Center"
FontSize="13"
Foreground="{StaticResource TextNormalBrush}"
Text="订单号" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
FontSize="13"
Foreground="{StaticResource TextPrimaryBrush}"
Text="{Binding SelectedOrder.order_sn}" />
</Grid>
<Grid Margin="0,0,0,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
VerticalAlignment="Center"
FontSize="13"
Foreground="{StaticResource TextNormalBrush}"
Text="发票类型" />
<ComboBox
Grid.Column="1"
Height="36"
Padding="10,0"
VerticalContentAlignment="Center"
FontSize="13"
SelectedValue="{Binding InvoiceType}"
SelectedValuePath="Content">
<ComboBoxItem Content="电子普通发票" />
<ComboBoxItem Content="增值税专用发票" />
</ComboBox>
</Grid>
<Grid Margin="0,0,0,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
VerticalAlignment="Center"
FontSize="13"
Foreground="{StaticResource TextNormalBrush}"
Text="发票抬头" />
<TextBox
Grid.Column="1"
Style="{StaticResource SearchTextBoxStyle}"
Text="{Binding InvoiceTitle}" />
</Grid>
<Grid Margin="0,0,0,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
VerticalAlignment="Center"
FontSize="13"
Foreground="{StaticResource TextNormalBrush}"
Text="税号" />
<TextBox
Grid.Column="1"
Style="{StaticResource SearchTextBoxStyle}"
Text="{Binding TaxNo}" />
</Grid>
<StackPanel
Margin="0,25,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Command="{Binding CloseInvoiceDialogCommand}"
Content="取消"
Style="{StaticResource DefaultButtonStyle}" />
<Button
Margin="10,0,0,0"
Command="{Binding ConfirmInvoiceCommand}"
Content="确认开票"
Style="{StaticResource PrimaryButtonStyle}" />
</StackPanel>
</StackPanel>
</Border>
</Border>-->
<!-- 发票信息弹窗 -->
<!--<Border
Grid.RowSpan="3"
Style="{StaticResource ModalMaskStyle}"
Visibility="{Binding IsInvoiceDetailOpen, Converter={StaticResource BooleanToVisibility}}">
<Border
Width="520"
Padding="24"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
CornerRadius="8">
<StackPanel>
<TextBlock
Margin="0,0,0,24"
FontSize="18"
FontWeight="SemiBold"
Foreground="{StaticResource TextPrimaryBrush}"
Text="发票信息" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
Style="{StaticResource DetailLabelStyle}"
Text="订单号:" />
<TextBlock
Grid.Row="0"
Grid.Column="1"
Style="{StaticResource DetailValueStyle}"
Text="{Binding SelectedOrder.OrderNo}" />
<TextBlock
Grid.Row="1"
Style="{StaticResource DetailLabelStyle}"
Text="发票类型:" />
<TextBlock
Grid.Row="1"
Grid.Column="1"
Style="{StaticResource DetailValueStyle}"
Text="{Binding SelectedOrder.InvoiceType}" />
<TextBlock
Grid.Row="2"
Style="{StaticResource DetailLabelStyle}"
Text="发票号码:" />
<TextBlock
Grid.Row="2"
Grid.Column="1"
Style="{StaticResource DetailValueStyle}"
Text="{Binding SelectedOrder.InvoiceNo}" />
<TextBlock
Grid.Row="3"
Style="{StaticResource DetailLabelStyle}"
Text="发票抬头:" />
<TextBlock
Grid.Row="3"
Grid.Column="1"
Style="{StaticResource DetailValueStyle}"
Text="{Binding SelectedOrder.InvoiceTitle}" />
<TextBlock
Grid.Row="4"
Style="{StaticResource DetailLabelStyle}"
Text="税号:" />
<TextBlock
Grid.Row="4"
Grid.Column="1"
Style="{StaticResource DetailValueStyle}"
Text="{Binding SelectedOrder.TaxNo}" />
<TextBlock
Grid.Row="5"
Style="{StaticResource DetailLabelStyle}"
Text="开票金额:" />
<TextBlock
Grid.Row="5"
Grid.Column="1"
Style="{StaticResource DetailValueStyle}"
Text="{Binding SelectedOrder.InvoiceAmountText}" />
<TextBlock
Grid.Row="6"
Style="{StaticResource DetailLabelStyle}"
Text="开票时间:" />
<TextBlock
Grid.Row="6"
Grid.Column="1"
Style="{StaticResource DetailValueStyle}"
Text="{Binding SelectedOrder.InvoiceTime}" />
</Grid>
<StackPanel
Margin="0,25,0,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
Command="{Binding CloseInvoiceDetailCommand}"
Content="关闭"
Style="{StaticResource DefaultButtonStyle}" />
</StackPanel>
</StackPanel>
</Border>
</Border>-->
</Grid>
</Border>
</UserControl>
@@ -1,37 +0,0 @@
using _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace _29WxOrderWpf.Ctrls.PDDInvoice;
/// <summary>
/// PDDInvoiceView.xaml 的交互逻辑
/// </summary>
public partial class PDDInvoiceView : UserControl
{
public PDDInvoiceView()
{
InitializeComponent();
DataContext = new PDDInvoiceViewModel();
}
private void txtSearch_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter && DataContext is PDDInvoiceViewModel viewModel)
{
viewModel.SearchCommand.Execute(null);
}
}
}
@@ -1,70 +0,0 @@
using AllBase.Model.Result;
using System;
using System.Collections.Generic;
using System.Linq;
using WPFCommon.Helpers;
using WPFCommon.Models;
namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels;
/// <summary>
/// 订单发票Model
/// </summary>
public class PddBrowserOrderInvoiceViewModel : BindableBaseEx
{
public string buyerId { get; set; } // 买手Id
public string buyerName { get; set; } // 买手名称
/// <summary>
/// 订单价
/// </summary>
public int order_amount { get; set; }
/// <summary>
/// 实付款
/// </summary>
public string display_amount { get; set; }
/// <summary>
/// 下单时间
/// </summary>
public long order_time { get; set; }
/// <summary>
/// 订单号
/// </summary>
public string order_sn { get; set; }
public int status { get; set; }
public int pay_status { get; set; }
public string order_status_prompt { get; set; }
public List<order_good> order_Goods { get; set; }
public List<OrderButtonItem> order_buttons { get; set; }
public string GoodsName { get => order_Goods?.FirstOrDefault()?.goods_name ?? ""; }
public bool IsInvoiced
{
get => order_buttons?.Any(a => a.button_code == 500) ?? false;
}
public int Quantity => order_Goods?.Sum(a => a.goods_number.Value) ?? 0;
/// <summary> 发票状态文案:已开票 / 待开票 </summary>
public string InvoiceStatusText => IsInvoiced ? "已开票" : "待开票";
public DateTime OrderTime
{
get => DateTimeHelper.ConvertFromUnixTimestampInSeconds(order_time);
}
public string ThumbUrl=> order_Goods?.FirstOrDefault()?.thumb_url ?? "";
public string DisplayAmount => (order_amount / 100.0).ToString("F2");
}
public class OrderButtonItem
{
public int button_code { get; set; }
public string brief_prompt { get; set; }
public ButtonTypeValue type_value { get; set; }
}
public class ButtonTypeValue
{
public string Url { get; set; }
}
@@ -1,168 +0,0 @@
using _29WxOrderWpf.CefHelper;
using _29WxOrderWpf.Commands;
using AllBase;
using CefSharp;
using CefSharp.Handler;
using CefSharp.Wpf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Work._29Tools.CefTools;
namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels;
public partial class PDDInvoiceViewModel
{
/// <summary>
/// 订单列表浏览器
/// </summary>
public ChromiumWebBrowser Browser { get; private set; }
/// <summary>
/// 内容浏览器
/// 订单详情
/// 发票详情
/// 申请发票
/// </summary>
public ChromiumWebBrowser BrowserDetail { get; private set; }
partial void InitBrowser()
{
BrowserZIndex = -1;
BrowserDetailZIndex = -1;
Browser = WPFCEFBrowser.CreateChromiumWebBrowser("about:blank", false);
LocalResourceRequestHandler resourceRequestHandler = new LocalResourceRequestHandler();
//resourceRequestHandler.BeforeResourceLoadEvent += RequestHandler_BeforeResourceLoad;
resourceRequestHandler.ResourceLoadCompleteEvent += RequestHandler_ResourceLoadComplete;
Browser.RequestHandler = new LocalRequestHandler(resourceRequestHandler);
Browser.LifeSpanHandler = new LocalLifeSpanHandler(PopWindowType.SelfWindow);
Browser.KeyboardHandler = new KeyboardHandler();
BrowserDetail = WPFCEFBrowser.CreateChromiumWebBrowser("about:blank", false);
LocalResourceRequestHandler detailResourceRequestHandler = new LocalResourceRequestHandler();
detailResourceRequestHandler.ResourceLoadCompleteEvent += DetailRequestHandler_ResourceLoadComplete;
BrowserDetail.RequestHandler = new LocalRequestHandler(resourceRequestHandler);
BrowserDetail.LifeSpanHandler = new LocalLifeSpanHandler(PopWindowType.SelfWindow);
BrowserDetail.KeyboardHandler = new KeyboardHandler();
}
public ICommand CloseOrderBrowserCommand => new DelegateCommand(HidenOrderBrowser);
public ICommand CloseInvoiceDetailCommand => new DelegateCommand(HidenOrderBrowserDetail);
public int BrowserZIndex
{
get => GetValue<int>();
set => SetValue(value);
}
public int BrowserDetailZIndex
{
get => GetValue<int>();
set => SetValue(value);
}
/// <summary>
/// 显示主浏览器
/// </summary>
public void ShowOrderBrowser()
{
BrowserZIndex = 10;
BrowserDetailZIndex = -1;
}
/// <summary>
/// 显示子浏览器
/// </summary>
public void ShowOrderBrowserDetail()
{
BrowserZIndex = -1;
BrowserDetailZIndex = 10;
}
public void HidenOrderBrowser()
{
BrowserZIndex = -1;
}
public void HidenOrderBrowserDetail()
{
BrowserDetailZIndex = -1;
}
public bool IsAutoScroll
{
get => GetValue<bool>();
set => SetValue(value);
}
private int top = 0;
private DateTime lastGetOrderDataTime = DateTime.Now;
private void RequestHandler_ResourceLoadComplete(object sender, string url, string postData, string responseData, IRequest request)
{
if (url.StartsWith("https://mobile.yangkeduo.com/orders.html"))
{
//if (isAutoScroll == false)
//{
// StartAutoScroll();
//}
StartAutoScroll();
}
if (url.StartsWith("https://mobile.yangkeduo.com/proxy/api/api/aristotle/order_list_v"))
{
lastGetOrderDataTime = DateTime.Now;
parserData(responseData);
//File.WriteAllText(@$"E:\{Guid.NewGuid().ToString()}.txt", responseData);
}
}
public void StartAutoScroll()
{
if (IsAutoScroll) return;
IsAutoScroll = true;
_cancellationTokenSource = new CancellationTokenSource();
_ = autoScroll(_cancellationTokenSource.Token);
}
// 停止滚动
public void StopAutoScroll()
{
IsAutoScroll = false;
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
}
private async Task autoScroll(CancellationToken token)
{
while (IsAutoScroll && !token.IsCancellationRequested)
{
if ((DateTime.Now - lastGetOrderDataTime).Seconds > 30) StopAutoScroll();
top += Randomx.GetId(450, 600);
var jsStr = @"window.scroll({
top: " + top + @",
left: 0,
behavior: 'smooth' // 可选,使滚动平滑
});";
var client = Browser.GetDevToolsClient();
if (client != null)
{
var result = client.Runtime.EvaluateAsync(jsStr, null, true, null, null, true, null, true);
result.Wait(5000);
}
await Task.Delay(Randomx.GetId(100, 300));
//Thread.Sleep();
}
}
private void DetailRequestHandler_ResourceLoadComplete(object sender, string url, string postData, string responseData, IRequest request)
{
if (url.StartsWith("https://mobile.yangkeduo.com/transac_return_compensation.html"))
{
}
}
}
@@ -1,391 +0,0 @@
using _29WxOrderWpf.CefHelper;
using _29WxOrderWpf.Commands;
using AllBase;
using AllBase.Helper;
using AllBase.Model.DBModel;
using AllBase.Model.Result;
using AllBase.Util;
using CefSharp;
using CefSharp.Handler;
using CefSharp.Wpf;
using NaiBa.Util.Extension;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using Work._29Tools.CefTools;
using WPFCommon.Models;
namespace _29WxOrderWpf.Ctrls.PDDInvoice.ViewModels;
/// <summary>
/// 拼多多发票助手 视图模型
/// </summary>
public partial class PDDInvoiceViewModel : BindableBaseEx
{
private readonly ObservableCollection<PddBrowserOrderInvoiceViewModel> _allOrders = new();
private readonly HashSet<string> _orderSns = new();
private string _searchText = "";
private PddBrowserOrderInvoiceViewModel _selectedOrder;
private bool _isInvoiceDialogOpen;
private bool _isInvoiceDetailOpen;
private string _invoiceType = "电子普通发票";
private string _invoiceTitle = "XX科技有限公司";
private string _taxNo = "91110000XXXXXXXXXX";
private CancellationTokenSource _cancellationTokenSource; public PDDInvoiceViewModel()
{
Orders = new ObservableCollection<PddBrowserOrderInvoiceViewModel>();
BuyerLoginList = GlobalConfig.PDDBuyerLoginList;
//Orders = new ObservableCollection<PDDInvoiceOrderModel>(_allOrders);
//_ = InitSampleData();
InitBrowser();
}
partial void InitBrowser();
private void parserData(string data)
{
List<PddBrowserOrderInvoiceViewModel> list = JsonHelper.DeserializeJsonToList<PddBrowserOrderInvoiceViewModel>(JsonHelper.JObjectParse(data)["orders"].ParseToString());
if (list.Count == 0)
{
StopAutoScroll();
return;
}
var matched = list.Where(item => item.status == 4 && item.pay_status == 2).ToList();
if (matched.Count == 0)
{
return;
}
// CEF 回调运行在后台线程,ObservableCollection 的更新需要切回 UI 线程
var dispatcher = Application.Current?.Dispatcher;
if (dispatcher == null || dispatcher.CheckAccess())
{
AddOrders(matched);
}
else
{
dispatcher.BeginInvoke(new Action(() => AddOrders(matched)));
}
}
/// <summary> 将新订单写入总表,并按当前搜索关键字决定是否加入可见列表(自动去重) </summary>
private void AddOrders(IEnumerable<PddBrowserOrderInvoiceViewModel> items)
{
var keyword = SearchText?.Trim();
foreach (var item in items)
{
if (!string.IsNullOrEmpty(item.order_sn) && !_orderSns.Add(item.order_sn))
{
continue;
}
_allOrders.Add(item);
if (IsKeywordMatch(item, keyword))
{
Orders.Add(item);
}
}
}
public ObservableCollectionThreadSafe<BuyerLoginInfo> BuyerLoginList { get; set; } = new ObservableCollectionThreadSafe<BuyerLoginInfo>();
public BuyerLoginInfo SelectedBuyer
{
get => GetProperty(() => SelectedBuyer);
set => SetProperty(() => SelectedBuyer, value, SelectedBuyerChanged);
}
private void SelectedBuyerChanged()
{
WPFCEFBrowser.SetCookieAsync(SelectedBuyer.cookie, Browser.GetCookieManager()).GetAwaiter();
WPFCEFBrowser.SetCookieAsync(SelectedBuyer.cookie, BrowserDetail.GetCookieManager()).GetAwaiter();
}
/// <summary> 订单列表 </summary>
public ObservableCollection<PddBrowserOrderInvoiceViewModel> Orders { get; }
/// <summary> 搜索关键字:订单号 / 商品名称 / 买家 </summary>
public string SearchText
{
get => _searchText;
set => SetProperty(ref _searchText, value, nameof(SearchText));
}
/// <summary> 开票弹窗是否打开 </summary>
public bool IsInvoiceDialogOpen
{
get => _isInvoiceDialogOpen;
set => SetProperty(ref _isInvoiceDialogOpen, value, nameof(IsInvoiceDialogOpen));
}
/// <summary> 发票详情弹窗是否打开 </summary>
public bool IsInvoiceDetailOpen
{
get => _isInvoiceDetailOpen;
set => SetProperty(ref _isInvoiceDetailOpen, value, nameof(IsInvoiceDetailOpen));
}
/// <summary> 当前操作的订单 </summary>
public PddBrowserOrderInvoiceViewModel SelectedOrder
{
get => _selectedOrder;
set => SetProperty(ref _selectedOrder, value, nameof(SelectedOrder));
}
/// <summary> 开票类型 </summary>
public string InvoiceType
{
get => _invoiceType;
set => SetProperty(ref _invoiceType, value, nameof(InvoiceType));
}
/// <summary> 发票抬头 </summary>
public string InvoiceTitle
{
get => _invoiceTitle;
set => SetProperty(ref _invoiceTitle, value, nameof(InvoiceTitle));
}
/// <summary> 税号 </summary>
public string TaxNo
{
get => _taxNo;
set => SetProperty(ref _taxNo, value, nameof(TaxNo));
}
public ICommand SearchCommand => new DelegateCommand(Search);
public ICommand ResetCommand => new DelegateCommand(ResetSearch);
public ICommand OpenInvoiceCommand => new DelegateCommand<PddBrowserOrderInvoiceViewModel>(OpenInvoice);
public ICommand ShowInvoiceCommand => new DelegateCommand<PddBrowserOrderInvoiceViewModel>(ShowInvoice);
public ICommand ViewOrderCommand => new DelegateCommand<PddBrowserOrderInvoiceViewModel>(ViewOrder);
public ICommand CloseInvoiceDialogCommand => new DelegateCommand(() => IsInvoiceDialogOpen = false);
public ICommand ConfirmInvoiceCommand => new DelegateCommand(ConfirmInvoice);
public ICommand ReadOrderCommand => new DelegateCommand(ReadOrder, () => !IsAutoScroll);
private void ReadOrder()
{
Browser.Load("https://mobile.yangkeduo.com/orders.html");
ShowOrderBrowser();
}
/// <summary> 按 订单号 / 商品名称 过滤订单 </summary>
private void Search()
{
var keyword = SearchText?.Trim();
Orders.Clear();
foreach (var order in _allOrders.Where(o => IsKeywordMatch(o, keyword)))
{
Orders.Add(order);
}
}
private static bool IsKeywordMatch(PddBrowserOrderInvoiceViewModel order, string keyword)
{
return string.IsNullOrEmpty(keyword)
|| (!string.IsNullOrEmpty(order.order_sn) && order.order_sn.Contains(keyword))
|| (!string.IsNullOrEmpty(order.GoodsName) && order.GoodsName.Contains(keyword));
}
private void ResetSearch()
{
SearchText = "";
Search();
}
private void OpenInvoice(PddBrowserOrderInvoiceViewModel order)
{
SelectedOrder = order;
BrowserDetail.Load($"https://mobile.yangkeduo.com/transac_return_compensation.html?_t_timestamp=transac_modify_invoice&order_sn={order.order_sn}");
ShowOrderBrowserDetail();
//InvoiceType = string.IsNullOrEmpty(order.InvoiceType) ? "电子普通发票" : order.InvoiceType;
//InvoiceTitle = string.IsNullOrEmpty(order.InvoiceTitle) ? "XX科技有限公司" : order.InvoiceTitle;
//TaxNo = string.IsNullOrEmpty(order.TaxNo) ? "91110000XXXXXXXXXX" : order.TaxNo;
//IsInvoiceDialogOpen = true;
}
private void ConfirmInvoice()
{
if (SelectedOrder == null)
return;
//SelectedOrder.IsInvoiced = true;
//SelectedOrder.InvoiceType = InvoiceType;
//SelectedOrder.InvoiceTitle = InvoiceTitle;
//SelectedOrder.TaxNo = TaxNo;
//SelectedOrder.InvoiceNo = "25" + DateTime.Now.ToString("MMddHHmmss");
//SelectedOrder.InvoiceAmountText = SelectedOrder.AmountText;
//SelectedOrder.InvoiceTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
IsInvoiceDialogOpen = false;
//MessageBox.Show($"订单 {SelectedOrder.OrderNo} 开票成功");
}
private void ShowInvoice(PddBrowserOrderInvoiceViewModel order)
{
SelectedOrder = order;
IsInvoiceDetailOpen = true;
}
private void ViewOrder(PddBrowserOrderInvoiceViewModel order)
{
//MessageBox.Show($"查看订单:{order.OrderNo}");
}
/// <summary>
/// 原型演示数据(后续可替换为真实接口数据)
/// </summary>
private Task InitSampleData()
{
string directoryPath = @"E:\820";
// 3. 获取所有 txt 文件
var txtFiles = Directory.GetFiles(directoryPath, "*.txt");
if (txtFiles.Length == 0)
{
Console.WriteLine("未找到任何 .txt 文件");
return Task.CompletedTask;
}
foreach (var filePath in txtFiles)
{
try
{
string jsonContent = File.ReadAllText(filePath);
parserData(jsonContent);
}
catch (Exception ex)
{
}
}
return Task.CompletedTask;
}
#region 进度条
private string _bottomMsg = "";
public string BottomMsg
{
get => _bottomMsg;
set => SetValue(ref _bottomMsg, value);
}
private double _progressValue;
public double ProgressValue
{
get => _progressValue;
set => SetValue(ref _progressValue, value);
}
private double _progressMaximum = 100;
public double ProgressMaximum
{
get => _progressMaximum;
set => SetValue(ref _progressMaximum, value);
}
public void SetProgress(int value, int maxValue)
{
StopUnknownTotalProgressTimer();
ProgressValue = value;
ProgressMaximum = maxValue;
}
#region 未知总数百分比模拟进度
private System.Threading.Timer _unknownTotalProgressTimer;
private DateTime _unknownTotalProgressStartTime;
/// <summary>
/// 开始未知总数的百分比模拟进度:80% 之前走得快,越到最后走得越慢,
/// 理论上永远走不到 95% 以上,直到调用 <see cref="CompleteProgress"/> 才会变成 100%。
/// </summary>
public void StartProgress()
{
StopUnknownTotalProgressTimer();
ProgressMaximum = 100;
ProgressValue = 0;
_unknownTotalProgressStartTime = DateTime.Now;
_unknownTotalProgressTimer = new System.Threading.Timer(_ => UpdateUnknownTotalProgress(), null, 0, 200);
}
/// <summary>
/// 结束进度:停止模拟,进度条立即变为 100%。
/// </summary>
public void CompleteProgress()
{
StopUnknownTotalProgressTimer();
ProgressMaximum = 100;
ProgressValue = 100;
}
private void UpdateUnknownTotalProgress()
{
try
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
var elapsed = (DateTime.Now - _unknownTotalProgressStartTime).TotalSeconds;
double progress;
if (elapsed <= 10)
{
// 前 10 秒内快速推进到 80%
progress = Math.Max(0, Math.Min(80, elapsed * 8));
}
else
{
// 超过 80% 后指数衰减越来越慢,渐近线为 95%,理论上永远走不到 95% 以上
progress = 95.0 - 15.0 * Math.Exp(-(elapsed - 10.0) / 20.0);
}
if (progress > 95) progress = 95;
ProgressValue = progress;
}));
}
catch
{
}
}
private void StopUnknownTotalProgressTimer()
{
if (_unknownTotalProgressTimer == null) return;
try
{
_unknownTotalProgressTimer.Dispose();
}
catch
{
}
_unknownTotalProgressTimer = null;
}
#endregion
#endregion
}
@@ -122,7 +122,7 @@
</UserControl.Resources>
<Grid Background="#F5F7FB">
<TabControl SelectionChanged="TabControl_SelectionChanged" Style="{StaticResource StatisticsTabControlStyle}">
<TabControl Style="{StaticResource StatisticsTabControlStyle}" SelectionChanged="TabControl_SelectionChanged">
<TabItem Header="综合统计" Style="{StaticResource StatisticsTabItemStyle}">
<ScrollViewer
wpf:ScrollViewerBehavior.FixMouseWheel="True"
@@ -283,19 +283,12 @@
BorderThickness="1"
Cursor="Hand"
MouseLeftButtonDown="help_mouseLeftButtonDown">
<WrapPanel>
<TextBlock
Margin="0,0,10,0"
Foreground="White"
Style="{StaticResource TextBlockIcon}"
Text="{StaticResource txt-chat_help}" />
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Black"
Foreground="White"
Text="利润计算逻辑" />
</WrapPanel>
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="Black"
Foreground="White"
Text="利润计算逻辑" />
</Border>
<!-- Popup 弹出层 -->
@@ -314,13 +307,11 @@
Margin="0,-10,-10,0"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
Click="close"
Background="Transparent" Click="close"
Content="x" />
<TextBlock
<TextBlock Margin="0,10,0,0"
x:Name="PopupText"
MaxWidth="500"
Margin="0,10,0,0"
FontSize="16"
Foreground="White"
LineHeight="25"