diff --git a/server/HoneyBox/src/HoneyBox.Core/Interfaces/IWechatService.cs b/server/HoneyBox/src/HoneyBox.Core/Interfaces/IWechatService.cs
index 782edd43..b0a494c7 100644
--- a/server/HoneyBox/src/HoneyBox.Core/Interfaces/IWechatService.cs
+++ b/server/HoneyBox/src/HoneyBox.Core/Interfaces/IWechatService.cs
@@ -1,4 +1,5 @@
using HoneyBox.Model.Models.Auth;
+using HoneyBox.Model.Models.Payment;
namespace HoneyBox.Core.Interfaces;
@@ -27,4 +28,105 @@ public interface IWechatService
/// 小程序AppId(可选,不传则使用默认配置)
/// access_token,失败返回null
Task GetAccessTokenAsync(string? appId = null);
+
+ ///
+ /// 创建支付订单(Web支付方式)
+ ///
+ /// 支付请求
+ /// 支付结果
+ Task CreatePayOrderAsync(CreatePayRequest request);
+}
+
+///
+/// 创建支付请求
+///
+public class CreatePayRequest
+{
+ ///
+ /// 用户ID
+ ///
+ public int UserId { get; set; }
+
+ ///
+ /// 用户OpenId
+ ///
+ public string OpenId { get; set; } = string.Empty;
+
+ ///
+ /// 支付金额(元)
+ ///
+ public decimal Price { get; set; }
+
+ ///
+ /// 商品标题
+ ///
+ public string Title { get; set; } = string.Empty;
+
+ ///
+ /// 附加数据(订单类型)
+ ///
+ public string Attach { get; set; } = string.Empty;
+
+ ///
+ /// 订单号前缀
+ ///
+ public string Prefix { get; set; } = "MH_";
+}
+
+///
+/// 创建支付结果
+///
+public class CreatePayResult
+{
+ ///
+ /// 状态:1=成功,0=失败
+ ///
+ public int Status { get; set; }
+
+ ///
+ /// 错误消息
+ ///
+ public string? Message { get; set; }
+
+ ///
+ /// 订单号
+ ///
+ public string OrderNo { get; set; } = string.Empty;
+
+ ///
+ /// 支付参数(返回给前端)
+ ///
+ public WebPayParams? Res { get; set; }
+}
+
+///
+/// Web支付参数
+///
+public class WebPayParams
+{
+ ///
+ /// 支付数据
+ ///
+ public WebPayData? Data { get; set; }
+
+ ///
+ /// 请求支付URL
+ ///
+ public string RequestPay { get; set; } = string.Empty;
+
+ ///
+ /// 提示信息
+ ///
+ public string Tips { get; set; } = string.Empty;
+}
+
+///
+/// Web支付数据
+///
+public class WebPayData
+{
+ ///
+ /// 订单号
+ ///
+ public string OrderNum { get; set; } = string.Empty;
}
diff --git a/server/HoneyBox/src/HoneyBox.Core/Services/WarehouseService.cs b/server/HoneyBox/src/HoneyBox.Core/Services/WarehouseService.cs
index d821f832..4ef31810 100644
--- a/server/HoneyBox/src/HoneyBox.Core/Services/WarehouseService.cs
+++ b/server/HoneyBox/src/HoneyBox.Core/Services/WarehouseService.cs
@@ -16,15 +16,18 @@ public class WarehouseService : IWarehouseService
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger _logger;
private readonly ILogisticsService _logisticsService;
+ private readonly IWechatService _wechatService;
public WarehouseService(
HoneyBoxDbContext dbContext,
ILogger logger,
- ILogisticsService logisticsService)
+ ILogisticsService logisticsService,
+ IWechatService wechatService)
{
_dbContext = dbContext;
_logger = logger;
_logisticsService = logisticsService;
+ _wechatService = wechatService;
}
#region 仓库查询
@@ -1099,13 +1102,55 @@ public class WarehouseService : IWarehouseService
SendResultDto result;
if (freePost > count && postMoney > 0)
{
- // 需要支付运费,返回支付参数
- // 注意:实际支付参数需要调用微信支付服务生成
+ // 需要支付运费,调用微信支付服务生成支付参数
+ // 获取用户信息
+ var user = await _dbContext.Users.FindAsync(userId);
+ if (user == null)
+ {
+ throw new InvalidOperationException("用户不存在");
+ }
+
+ var payRequest = new CreatePayRequest
+ {
+ UserId = userId,
+ OpenId = user.OpenId,
+ Price = actualFreight,
+ Title = $"背包发货{count}件",
+ Attach = "order_list_send",
+ Prefix = "FH_"
+ };
+
+ var payResult = await _wechatService.CreatePayOrderAsync(payRequest);
+
+ if (payResult.Status != 1)
+ {
+ throw new InvalidOperationException(payResult.Message ?? "创建支付订单失败");
+ }
+
+ // 更新发货记录的订单号为支付订单号
+ sendRecord.SendNum = payResult.OrderNo;
+ await _dbContext.SaveChangesAsync();
+
+ // 同时更新 OrderItems 的 SendNum
+ await _dbContext.OrderItems
+ .Where(o => o.SendNum == sendNum && o.UserId == userId)
+ .ExecuteUpdateAsync(s => s
+ .SetProperty(o => o.SendNum, payResult.OrderNo)
+ .SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
+
result = new SendResultDto
{
Status = 1, // 需要支付
- OrderNo = sendNum,
- Res = null // 实际项目中需要调用WechatService生成支付参数
+ OrderNo = payResult.OrderNo,
+ Res = payResult.Res != null ? new WebPayResultDto
+ {
+ Data = new WebPayDataDto
+ {
+ OrderNum = payResult.OrderNo
+ },
+ RequestPay = payResult.Res.RequestPay,
+ Tips = payResult.Res.Tips
+ } : null
};
}
else
diff --git a/server/HoneyBox/src/HoneyBox.Core/Services/WechatService.cs b/server/HoneyBox/src/HoneyBox.Core/Services/WechatService.cs
index be13b692..2a6b3ea0 100644
--- a/server/HoneyBox/src/HoneyBox.Core/Services/WechatService.cs
+++ b/server/HoneyBox/src/HoneyBox.Core/Services/WechatService.cs
@@ -1,5 +1,7 @@
using System.Text.Json;
using HoneyBox.Core.Interfaces;
+using HoneyBox.Model.Data;
+using HoneyBox.Model.Entities;
using HoneyBox.Model.Models.Auth;
using HoneyBox.Model.Models.Payment;
using Microsoft.Extensions.Logging;
@@ -17,6 +19,7 @@ public class WechatService : IWechatService
private readonly WechatSettings _wechatSettings;
private readonly WechatPaySettings _wechatPaySettings;
private readonly IRedisService _redisService;
+ private readonly HoneyBoxDbContext _dbContext;
// 微信API端点
private const string WechatCodeToSessionUrl = "https://api.weixin.qq.com/sns/jscode2session";
@@ -31,13 +34,15 @@ public class WechatService : IWechatService
ILogger logger,
WechatSettings wechatSettings,
IOptions wechatPaySettings,
- IRedisService redisService)
+ IRedisService redisService,
+ HoneyBoxDbContext dbContext)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_wechatSettings = wechatSettings ?? throw new ArgumentNullException(nameof(wechatSettings));
_wechatPaySettings = wechatPaySettings?.Value ?? throw new ArgumentNullException(nameof(wechatPaySettings));
_redisService = redisService ?? throw new ArgumentNullException(nameof(redisService));
+ _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
}
///
@@ -394,4 +399,104 @@ public class WechatService : IWechatService
_logger.LogWarning("未找到AppId {AppId} 的配置,使用默认AppSecret", appId);
return _wechatSettings.AppSecret;
}
+
+ ///
+ /// 创建支付订单(Web支付方式)
+ ///
+ public async Task CreatePayOrderAsync(CreatePayRequest request)
+ {
+ try
+ {
+ _logger.LogInformation("[创建支付订单] 开始处理: UserId={UserId}, Price={Price}, Title={Title}, Attach={Attach}",
+ request.UserId, request.Price, request.Title, request.Attach);
+
+ // 如果金额为0,直接返回成功(免费订单)
+ if (request.Price <= 0)
+ {
+ var freeOrderNo = GenerateOrderNo(request.Prefix, "MON", "H5", "ZFB");
+ _logger.LogInformation("[创建支付订单] 免费订单,直接返回成功: OrderNo={OrderNo}", freeOrderNo);
+ return new CreatePayResult
+ {
+ Status = 1,
+ OrderNo = freeOrderNo,
+ Res = null
+ };
+ }
+
+ // 生成订单号
+ var orderNo = GenerateOrderNo(request.Prefix, "ZFA", "H5", "ZFB");
+
+ // 截取标题(最多30个字符)
+ var title = request.Title.Length > 30 ? request.Title.Substring(0, 30) : request.Title;
+
+ // 构建扩展数据
+ var extend = new Dictionary
+ {
+ { "orderType", request.Attach }
+ };
+ var extendStr = JsonSerializer.Serialize(extend);
+
+ // 创建支付通知记录
+ var orderNotify = new OrderNotify
+ {
+ OrderNo = orderNo,
+ NotifyUrl = string.Empty,
+ NonceStr = string.Empty,
+ PayTime = DateTime.UtcNow,
+ PayAmount = request.Price,
+ Status = 0, // 待处理
+ RetryCount = 0,
+ Attach = request.Attach,
+ OpenId = request.OpenId,
+ Extend = extendStr,
+ CreatedAt = DateTime.UtcNow,
+ UpdatedAt = DateTime.UtcNow
+ };
+
+ _dbContext.OrderNotifies.Add(orderNotify);
+ await _dbContext.SaveChangesAsync();
+
+ _logger.LogInformation("[创建支付订单] 订单记录已创建: OrderNo={OrderNo}, NotifyId={NotifyId}",
+ orderNo, orderNotify.Id);
+
+ // 构建Web支付参数
+ var webPayParams = new WebPayParams
+ {
+ Data = new WebPayData
+ {
+ OrderNum = orderNo
+ },
+ RequestPay = "/api/send_web_pay_order",
+ Tips = "您即将进入客服聊天界面完成支付,也可前往「我的」页面下载官方APP,享受更便捷的购物及充值服务。"
+ };
+
+ return new CreatePayResult
+ {
+ Status = 1,
+ OrderNo = orderNo,
+ Res = webPayParams
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "[创建支付订单] 创建失败: UserId={UserId}", request.UserId);
+ return new CreatePayResult
+ {
+ Status = 0,
+ Message = "创建支付订单失败",
+ OrderNo = string.Empty
+ };
+ }
+ }
+
+ ///
+ /// 生成订单号
+ /// 格式:前缀(3位) + 商户前缀(3位) + 项目前缀(2位) + 支付类型(3位) + 时间戳 + 随机数
+ ///
+ private string GenerateOrderNo(string prefix, string merchantPrefix, string projectPrefix, string payType)
+ {
+ var timestamp = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
+ var random = new Random().Next(1000, 9999);
+ return $"{prefix}{merchantPrefix}{projectPrefix}{payType}{timestamp}{random}";
+ }
}
diff --git a/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs b/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs
index 72fd7b38..be4d01e6 100644
--- a/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs
+++ b/server/HoneyBox/src/HoneyBox.Infrastructure/Modules/ServiceModule.cs
@@ -29,7 +29,8 @@ public class ServiceModule : Module
var wechatSettings = c.Resolve();
var wechatPaySettings = c.Resolve>();
var redisService = c.Resolve();
- return new WechatService(httpClientFactory.CreateClient(), logger, wechatSettings, wechatPaySettings, redisService);
+ var dbContext = c.Resolve();
+ return new WechatService(httpClientFactory.CreateClient(), logger, wechatSettings, wechatPaySettings, redisService, dbContext);
}).As().InstancePerLifetimeScope();
// 注册 IP 地理位置服务
@@ -218,7 +219,8 @@ public class ServiceModule : Module
var dbContext = c.Resolve();
var logger = c.Resolve>();
var logisticsService = c.Resolve();
- return new WarehouseService(dbContext, logger, logisticsService);
+ var wechatService = c.Resolve();
+ return new WarehouseService(dbContext, logger, logisticsService, wechatService);
}).As().InstancePerLifetimeScope();
// ========== 支付系统服务注册 ==========
diff --git a/server/HoneyBox/src/HoneyBox.Model/Models/Order/WarehouseModels.cs b/server/HoneyBox/src/HoneyBox.Model/Models/Order/WarehouseModels.cs
index 4e51e966..c7b5c75b 100644
--- a/server/HoneyBox/src/HoneyBox.Model/Models/Order/WarehouseModels.cs
+++ b/server/HoneyBox/src/HoneyBox.Model/Models/Order/WarehouseModels.cs
@@ -473,10 +473,46 @@ public class SendResultDto
public string OrderNo { get; set; } = string.Empty;
///
- /// 微信支付参数(需要支付运费时返回)
+ /// 支付参数(需要支付运费时返回,支持Web支付和微信原生支付)
///
[JsonPropertyName("res")]
- public WechatPayParamsDto? Res { get; set; }
+ public WebPayResultDto? Res { get; set; }
+}
+
+///
+/// Web支付结果DTO(兼容前端支付流程)
+///
+public class WebPayResultDto
+{
+ ///
+ /// 支付数据(包含订单号)
+ ///
+ [JsonPropertyName("data")]
+ public WebPayDataDto? Data { get; set; }
+
+ ///
+ /// 支付请求URL
+ ///
+ [JsonPropertyName("requestPay")]
+ public string RequestPay { get; set; } = string.Empty;
+
+ ///
+ /// 提示信息
+ ///
+ [JsonPropertyName("tips")]
+ public string Tips { get; set; } = string.Empty;
+}
+
+///
+/// Web支付数据DTO
+///
+public class WebPayDataDto
+{
+ ///
+ /// 订单号
+ ///
+ [JsonPropertyName("order_num")]
+ public string OrderNum { get; set; } = string.Empty;
}
///