39 changed files with 1464 additions and 79 deletions
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace BBWY.Client.Models |
||||
|
{ |
||||
|
public class StoreResponse |
||||
|
{ |
||||
|
public DateTime? CreateTime { get; set; } |
||||
|
public string Id { get; set; } |
||||
|
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public Platform Platform { get; set; } |
||||
|
|
||||
|
public StockStatus Status { get; set; } |
||||
|
|
||||
|
public StockType Type { get; set; } |
||||
|
} |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
using System.Collections.ObjectModel; |
||||
|
|
||||
|
namespace BBWY.Client.Models.QiKu |
||||
|
{ |
||||
|
public class PackSkuConfig : NotifyObject |
||||
|
{ |
||||
|
public PackSkuConfig() |
||||
|
{ |
||||
|
PackSkuSplitConfigList = new ObservableCollection<PackSkuSplitConfig>(); |
||||
|
} |
||||
|
|
||||
|
private int splitCount; |
||||
|
private string remarkMessage; |
||||
|
|
||||
|
public string SkuId { get; set; } |
||||
|
|
||||
|
public string Logo { get; set; } |
||||
|
|
||||
|
public string Title { get; set; } |
||||
|
|
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购数量
|
||||
|
/// </summary>
|
||||
|
public int PurchaseCount { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 分箱数量
|
||||
|
/// </summary>
|
||||
|
public int SplitCount { get => splitCount; set { Set(ref splitCount, value); } } |
||||
|
|
||||
|
public string RemarkMessage { get => remarkMessage; set { Set(ref remarkMessage, value); } } |
||||
|
|
||||
|
public ObservableCollection<PackSkuSplitConfig> PackSkuSplitConfigList { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class PackSkuSplitConfig : NotifyObject |
||||
|
{ |
||||
|
private int packCount; |
||||
|
private StoreResponse store; |
||||
|
|
||||
|
public int Index { get; set; } |
||||
|
|
||||
|
public int PackCount { get => packCount; set { Set(ref packCount, value); } } |
||||
|
|
||||
|
public StoreResponse Store { get => store; set { Set(ref store, value); } } |
||||
|
} |
||||
|
} |
@ -0,0 +1,105 @@ |
|||||
|
using BBWY.Client.APIServices; |
||||
|
using BBWY.Client.Models; |
||||
|
using BBWY.Client.Models.QiKu; |
||||
|
using BBWY.Client.Views.BatchPurchase; |
||||
|
using GalaSoft.MvvmLight.Command; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using System.Linq; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Input; |
||||
|
|
||||
|
namespace BBWY.Client.ViewModels |
||||
|
{ |
||||
|
public class PackSkuSplitConfigViewModel : BaseVM |
||||
|
{ |
||||
|
public IList<PackSkuConfig> PackSkuConfigList { get; set; } |
||||
|
|
||||
|
private IList<StoreResponse> storeList; |
||||
|
|
||||
|
public ICommand SetSplitCountCommand { get; set; } |
||||
|
|
||||
|
public ICommand SetPackCountAndStoreCommand { get; set; } |
||||
|
|
||||
|
public ICommand SaveCommand { get; set; } |
||||
|
|
||||
|
private LogisticsService logisticsService; |
||||
|
|
||||
|
public PackSkuSplitConfigViewModel(LogisticsService logisticsService) |
||||
|
{ |
||||
|
this.logisticsService = logisticsService; |
||||
|
SetSplitCountCommand = new RelayCommand<PackSkuConfig>(SetSplitCount); |
||||
|
SetPackCountAndStoreCommand = new RelayCommand<PackSkuSplitConfig>(SetPackCountAndStore); |
||||
|
SaveCommand = new RelayCommand(Save); |
||||
|
PackSkuConfigList = new ObservableCollection<PackSkuConfig>(); |
||||
|
} |
||||
|
|
||||
|
public void SetData(IList<PackSkuConfig> packSkuConfigList) |
||||
|
{ |
||||
|
foreach (var item in packSkuConfigList) |
||||
|
PackSkuConfigList.Add(item); |
||||
|
} |
||||
|
|
||||
|
public IList<PackSkuConfig> GetPackSkuConfigList() |
||||
|
{ |
||||
|
return PackSkuConfigList; |
||||
|
} |
||||
|
|
||||
|
private void SetSplitCount(PackSkuConfig packSkuConfig) |
||||
|
{ |
||||
|
if (packSkuConfig.SplitCount <= 0) |
||||
|
{ |
||||
|
MessageBox.Show("份数不正确"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
packSkuConfig.PackSkuSplitConfigList.Clear(); |
||||
|
for (var i = 1; i <= packSkuConfig.SplitCount; i++) |
||||
|
{ |
||||
|
packSkuConfig.PackSkuSplitConfigList.Add(new PackSkuSplitConfig() |
||||
|
{ |
||||
|
Index = i, |
||||
|
PackCount = 0 |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void SetPackCountAndStore(PackSkuSplitConfig packSkuSplitConfig) |
||||
|
{ |
||||
|
if (storeList == null) |
||||
|
{ |
||||
|
var response = logisticsService.GetStoreList(); |
||||
|
if (!response.Success) |
||||
|
{ |
||||
|
MessageBox.Show(response.Msg, "获取仓库"); |
||||
|
return; |
||||
|
} |
||||
|
storeList = response.Data; |
||||
|
} |
||||
|
var w = new PackSkuSplitCountAndStoreWindow(packSkuSplitConfig.PackCount, packSkuSplitConfig.Store, storeList); |
||||
|
if (w.ShowDialog() == true) |
||||
|
{ |
||||
|
packSkuSplitConfig.PackCount = w.Quantity; |
||||
|
packSkuSplitConfig.Store = w.Store; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void Save() |
||||
|
{ |
||||
|
if (PackSkuConfigList.Any(s => s.PackSkuSplitConfigList.Count() == 0 || |
||||
|
s.PackSkuSplitConfigList.Any(sp => sp.PackCount <= 0))) |
||||
|
{ |
||||
|
MessageBox.Show("装箱设置不正确", "提示"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (PackSkuConfigList.Any(s => s.PurchaseCount != s.PackSkuSplitConfigList.Sum(sp => sp.PackCount))) |
||||
|
{ |
||||
|
MessageBox.Show("打包份数总数与采购数量不相等", "提示"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
GalaSoft.MvvmLight.Messaging.Messenger.Default.Send(true, "PackSkuConfigWindowClose"); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,137 @@ |
|||||
|
<c:BWindow x:Class="BBWY.Client.Views.BatchPurchase.PackSkuConfigWindow" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:local="clr-namespace:BBWY.Client.Views.BatchPurchase" |
||||
|
xmlns:c="clr-namespace:BBWY.Controls;assembly=BBWY.Controls" |
||||
|
xmlns:b="http://schemas.microsoft.com/xaml/behaviors" |
||||
|
mc:Ignorable="d" |
||||
|
Title="PackSkuConfigWindow" Height="500" Width="1024" |
||||
|
MinButtonVisibility="Collapsed" |
||||
|
MaxButtonVisibility="Collapsed" |
||||
|
Style="{StaticResource bwstyle}" |
||||
|
DataContext="{Binding PackSkuConfig,Source={StaticResource Locator}}"> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="30"/> |
||||
|
<RowDefinition/> |
||||
|
<RowDefinition Height="40"/> |
||||
|
</Grid.RowDefinitions> |
||||
|
|
||||
|
<Border BorderThickness="0,0,0,1" BorderBrush="{StaticResource MainMenu.BorderBrush}" |
||||
|
Background="{StaticResource Border.Background}"> |
||||
|
<TextBlock Text="分箱与落仓" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
||||
|
</Border> |
||||
|
|
||||
|
<ListBox x:Name="listbox" |
||||
|
ItemsSource="{Binding PackSkuConfigList}" |
||||
|
ItemContainerStyle="{StaticResource NoBgListBoxItemStyle}" |
||||
|
BorderBrush="{StaticResource Border.Brush}" |
||||
|
BorderThickness="1,0,0,0" |
||||
|
Grid.Row="1"> |
||||
|
<ListBox.ItemTemplate> |
||||
|
<DataTemplate> |
||||
|
<Grid Width="{Binding ActualWidth,ElementName=listbox,Converter={StaticResource widthConverter},ConverterParameter=3}"> |
||||
|
|
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="140"/> |
||||
|
<ColumnDefinition/> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<!--{Binding Logo}--> |
||||
|
<c:BAsyncImage UrlSource="{Binding Logo}" |
||||
|
Width="130" DecodePixelWidth="130" |
||||
|
VerticalAlignment="Top" Margin="0,5,0,5" |
||||
|
Cursor="Hand"/> |
||||
|
|
||||
|
<Grid Grid.Column="1"> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="30"/> |
||||
|
<RowDefinition Height="30"/> |
||||
|
<RowDefinition/> |
||||
|
<RowDefinition/> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="Auto"/> |
||||
|
<ColumnDefinition/> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<TextBlock VerticalAlignment="Center" Margin="5,0,0,0"> |
||||
|
<Run Text="SKU:"/> |
||||
|
<Run Text="{Binding SkuId}"/> |
||||
|
</TextBlock> |
||||
|
<TextBlock VerticalAlignment="Center" Grid.Column="1" Margin="5,0,0,0"> |
||||
|
<Run Text="采购数量:"/> |
||||
|
<Run Text="{Binding PurchaseCount}"/> |
||||
|
</TextBlock> |
||||
|
|
||||
|
<TextBlock VerticalAlignment="Center" Margin="5,0,5,0" Grid.Row="1"> |
||||
|
<Run Text="SKU名称:"/> |
||||
|
<Run Text="{Binding Title}"/> |
||||
|
</TextBlock> |
||||
|
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="1" Margin="5,0,0,0"> |
||||
|
<TextBlock Text="份数:" VerticalAlignment="Center"/> |
||||
|
<c:BTextBox Text="{Binding SplitCount}" Width="40" Margin="5,0" Height="25"/> |
||||
|
<c:BButton Command="{Binding DataContext.SetSplitCountCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBox}}}" |
||||
|
CommandParameter="{Binding }" |
||||
|
Content="设置" |
||||
|
Style="{StaticResource LinkButton}"/> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<ListBox Grid.Row="2" Grid.ColumnSpan="2" |
||||
|
ItemContainerStyle="{StaticResource NoBgListBoxItemStyle}" |
||||
|
BorderThickness="1,1,0,1" |
||||
|
BorderBrush="{StaticResource Border.Brush}" |
||||
|
ItemsSource="{Binding PackSkuSplitConfigList}" |
||||
|
Width="Auto" |
||||
|
Margin="5,0,0,6" |
||||
|
HorizontalAlignment="Left" |
||||
|
Visibility="{Binding SplitCount,ConverterParameter=0:Collapsed:Visible,Converter={StaticResource objConverter}}"> |
||||
|
<ListBox.ItemsPanel> |
||||
|
<ItemsPanelTemplate> |
||||
|
<StackPanel Orientation="Horizontal"/> |
||||
|
</ItemsPanelTemplate> |
||||
|
</ListBox.ItemsPanel> |
||||
|
<ListBox.ItemTemplate> |
||||
|
<DataTemplate> |
||||
|
<Grid Width="120" Height="80"> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition/> |
||||
|
<RowDefinition/> |
||||
|
<RowDefinition/> |
||||
|
</Grid.RowDefinitions> |
||||
|
<TextBlock Text="{Binding Index,StringFormat=第\{0\}份}" Style="{StaticResource middleTextBlock}"/> |
||||
|
<c:BButton Content="设置" Style="{StaticResource LinkButton}" Grid.Row="1" |
||||
|
Command="{Binding DataContext.SetPackCountAndStoreCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}" |
||||
|
CommandParameter="{Binding }"/> |
||||
|
<TextBlock Grid.Row="2" Style="{StaticResource middleTextBlock}"> |
||||
|
<Run Text="{Binding PackCount,StringFormat=\{0\}件}"/> |
||||
|
<Run Text="{Binding Store.Name}"/> |
||||
|
</TextBlock> |
||||
|
<Border Width="1" Grid.RowSpan="3" HorizontalAlignment="Right" |
||||
|
Background="{StaticResource Border.Brush}"/> |
||||
|
<Border Height="1" Background="{StaticResource Border.Brush}" |
||||
|
VerticalAlignment="Bottom"/> |
||||
|
<Border Height="1" Background="{StaticResource Border.Brush}" |
||||
|
VerticalAlignment="Bottom" Grid.Row="1"/> |
||||
|
</Grid> |
||||
|
</DataTemplate> |
||||
|
</ListBox.ItemTemplate> |
||||
|
|
||||
|
</ListBox> |
||||
|
<c:BTextBox Grid.Row="3" Text="{Binding RemarkMessage,Mode=TwoWay}" WaterRemark="打包备注" AcceptsReturn="True" TextWrapping="Wrap" Grid.ColumnSpan="2" Height="70" Margin="5"/> |
||||
|
</Grid> |
||||
|
|
||||
|
<Border Grid.ColumnSpan="2" VerticalAlignment="Bottom" Height="1" Background="{StaticResource Border.Brush}"/> |
||||
|
|
||||
|
<Border HorizontalAlignment="Right" Width="1" Background="{StaticResource Border.Brush}"/> |
||||
|
</Grid> |
||||
|
</DataTemplate> |
||||
|
</ListBox.ItemTemplate> |
||||
|
</ListBox> |
||||
|
|
||||
|
<c:BButton Content="提交订单" Width="80" HorizontalAlignment="Right" Grid.Row="2" |
||||
|
Command="{Binding SaveCommand}" Margin="0,0,5,0"/> |
||||
|
</Grid> |
||||
|
</c:BWindow> |
@ -0,0 +1,44 @@ |
|||||
|
using BBWY.Client.Models.QiKu; |
||||
|
using BBWY.Client.ViewModels; |
||||
|
using BBWY.Controls; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace BBWY.Client.Views.BatchPurchase |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// PackSkuConfigWindow.xaml 的交互逻辑
|
||||
|
/// </summary>
|
||||
|
public partial class PackSkuConfigWindow : BWindow |
||||
|
{ |
||||
|
private PackSkuSplitConfigViewModel vm; |
||||
|
|
||||
|
public PackSkuConfigWindow(IList<PackSkuConfig> list) |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
vm = this.DataContext as PackSkuSplitConfigViewModel; |
||||
|
vm.SetData(list); |
||||
|
|
||||
|
this.Loaded += PackSkuConfigWindow_Loaded; |
||||
|
this.Unloaded += PackSkuConfigWindow_Unloaded; |
||||
|
} |
||||
|
|
||||
|
private void PackSkuConfigWindow_Unloaded(object sender, System.Windows.RoutedEventArgs e) |
||||
|
{ |
||||
|
GalaSoft.MvvmLight.Messaging.Messenger.Default.Unregister(this); |
||||
|
} |
||||
|
|
||||
|
private void PackSkuConfigWindow_Loaded(object sender, System.Windows.RoutedEventArgs e) |
||||
|
{ |
||||
|
GalaSoft.MvvmLight.Messaging.Messenger.Default.Register<bool>(this, "PackSkuConfigWindowClose", (r) => |
||||
|
{ |
||||
|
this.DialogResult = r; |
||||
|
this.Close(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public IList<PackSkuConfig> GetPackSkuConfigList() |
||||
|
{ |
||||
|
return vm.GetPackSkuConfigList(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
<c:BWindow x:Class="BBWY.Client.Views.BatchPurchase.PackSkuSplitCountAndStoreWindow" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:local="clr-namespace:BBWY.Client.Views.BatchPurchase" |
||||
|
mc:Ignorable="d" |
||||
|
xmlns:c="clr-namespace:BBWY.Controls;assembly=BBWY.Controls" |
||||
|
xmlns:b="http://schemas.microsoft.com/xaml/behaviors" |
||||
|
Title="PackSkuSplitCountAndStoreWindow" Height="160" Width="250" |
||||
|
Style="{StaticResource bwstyle}" |
||||
|
MinButtonVisibility="Collapsed" |
||||
|
MaxButtonVisibility="Collapsed"> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="30"/> |
||||
|
<RowDefinition Height="5"/> |
||||
|
<RowDefinition/> |
||||
|
<RowDefinition/> |
||||
|
<RowDefinition Height="40"/> |
||||
|
</Grid.RowDefinitions> |
||||
|
|
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="70"/> |
||||
|
<ColumnDefinition/> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<Border BorderThickness="0,0,0,1" BorderBrush="{StaticResource MainMenu.BorderBrush}" |
||||
|
Background="{StaticResource Border.Background}" |
||||
|
Grid.ColumnSpan="2"> |
||||
|
<TextBlock Text="装箱设置" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
||||
|
</Border> |
||||
|
|
||||
|
<TextBlock Text="件数:" HorizontalAlignment="Right" VerticalAlignment="Center" |
||||
|
Grid.Row="2"/> |
||||
|
<c:BTextBox x:Name="txtQuantity" Grid.Column="1" Grid.Row="2" VerticalAlignment="Center" |
||||
|
Margin="5,0,10,0"/> |
||||
|
|
||||
|
<TextBlock Text="落仓去向:" HorizontalAlignment="Right" VerticalAlignment="Center" |
||||
|
Grid.Row="3"/> |
||||
|
<ComboBox x:Name="cbx_stroeList" Grid.Row="3" Grid.Column="1" Height="30" |
||||
|
Margin="5,0,10,0" |
||||
|
DisplayMemberPath="Name" |
||||
|
VerticalContentAlignment="Center"/> |
||||
|
|
||||
|
<c:BButton x:Name="btn_save" Content="保存" Width="80" HorizontalAlignment="Right" Grid.Row="4" |
||||
|
Margin="0,0,5,0" Click="btn_save_Click" |
||||
|
Grid.Column="1"/> |
||||
|
</Grid> |
||||
|
</c:BWindow> |
@ -0,0 +1,64 @@ |
|||||
|
using BBWY.Client.Models; |
||||
|
using BBWY.Controls; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Windows; |
||||
|
|
||||
|
namespace BBWY.Client.Views.BatchPurchase |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// PackSkuSplitCountAndStoreWindow.xaml 的交互逻辑
|
||||
|
/// </summary>
|
||||
|
public partial class PackSkuSplitCountAndStoreWindow : BWindow |
||||
|
{ |
||||
|
public int Quantity { get; set; } |
||||
|
|
||||
|
public StoreResponse Store { get; set; } |
||||
|
|
||||
|
private IList<StoreResponse> storeList; |
||||
|
|
||||
|
public PackSkuSplitCountAndStoreWindow(int quantity, StoreResponse store, IList<StoreResponse> storeList) |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
this.Quantity = quantity; |
||||
|
this.Store = store; |
||||
|
this.storeList = storeList; |
||||
|
this.Loaded += PackSkuSplitCountAndStoreWindow_Loaded; |
||||
|
} |
||||
|
|
||||
|
private void PackSkuSplitCountAndStoreWindow_Loaded(object sender, System.Windows.RoutedEventArgs e) |
||||
|
{ |
||||
|
this.txtQuantity.Text = Quantity.ToString(); |
||||
|
this.cbx_stroeList.ItemsSource = storeList; |
||||
|
if (Store != null) |
||||
|
this.cbx_stroeList.SelectedItem = storeList.FirstOrDefault(s => s.Id == Store.Id); |
||||
|
else |
||||
|
this.cbx_stroeList.SelectedItem = storeList.FirstOrDefault(); |
||||
|
} |
||||
|
|
||||
|
private void btn_save_Click(object sender, System.Windows.RoutedEventArgs e) |
||||
|
{ |
||||
|
if (!int.TryParse(txtQuantity.Text, out int q)) |
||||
|
{ |
||||
|
MessageBox.Show("件数不正确", "提示"); |
||||
|
return; |
||||
|
} |
||||
|
if (q <= 0) |
||||
|
{ |
||||
|
MessageBox.Show("件数不正确", "提示"); |
||||
|
return; |
||||
|
} |
||||
|
if (cbx_stroeList.SelectedItem == null) |
||||
|
{ |
||||
|
MessageBox.Show("请选择一个仓库", "提示"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
this.Quantity = q; |
||||
|
this.Store = cbx_stroeList.SelectedItem as StoreResponse; |
||||
|
|
||||
|
this.DialogResult = true; |
||||
|
this.Close(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,12 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
|
||||
|
namespace BBWY.Common.Extensions |
||||
|
{ |
||||
|
public static class CopyExtensions |
||||
|
{ |
||||
|
public static T Copy<T>(this T p) |
||||
|
{ |
||||
|
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(p)); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,301 @@ |
|||||
|
using BBWY.Common.Extensions; |
||||
|
using BBWY.Common.Http; |
||||
|
using BBWY.Common.Models; |
||||
|
using BBWY.Server.Model; |
||||
|
using BBWY.Server.Model.Db; |
||||
|
using BBWY.Server.Model.Dto; |
||||
|
using Microsoft.Extensions.Caching.Memory; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using QuanTan.SDK.Client; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Net.Http; |
||||
|
using System.Text.RegularExpressions; |
||||
|
|
||||
|
namespace BBWY.Server.Business |
||||
|
{ |
||||
|
public class PurchaseProductAPIService : IDenpendency |
||||
|
{ |
||||
|
private RestApiService restApiService; |
||||
|
private IMemoryCache memoryCache; |
||||
|
private string oneBoundKey = "t5060712539"; |
||||
|
private string oneBoundSecret = "20211103"; |
||||
|
|
||||
|
private string qtAppId = "BBWY2023022001"; |
||||
|
private string qtAppSecret = "908e131365d5448ca651ba20ed7ddefe"; |
||||
|
|
||||
|
private TimeSpan purchaseProductCacheTimeSpan; |
||||
|
//private TimeSpan _1688SessionIdTimeSpan;
|
||||
|
|
||||
|
//private ConcurrentDictionary<string, (Purchaser purchaser, IList<PurchaseSchemeProductSku> purchaseSchemeProductSkus)> productChaches;
|
||||
|
|
||||
|
private IDictionary<string, string> _1688ProductDetailRequestHeader; |
||||
|
private char[] skuPropertiesSplitChar = new char[] { ';' }; |
||||
|
private QuanTanProductClient quanTanProductClient; |
||||
|
|
||||
|
public PurchaseProductAPIService(RestApiService restApiService, IMemoryCache memoryCache, QuanTanProductClient quanTanProductClient) |
||||
|
{ |
||||
|
this.memoryCache = memoryCache; |
||||
|
this.restApiService = restApiService; |
||||
|
_1688ProductDetailRequestHeader = new Dictionary<string, string>() |
||||
|
{ |
||||
|
{ "Host","detail.1688.com"}, |
||||
|
{ "User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36 Edg/104.0.1293.70"}, |
||||
|
{ "Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"}, |
||||
|
{ "Accept-Encoding","gzip, deflate, br"}, |
||||
|
{ "Accept-Language","zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"} |
||||
|
}; |
||||
|
purchaseProductCacheTimeSpan = TimeSpan.FromDays(1); |
||||
|
this.quanTanProductClient = quanTanProductClient; |
||||
|
} |
||||
|
|
||||
|
public PurchaseSkuBasicInfoResponse GetProductInfo(PurchaseSkuBasicInfoRequest request) |
||||
|
{ |
||||
|
var cacheKey = $"{request.PurchaseProductId}_{request.PriceMode}"; |
||||
|
if (memoryCache.TryGetValue<PurchaseSkuBasicInfoResponse>(cacheKey, out var tuple)) |
||||
|
return tuple.Copy(); |
||||
|
|
||||
|
PurchaseSkuBasicInfoResponse response = null; |
||||
|
|
||||
|
if (request.FirstApiMode == Enums.PurchaseProductAPIMode.Spider) |
||||
|
{ |
||||
|
response = LoadFromSpider(request); |
||||
|
if (response == null) |
||||
|
response = LoadFromOneBound(request); |
||||
|
} |
||||
|
else if (request.FirstApiMode == Enums.PurchaseProductAPIMode.OneBound) |
||||
|
{ |
||||
|
response = LoadFromOneBound(request); |
||||
|
if (response == null) |
||||
|
response = LoadFromSpider(request); |
||||
|
} |
||||
|
|
||||
|
if (response != null) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
memoryCache.Set(cacheKey, response, purchaseProductCacheTimeSpan); |
||||
|
} |
||||
|
catch { } |
||||
|
} |
||||
|
|
||||
|
return response?.Copy(); |
||||
|
} |
||||
|
|
||||
|
private PurchaseSkuBasicInfoResponse LoadFromOneBound(PurchaseSkuBasicInfoRequest request) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
string platformStr = string.Empty; |
||||
|
if (request.Platform == Enums.Platform.阿里巴巴) |
||||
|
platformStr = "1688"; |
||||
|
|
||||
|
if (string.IsNullOrEmpty(platformStr)) |
||||
|
return null; |
||||
|
|
||||
|
var result = restApiService.SendRequest("https://api-gw.onebound.cn/", $"{platformStr}/item_get", $"key={oneBoundKey}&secret={oneBoundSecret}&num_iid={request.PurchaseProductId}&lang=zh-CN&cache=no&agent={(request.PriceMode == Enums.PurchaseOrderMode.批发 ? 0 : 1)}", null, HttpMethod.Get, paramPosition: ParamPosition.Query, enableRandomTimeStamp: true); |
||||
|
if (result.StatusCode != System.Net.HttpStatusCode.OK) |
||||
|
throw new Exception($"{result.StatusCode} {result.Content}"); |
||||
|
|
||||
|
var jobject = JObject.Parse(result.Content); |
||||
|
var isOK = jobject.Value<string>("error_code") == "0000"; |
||||
|
if (isOK) |
||||
|
{ |
||||
|
var skuJArray = (JArray)jobject["item"]["skus"]["sku"]; |
||||
|
if (skuJArray.Count == 0) |
||||
|
{ |
||||
|
//errorMsg = $"商品{purchaseSchemeProduct.PurchaseProductId}缺少sku信息";
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
var list = skuJArray.Select(j => new PurchaseSkuItemBasicInfoResponse() |
||||
|
{ |
||||
|
PurchaseProductId = request.PurchaseProductId, |
||||
|
Price = j.Value<decimal>("price"), |
||||
|
PurchaseSkuId = j.Value<string>("sku_id"), |
||||
|
PurchaseSkuSpecId = j.Value<string>("spec_id"), |
||||
|
Title = j.Value<string>("properties_name"), |
||||
|
Logo = GetOneBoundSkuLogo(j, (JArray)jobject["item"]["prop_imgs"]["prop_img"]) |
||||
|
}).ToList(); |
||||
|
|
||||
|
var purchaserId = jobject["item"]["seller_info"].Value<string>("user_num_id"); |
||||
|
var purchaserName = jobject["item"]["seller_info"].Value<string>("title"); |
||||
|
if (string.IsNullOrEmpty(purchaserName)) |
||||
|
purchaserName = jobject["item"]["seller_info"].Value<string>("shop_name"); |
||||
|
var purchaserLocation = jobject["item"].Value<string>("location"); |
||||
|
|
||||
|
return new PurchaseSkuBasicInfoResponse() |
||||
|
{ |
||||
|
Purchaser = new Model.Db.Purchaser() |
||||
|
{ |
||||
|
Id = purchaserId, |
||||
|
Location = purchaserLocation, |
||||
|
Name = purchaserName, |
||||
|
Platform = request.Platform |
||||
|
}, |
||||
|
ItemList = list, |
||||
|
PurchasePlatform = request.Platform, |
||||
|
PurchaseProductId = request.PurchaseProductId |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
catch { } |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private string GetOneBoundSkuLogo(JToken skuJToken, JArray prop_img) |
||||
|
{ |
||||
|
if (!prop_img.HasValues) |
||||
|
return "pack://application:,,,/Resources/Images/defaultItem.png"; |
||||
|
var properties = skuJToken.Value<string>("properties").Split(skuPropertiesSplitChar, StringSplitOptions.RemoveEmptyEntries); |
||||
|
foreach (var p in properties) |
||||
|
{ |
||||
|
var imgJToken = prop_img.FirstOrDefault(g => g.Value<string>("properties") == p); |
||||
|
if (imgJToken != null) |
||||
|
return imgJToken.Value<string>("url"); |
||||
|
} |
||||
|
return "pack://application:,,,/Resources/Images/defaultItem.png"; |
||||
|
} |
||||
|
|
||||
|
private PurchaseSkuBasicInfoResponse LoadFromSpider(PurchaseSkuBasicInfoRequest request) |
||||
|
{ |
||||
|
switch (request.Platform) |
||||
|
{ |
||||
|
case Enums.Platform.阿里巴巴: |
||||
|
return LoadFrom1688Spider(request); |
||||
|
case Enums.Platform.拳探: |
||||
|
return LoadFromQTSpider(request); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private PurchaseSkuBasicInfoResponse LoadFrom1688Spider(PurchaseSkuBasicInfoRequest request) |
||||
|
{ |
||||
|
//https://detail.1688.com/offer/672221374773.html?clickid=65f3772cd5d16f190ce4991414607&sessionid=3de47a0c26dcbfde4692064bd55861&sk=order
|
||||
|
|
||||
|
//globalData/tempModel/sellerUserId
|
||||
|
//globalData/tempModel/companyName
|
||||
|
//data/1081181309101/data/location
|
||||
|
|
||||
|
|
||||
|
//data/1081181309582/data/pirceModel/[currentPrices]/[0]price
|
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
var _1688pageResult = restApiService.SendRequest("https://detail.1688.com", |
||||
|
$"offer/{request.PurchaseProductId}.html", |
||||
|
$"clickid={Guid.NewGuid().ToString().Md5Encrypt()}&sessionid={Guid.NewGuid().ToString().Md5Encrypt()}&sk={(request.PriceMode == Enums.PurchaseOrderMode.批发 ? "order" : "consign")}", |
||||
|
_1688ProductDetailRequestHeader, |
||||
|
HttpMethod.Get, |
||||
|
httpClientName: "gzip"); |
||||
|
|
||||
|
if (_1688pageResult.StatusCode != System.Net.HttpStatusCode.OK) |
||||
|
return null; |
||||
|
|
||||
|
var match = Regex.Match(_1688pageResult.Content, @"(window\.__INIT_DATA=)(.*)(\r*\n*\s*</script>)"); |
||||
|
if (!match.Success) |
||||
|
return null; |
||||
|
|
||||
|
var jsonStr = match.Groups[2].Value; |
||||
|
var jobject = JObject.Parse(jsonStr); |
||||
|
|
||||
|
//16347413030323
|
||||
|
var purchaser = new Purchaser() |
||||
|
{ |
||||
|
Id = jobject["globalData"]["tempModel"]["sellerUserId"].ToString(), |
||||
|
Name = jobject["globalData"]["tempModel"]["companyName"].ToString(), |
||||
|
Location = jobject["data"]["1081181309101"] != null ? |
||||
|
jobject["data"]["1081181309101"]["data"]["location"].ToString() : |
||||
|
jobject["data"]["16347413030323"]["data"]["location"].ToString(), |
||||
|
Platform = Enums.Platform.阿里巴巴 |
||||
|
}; |
||||
|
|
||||
|
var colorsProperty = jobject["globalData"]["skuModel"]["skuProps"].FirstOrDefault(j => j.Value<int>("fid") == 3216 || |
||||
|
j.Value<int>("fid") == 1627207 || |
||||
|
j.Value<int>("fid") == 1234 || |
||||
|
j.Value<int>("fid") == 3151)["value"] |
||||
|
.Children() |
||||
|
.Select(j => new |
||||
|
{ |
||||
|
name = j.Value<string>("name"), |
||||
|
imageUrl = j.Value<string>("imageUrl") |
||||
|
}).ToList(); |
||||
|
|
||||
|
var firstPrice = jobject["data"]["1081181309582"] != null ? |
||||
|
jobject["data"]["1081181309582"]["data"]["priceModel"]["currentPrices"][0].Value<decimal>("price") : |
||||
|
jobject["data"]["16347413030316"]["data"]["priceModel"]["currentPrices"][0].Value<decimal>("price"); |
||||
|
|
||||
|
var list = new List<PurchaseSkuItemBasicInfoResponse>(); |
||||
|
|
||||
|
foreach (var jsku in jobject["globalData"]["skuModel"]["skuInfoMap"].Children()) |
||||
|
{ |
||||
|
var jskuProperty = jsku as JProperty; |
||||
|
var name = jskuProperty.Name; |
||||
|
var matchName = name.Contains(">") ? name.Substring(0, name.IndexOf(">")) : name; |
||||
|
var value = jskuProperty.Value; |
||||
|
|
||||
|
var skuPrice = value.Value<decimal>("price"); |
||||
|
|
||||
|
list.Add(new PurchaseSkuItemBasicInfoResponse() |
||||
|
{ |
||||
|
PurchaseProductId = request.PurchaseProductId, |
||||
|
Price = skuPrice == 0M ? firstPrice : skuPrice, |
||||
|
Title = name, |
||||
|
PurchaseSkuId = value.Value<string>("skuId"), |
||||
|
PurchaseSkuSpecId = value.Value<string>("specId"), |
||||
|
Logo = colorsProperty.FirstOrDefault(c => c.name == matchName)?.imageUrl ?? "pack://application:,,,/Resources/Images/defaultItem.png" |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
return new PurchaseSkuBasicInfoResponse() |
||||
|
{ |
||||
|
ItemList = list, |
||||
|
Purchaser = purchaser, |
||||
|
PurchaseProductId = request.PurchaseProductId, |
||||
|
PurchasePlatform = Enums.Platform.阿里巴巴 |
||||
|
}; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private PurchaseSkuBasicInfoResponse LoadFromQTSpider(PurchaseSkuBasicInfoRequest request) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var response = quanTanProductClient.GetProductInfo(request.PurchaseProductId, qtAppId, qtAppSecret); |
||||
|
if (response.Status != 200) |
||||
|
return null; |
||||
|
return new PurchaseSkuBasicInfoResponse() |
||||
|
{ |
||||
|
Purchaser = new Purchaser() |
||||
|
{ |
||||
|
Id = response.Data.Supplier.VenderId, |
||||
|
Name = response.Data.Supplier.VerdenName, |
||||
|
Location = response.Data.Supplier.Location |
||||
|
}, |
||||
|
PurchaseProductId = request.PurchaseProductId, |
||||
|
PurchasePlatform = Enums.Platform.拳探, |
||||
|
ItemList = response.Data.ProductSku.Select(s => new PurchaseSkuItemBasicInfoResponse() |
||||
|
{ |
||||
|
Logo = s.Logo, |
||||
|
Price = s.Price, |
||||
|
PurchaseProductId = s.ProductId, |
||||
|
PurchaseSkuId = s.SkuId, |
||||
|
Title = s.Title |
||||
|
}).ToList() |
||||
|
}; |
||||
|
} |
||||
|
catch |
||||
|
{ |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,16 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace BBWY.Server.Model.Dto |
||||
|
{ |
||||
|
public class BBWYBDeliveryCallBackRequest |
||||
|
{ |
||||
|
public string OrderId { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class BBWYBSignCallBackRequest : BBWYBDeliveryCallBackRequest |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
namespace BBWY.Server.Model.Dto |
||||
|
{ |
||||
|
public class BatchUpdateQTPurchaseSchemeBelongPurchaserRequest |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 采购商Id 可空
|
||||
|
/// </summary>
|
||||
|
public string PurchaserId { get; set; } |
||||
|
} |
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace BBWY.Server.Model.Dto |
||||
|
{ |
||||
|
public class PurchaseSkuBasicInfoRequest |
||||
|
{ |
||||
|
public Enums.Platform Platform { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购商品Id
|
||||
|
/// </summary>
|
||||
|
public string PurchaseProductId { get; set; } |
||||
|
|
||||
|
public Enums.PurchaseOrderMode PriceMode { get; set; } |
||||
|
|
||||
|
public Enums.PurchaseProductAPIMode FirstApiMode { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class BatchPurchaseSkuBasicInfoRequest |
||||
|
{ |
||||
|
public IList<BatchPurchaseSkuBasicInfoParamRequest> Params { get; set; } |
||||
|
|
||||
|
public Enums.PurchaseOrderMode PriceMode { get; set; } |
||||
|
|
||||
|
public Enums.PurchaseProductAPIMode FirstApiMode { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class BatchPurchaseSkuBasicInfoParamRequest |
||||
|
{ |
||||
|
public Enums.Platform Platform { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购商品Id(采购spu)
|
||||
|
/// </summary>
|
||||
|
public string[] PurchaseProductIds { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 需要保留的采购SkuId,如果传递了该数组,将过滤不在该数组的采购sku
|
||||
|
/// </summary>
|
||||
|
public string[] PurchaseSkuIds { get; set; } |
||||
|
} |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace BBWY.Server.Model.Dto |
||||
|
{ |
||||
|
public class PackSkuConfigRequest |
||||
|
{ |
||||
|
public PackSkuConfigRequest() |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
/// <summary>
|
||||
|
/// 采购备注信息
|
||||
|
/// </summary>
|
||||
|
public string RemarkMessage { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 店铺Sku
|
||||
|
/// </summary>
|
||||
|
public string SkuId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购数量
|
||||
|
/// </summary>
|
||||
|
public int PurchaseCount { get; set; } |
||||
|
|
||||
|
|
||||
|
public IList<PackSkuSplitConfigRequest> PackSkuSplitConfigList { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class PackSkuSplitConfigRequest |
||||
|
{ |
||||
|
public int Index { get; set; } |
||||
|
|
||||
|
public int PackCount { get; set; } |
||||
|
|
||||
|
public StoreRequest Store { get; set; } |
||||
|
} |
||||
|
} |
@ -0,0 +1,9 @@ |
|||||
|
namespace BBWY.Server.Model.Dto |
||||
|
{ |
||||
|
public class StoreRequest |
||||
|
{ |
||||
|
public string Id { get; set; } |
||||
|
|
||||
|
public string Name { get; set; } |
||||
|
} |
||||
|
} |
@ -0,0 +1,58 @@ |
|||||
|
using BBWY.Server.Model.Db; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace BBWY.Server.Model.Dto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 采购Sku基础信息对象
|
||||
|
/// </summary>
|
||||
|
public class PurchaseSkuBasicInfoResponse |
||||
|
{ |
||||
|
public Enums.Platform PurchasePlatform { get; set; } |
||||
|
|
||||
|
public string PurchaseProductId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购SKU基础信息列表
|
||||
|
/// </summary>
|
||||
|
public IList<PurchaseSkuItemBasicInfoResponse> ItemList { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购商
|
||||
|
/// </summary>
|
||||
|
public Purchaser Purchaser { get; set; } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购Sku基础信息对象
|
||||
|
/// </summary>
|
||||
|
public class PurchaseSkuItemBasicInfoResponse |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 采购SPU
|
||||
|
/// </summary>
|
||||
|
public string PurchaseProductId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购SKU
|
||||
|
/// </summary>
|
||||
|
public string PurchaseSkuId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 采购SPEC 1688独有属性 下单需要
|
||||
|
/// </summary>
|
||||
|
public string PurchaseSkuSpecId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// SKU标题
|
||||
|
/// </summary>
|
||||
|
public string Title { get; set; } |
||||
|
|
||||
|
public string Logo { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 单价
|
||||
|
/// </summary>
|
||||
|
public decimal Price { get; set; } |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue