feat: 适配供应商发货接口并支持单订单发货
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
<appSettings>
|
<appSettings>
|
||||||
<!-- API工厂配置 -->
|
<!-- API工厂配置 -->
|
||||||
<add key="ApiBaseUrl" value="https://api.it120.cc" />
|
<add key="ApiBaseUrl" value="https://api.it120.cc" />
|
||||||
|
<add key="CommonApiBaseUrl" value="https://common.apifm.com" />
|
||||||
<add key="SubDomain" value="let5see" />
|
<add key="SubDomain" value="let5see" />
|
||||||
|
|
||||||
<!-- 同步配置 -->
|
<!-- 同步配置 -->
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace PackagingMallShipper.Helpers
|
|||||||
public static string ApiBaseUrl =>
|
public static string ApiBaseUrl =>
|
||||||
ConfigurationManager.AppSettings["ApiBaseUrl"] ?? "https://user.api.it120.cc";
|
ConfigurationManager.AppSettings["ApiBaseUrl"] ?? "https://user.api.it120.cc";
|
||||||
|
|
||||||
|
public static string CommonApiBaseUrl =>
|
||||||
|
ConfigurationManager.AppSettings["CommonApiBaseUrl"] ?? "https://common.apifm.com";
|
||||||
|
|
||||||
public static string SubDomain =>
|
public static string SubDomain =>
|
||||||
ConfigurationManager.AppSettings["SubDomain"] ?? "vv125s";
|
ConfigurationManager.AppSettings["SubDomain"] ?? "vv125s";
|
||||||
|
|
||||||
@@ -23,5 +26,10 @@ namespace PackagingMallShipper.Helpers
|
|||||||
{
|
{
|
||||||
return $"{ApiBaseUrl}/{SubDomain}{endpoint}";
|
return $"{ApiBaseUrl}/{SubDomain}{endpoint}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetCommonApiUrl(string endpoint)
|
||||||
|
{
|
||||||
|
return $"{CommonApiBaseUrl}{endpoint}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.SQLite;
|
using System.Data.SQLite;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -22,37 +23,38 @@ namespace PackagingMallShipper.Services
|
|||||||
public ShipService(IAuthService authService)
|
public ShipService(IAuthService authService)
|
||||||
{
|
{
|
||||||
_authService = authService;
|
_authService = authService;
|
||||||
_httpClient = new HttpClient();
|
_httpClient = new HttpClient
|
||||||
_httpClient.Timeout = TimeSpan.FromSeconds(30);
|
{
|
||||||
|
Timeout = TimeSpan.FromSeconds(30)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ShipResult> ShipOrderAsync(ShipOrderRequest request)
|
public async Task<ShipResult> ShipOrderAsync(ShipOrderRequest request)
|
||||||
{
|
{
|
||||||
var token = _authService.GetToken();
|
var token = _authService.GetToken();
|
||||||
if (string.IsNullOrEmpty(token))
|
if (string.IsNullOrEmpty(token))
|
||||||
throw new UnauthorizedAccessException("未登录");
|
throw new UnauthorizedAccessException("未登录,请先登录");
|
||||||
|
|
||||||
UpdateLocalOrderStatus(request.OrderId, "shipping");
|
UpdateLocalOrderStatus(request.OrderId, "shipping");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var url = AppConfig.GetApiUrl($"/order/delivery") +
|
var query = $"?id={request.OrderId}" +
|
||||||
$"?orderId={request.OrderId}" +
|
$"&expressCompanyId={request.ExpressCompanyId}" +
|
||||||
$"&expressType={request.ExpressCompanyId}" +
|
$"&number={Uri.EscapeDataString(request.TrackingNumber)}";
|
||||||
$"&shipperCode={Uri.EscapeDataString(request.TrackingNumber)}";
|
|
||||||
|
var url = AppConfig.GetCommonApiUrl("/apifmUser/fsmRepair/fahuo") + query;
|
||||||
|
|
||||||
_httpClient.DefaultRequestHeaders.Clear();
|
_httpClient.DefaultRequestHeaders.Clear();
|
||||||
_httpClient.DefaultRequestHeaders.Add("X-Token", token);
|
_httpClient.DefaultRequestHeaders.Add("X-Token", token);
|
||||||
|
|
||||||
var response = await _httpClient.PostAsync(url, null);
|
Debug.WriteLine($"[发货请求] URL: {url}");
|
||||||
var json = await response.Content.ReadAsStringAsync();
|
var result = await PostShipRequestAsync(url);
|
||||||
var result = JsonConvert.DeserializeObject<ApiResponse<object>>(json);
|
|
||||||
|
|
||||||
if (result?.Code != 0)
|
if (result?.Code != 0)
|
||||||
throw new Exception(result?.Msg ?? "发货失败");
|
throw new Exception(result?.Msg ?? "发货失败");
|
||||||
|
|
||||||
UpdateLocalOrderAfterShip(request);
|
UpdateLocalOrderAfterShip(request);
|
||||||
|
|
||||||
return new ShipResult { Success = true };
|
return new ShipResult { Success = true };
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -73,7 +75,7 @@ namespace PackagingMallShipper.Services
|
|||||||
Results = new List<ShipOrderResult>()
|
Results = new List<ShipOrderResult>()
|
||||||
};
|
};
|
||||||
|
|
||||||
int completed = 0;
|
var completed = 0;
|
||||||
|
|
||||||
using (var semaphore = new SemaphoreSlim(concurrency))
|
using (var semaphore = new SemaphoreSlim(concurrency))
|
||||||
{
|
{
|
||||||
@@ -130,6 +132,15 @@ namespace PackagingMallShipper.Services
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<ApiResponse<object>> PostShipRequestAsync(string url)
|
||||||
|
{
|
||||||
|
var response = await _httpClient.PostAsync(url, null);
|
||||||
|
var json = await response.Content.ReadAsStringAsync();
|
||||||
|
Debug.WriteLine($"[发货响应] URL: {url}");
|
||||||
|
Debug.WriteLine($"[发货响应] HTTP: {response.StatusCode}, body: {json}");
|
||||||
|
return JsonConvert.DeserializeObject<ApiResponse<object>>(json);
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateLocalOrderStatus(int orderId, string status, string errorMsg = null)
|
private void UpdateLocalOrderStatus(int orderId, string status, string errorMsg = null)
|
||||||
{
|
{
|
||||||
using (var conn = SqliteHelper.GetConnection())
|
using (var conn = SqliteHelper.GetConnection())
|
||||||
@@ -165,8 +176,7 @@ namespace PackagingMallShipper.Services
|
|||||||
using (var cmd = new SQLiteCommand(sql, conn))
|
using (var cmd = new SQLiteCommand(sql, conn))
|
||||||
{
|
{
|
||||||
cmd.Parameters.AddWithValue("@expressId", request.ExpressCompanyId);
|
cmd.Parameters.AddWithValue("@expressId", request.ExpressCompanyId);
|
||||||
cmd.Parameters.AddWithValue("@expressName",
|
cmd.Parameters.AddWithValue("@expressName", ExpressCompanies.GetName(request.ExpressCompanyId));
|
||||||
ExpressCompanies.GetName(request.ExpressCompanyId));
|
|
||||||
cmd.Parameters.AddWithValue("@trackingNumber", request.TrackingNumber);
|
cmd.Parameters.AddWithValue("@trackingNumber", request.TrackingNumber);
|
||||||
cmd.Parameters.AddWithValue("@dateShip", DateTime.Now);
|
cmd.Parameters.AddWithValue("@dateShip", DateTime.Now);
|
||||||
cmd.Parameters.AddWithValue("@now", DateTime.Now);
|
cmd.Parameters.AddWithValue("@now", DateTime.Now);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Microsoft.Win32;
|
|||||||
using PackagingMallShipper.Helpers;
|
using PackagingMallShipper.Helpers;
|
||||||
using PackagingMallShipper.Models;
|
using PackagingMallShipper.Models;
|
||||||
using PackagingMallShipper.Services;
|
using PackagingMallShipper.Services;
|
||||||
|
using PackagingMallShipper.Views;
|
||||||
|
|
||||||
namespace PackagingMallShipper.ViewModels
|
namespace PackagingMallShipper.ViewModels
|
||||||
{
|
{
|
||||||
@@ -633,6 +634,57 @@ namespace PackagingMallShipper.ViewModels
|
|||||||
"提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
"提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async Task ShipSingleOrder(Order order)
|
||||||
|
{
|
||||||
|
if (order == null || order.Status != 1) return;
|
||||||
|
|
||||||
|
var dialog = new ShippingDialog(order);
|
||||||
|
var activeWindow = Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.IsActive)
|
||||||
|
?? Application.Current.Windows.OfType<Window>().FirstOrDefault(w => w.IsVisible);
|
||||||
|
if (activeWindow != null)
|
||||||
|
dialog.Owner = activeWindow;
|
||||||
|
|
||||||
|
if (dialog.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
IsBusy = true;
|
||||||
|
StatusMessage = $"正在发货 {order.OrderNumber}...";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = new ShipOrderRequest
|
||||||
|
{
|
||||||
|
OrderId = order.Id,
|
||||||
|
OrderNumber = order.OrderNumber,
|
||||||
|
ExpressCompanyId = dialog.SelectedExpressId,
|
||||||
|
TrackingNumber = dialog.TrackingNumber
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = await _shipService.ShipOrderAsync(request);
|
||||||
|
if (result.Success)
|
||||||
|
{
|
||||||
|
StatusMessage = $"订单 {order.OrderNumber} 发货成功";
|
||||||
|
await RefreshOrdersAsync();
|
||||||
|
await UpdateCountsAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
StatusMessage = $"发货失败: {result.Message}";
|
||||||
|
MessageBox.Show($"发货失败: {result.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
StatusMessage = $"发货失败: {ex.Message}";
|
||||||
|
MessageBox.Show($"发货失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task UpdateCountsAsync()
|
private async Task UpdateCountsAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -100,12 +100,10 @@
|
|||||||
Width="90" Height="30" Margin="0,0,5,0"
|
Width="90" Height="30" Margin="0,0,5,0"
|
||||||
IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBool}}"/>
|
IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBool}}"/>
|
||||||
|
|
||||||
<!-- 暂时禁用导入发货功能
|
|
||||||
<Button Content="📥 导入发货" Command="{Binding ImportAndShipCommand}"
|
<Button Content="📥 导入发货" Command="{Binding ImportAndShipCommand}"
|
||||||
Width="90" Height="30"
|
Width="90" Height="30"
|
||||||
Background="#52C41A" Foreground="White" BorderThickness="0"
|
Background="#52C41A" Foreground="White" BorderThickness="0"
|
||||||
IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBool}}"/>
|
IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBool}}"/>
|
||||||
-->
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- 订单列表 -->
|
<!-- 订单列表 -->
|
||||||
@@ -163,6 +161,37 @@
|
|||||||
Width="70"/>
|
Width="70"/>
|
||||||
|
|
||||||
<DataGridTextColumn Header="快递单号" Binding="{Binding TrackingNumber}" Width="150"/>
|
<DataGridTextColumn Header="快递单号" Binding="{Binding TrackingNumber}" Width="150"/>
|
||||||
|
|
||||||
|
<DataGridTemplateColumn Header="操作" Width="80">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Button Content="发货"
|
||||||
|
Command="{Binding DataContext.ShipSingleOrderCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
Padding="8,2" Cursor="Hand"
|
||||||
|
Background="#1890FF" Foreground="White" BorderThickness="0">
|
||||||
|
<Button.Style>
|
||||||
|
<Style TargetType="Button">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Status}" Value="2">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding Status}" Value="3">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding Status}" Value="4">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding Status}" Value="-1">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Button.Style>
|
||||||
|
</Button>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
Title="填写发货信息"
|
Title="填写发货信息"
|
||||||
Height="280" Width="400"
|
Height="320" Width="400"
|
||||||
WindowStartupLocation="CenterOwner"
|
WindowStartupLocation="CenterOwner"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
ShowInTaskbar="False">
|
ShowInTaskbar="False">
|
||||||
|
|||||||
Reference in New Issue
Block a user