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