feat: 适配供应商发货接口并支持单订单发货

This commit is contained in:
Administrator
2026-03-05 09:30:29 +08:00
parent 4fd9c44ee8
commit c077fa9989
6 changed files with 117 additions and 17 deletions

View File

@@ -6,6 +6,7 @@
<appSettings>
<!-- API工厂配置 -->
<add key="ApiBaseUrl" value="https://api.it120.cc" />
<add key="CommonApiBaseUrl" value="https://common.apifm.com" />
<add key="SubDomain" value="let5see" />
<!-- 同步配置 -->

View File

@@ -7,6 +7,9 @@ namespace PackagingMallShipper.Helpers
public static string ApiBaseUrl =>
ConfigurationManager.AppSettings["ApiBaseUrl"] ?? "https://user.api.it120.cc";
public static string CommonApiBaseUrl =>
ConfigurationManager.AppSettings["CommonApiBaseUrl"] ?? "https://common.apifm.com";
public static string SubDomain =>
ConfigurationManager.AppSettings["SubDomain"] ?? "vv125s";
@@ -23,5 +26,10 @@ namespace PackagingMallShipper.Helpers
{
return $"{ApiBaseUrl}/{SubDomain}{endpoint}";
}
public static string GetCommonApiUrl(string endpoint)
{
return $"{CommonApiBaseUrl}{endpoint}";
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading;
@@ -22,37 +23,38 @@ namespace PackagingMallShipper.Services
public ShipService(IAuthService authService)
{
_authService = authService;
_httpClient = new HttpClient();
_httpClient.Timeout = TimeSpan.FromSeconds(30);
_httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(30)
};
}
public async Task<ShipResult> ShipOrderAsync(ShipOrderRequest request)
{
var token = _authService.GetToken();
if (string.IsNullOrEmpty(token))
throw new UnauthorizedAccessException("未登录");
throw new UnauthorizedAccessException("未登录,请先登录");
UpdateLocalOrderStatus(request.OrderId, "shipping");
try
{
var url = AppConfig.GetApiUrl($"/order/delivery") +
$"?orderId={request.OrderId}" +
$"&expressType={request.ExpressCompanyId}" +
$"&shipperCode={Uri.EscapeDataString(request.TrackingNumber)}";
var query = $"?id={request.OrderId}" +
$"&expressCompanyId={request.ExpressCompanyId}" +
$"&number={Uri.EscapeDataString(request.TrackingNumber)}";
var url = AppConfig.GetCommonApiUrl("/apifmUser/fsmRepair/fahuo") + query;
_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Add("X-Token", token);
var response = await _httpClient.PostAsync(url, null);
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<ApiResponse<object>>(json);
Debug.WriteLine($"[发货请求] URL: {url}");
var result = await PostShipRequestAsync(url);
if (result?.Code != 0)
throw new Exception(result?.Msg ?? "发货失败");
UpdateLocalOrderAfterShip(request);
return new ShipResult { Success = true };
}
catch (Exception ex)
@@ -73,7 +75,7 @@ namespace PackagingMallShipper.Services
Results = new List<ShipOrderResult>()
};
int completed = 0;
var completed = 0;
using (var semaphore = new SemaphoreSlim(concurrency))
{
@@ -130,6 +132,15 @@ namespace PackagingMallShipper.Services
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)
{
using (var conn = SqliteHelper.GetConnection())
@@ -165,8 +176,7 @@ namespace PackagingMallShipper.Services
using (var cmd = new SQLiteCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@expressId", request.ExpressCompanyId);
cmd.Parameters.AddWithValue("@expressName",
ExpressCompanies.GetName(request.ExpressCompanyId));
cmd.Parameters.AddWithValue("@expressName", ExpressCompanies.GetName(request.ExpressCompanyId));
cmd.Parameters.AddWithValue("@trackingNumber", request.TrackingNumber);
cmd.Parameters.AddWithValue("@dateShip", DateTime.Now);
cmd.Parameters.AddWithValue("@now", DateTime.Now);

View File

@@ -11,6 +11,7 @@ using Microsoft.Win32;
using PackagingMallShipper.Helpers;
using PackagingMallShipper.Models;
using PackagingMallShipper.Services;
using PackagingMallShipper.Views;
namespace PackagingMallShipper.ViewModels
{
@@ -633,6 +634,57 @@ namespace PackagingMallShipper.ViewModels
"提示", 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()
{
try

View File

@@ -100,12 +100,10 @@
Width="90" Height="30" Margin="0,0,5,0"
IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBool}}"/>
<!-- 暂时禁用导入发货功能
<Button Content="📥 导入发货" Command="{Binding ImportAndShipCommand}"
Width="90" Height="30"
Background="#52C41A" Foreground="White" BorderThickness="0"
IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBool}}"/>
-->
</StackPanel>
<!-- 订单列表 -->
@@ -163,6 +161,37 @@
Width="70"/>
<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>

View File

@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="填写发货信息"
Height="280" Width="400"
Height="320" Width="400"
WindowStartupLocation="CenterOwner"
ResizeMode="NoResize"
ShowInTaskbar="False">