HaniBlindBox/server/HoneyBox/src/HoneyBox.Core/Services/WarehouseService.cs
gpu 9867b87594 feat: 实现原生微信支付功能
- 修改 ConfigService.GetPlatformConfigAsync 返回 isWebPay=false,关闭 Web 支付
- 重写 WechatService.CreatePayOrderAsync 实现原生微信支付:
  - 调用微信统一下单 API 获取 prepay_id
  - 生成 MD5 签名
  - 返回前端 uni.requestPayment 所需的参数(appId, timeStamp, nonceStr, package, signType, paySign)
- 更新 IWechatService 接口,添加 NativePayParams 类型
- 更新 WarehouseModels.cs,SendResultDto 使用 NativePayResultDto
- 更新 WarehouseService.SendPrizesAsync 使用新的支付参数格式
- 更新 appsettings.json 配置微信支付商户信息
2026-01-24 13:15:12 +08:00

1757 lines
60 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using HoneyBox.Core.Interfaces;
using HoneyBox.Model.Data;
using HoneyBox.Model.Entities;
using HoneyBox.Model.Models;
using HoneyBox.Model.Models.Order;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace HoneyBox.Core.Services;
/// <summary>
/// 仓库服务实现
/// </summary>
public class WarehouseService : IWarehouseService
{
private readonly HoneyBoxDbContext _dbContext;
private readonly ILogger<WarehouseService> _logger;
private readonly ILogisticsService _logisticsService;
private readonly IWechatService _wechatService;
public WarehouseService(
HoneyBoxDbContext dbContext,
ILogger<WarehouseService> logger,
ILogisticsService logisticsService,
IWechatService wechatService)
{
_dbContext = dbContext;
_logger = logger;
_logisticsService = logisticsService;
_wechatService = wechatService;
}
#region
/// <inheritdoc />
public async Task<WarehouseIndexResponseDto> GetWarehouseIndexAsync(int userId, WarehouseIndexRequest request)
{
var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var showDadajuan = true;
// 自动将预售商品转为现货当sale_time <= 当前时间)
await AutoConvertPresaleToAvailableAsync(userId, currentTime);
var response = new WarehouseIndexResponseDto();
switch (request.Type)
{
case 1: // 赏品
response = await GetPrizesWarehouseAsync(userId, request, currentTime);
showDadajuan = await CheckShowDadajuanAsync(userId, response.Data.Any());
break;
case 2: // 预售
response = await GetPresaleWarehouseAsync(userId, request);
break;
case 3: // 卡册
response = await GetCardAlbumWarehouseAsync(userId, request);
break;
case 4: // 保险柜
response = await GetSafeWarehouseAsync(userId, request);
break;
case 5: // 无限赏
response = await GetInfiniteWarehouseAsync(userId, request);
break;
default:
throw new InvalidOperationException("请求错误");
}
// 获取运费设置
response.Yufei = await GetShippingFeeConfigAsync(request.Type);
response.ShowDadajuan = showDadajuan;
return response;
}
/// <summary>
/// 自动将预售商品转为现货
/// </summary>
private async Task AutoConvertPresaleToAvailableAsync(int userId, long currentTime)
{
var presaleItems = await _dbContext.OrderItems
.Where(o => o.UserId == userId && o.Status == 0 && o.GoodslistType == 2)
.Select(o => new { o.Id, o.GoodslistId, o.UserId, o.GoodslistSaleTime })
.ToListAsync();
var currentDateTime = DateTimeOffset.FromUnixTimeSeconds(currentTime).DateTime;
foreach (var item in presaleItems)
{
var goodsItem = await _dbContext.GoodsItems
.Where(g => g.Id == item.GoodslistId)
.Select(g => new { g.SaleTime })
.FirstOrDefaultAsync();
bool shouldConvert = false;
if (goodsItem?.SaleTime != null)
{
shouldConvert = goodsItem.SaleTime <= currentDateTime;
}
else if (item.GoodslistSaleTime > 0 && item.GoodslistSaleTime <= currentTime)
{
shouldConvert = true;
}
if (shouldConvert)
{
await _dbContext.OrderItems
.Where(o => o.Id == item.Id && o.Status == 0 && o.UserId == userId && o.GoodslistType == 2)
.ExecuteUpdateAsync(s => s.SetProperty(o => o.GoodslistType, (byte)1));
}
}
}
/// <summary>
/// 获取赏品仓库type=1
/// </summary>
private async Task<WarehouseIndexResponseDto> GetPrizesWarehouseAsync(int userId, WarehouseIndexRequest request, long currentTime)
{
var response = new WarehouseIndexResponseDto();
var total = 0;
var goodsGroups = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 1
&& o.InsuranceIs == 0
&& o.OrderType != 4)
.GroupBy(o => o.GoodsId)
.Select(g => g.Key)
.OrderBy(g => g)
.ToListAsync();
foreach (var goodsId in goodsGroups)
{
var goodsTitle = await GetGoodsTitleAsync(goodsId);
var query = _dbContext.OrderItems
.Where(o => o.GoodsId == goodsId
&& o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 1
&& o.InsuranceIs == 0
&& o.OrderType != 4);
if (!string.IsNullOrEmpty(request.Keyword))
{
query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
}
var orderListItems = await query
.GroupBy(o => o.PrizeCode)
.Select(g => new
{
Id = g.First().Id,
GoodslistTitle = g.First().GoodslistTitle,
GoodslistImgurl = g.First().GoodslistImgurl,
GoodslistMoney = g.First().GoodslistMoney,
GoodsId = g.First().GoodsId,
ShangId = g.First().ShangId,
PrizeCode = g.Key,
PrizeNum = g.Count()
})
.OrderBy(o => o.ShangId)
.ToListAsync();
var orderListDtos = new List<WarehouseItemDto>();
foreach (var item in orderListItems)
{
var orderListIds = await _dbContext.OrderItems
.Where(o => o.GoodsId == item.GoodsId
&& o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 1
&& o.InsuranceIs == 0
&& o.OrderType != 4 && o.OrderType != 9
&& o.PrizeCode == item.PrizeCode)
.OrderBy(o => o.ShangId)
.Select(o => o.Id)
.ToListAsync();
var shangTitle = await GetShangTitleAsync(item.ShangId);
orderListDtos.Add(new WarehouseItemDto
{
Id = item.Id,
GoodsListTitle = item.GoodslistTitle ?? string.Empty,
GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
GoodsId = item.GoodsId ?? 0,
ShangId = item.ShangId,
PrizeCode = item.PrizeCode,
PrizeNum = item.PrizeNum,
OrderListIds = orderListIds,
ShangTitle = shangTitle
});
}
var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
total += orderListTotal;
response.Data.Add(new WarehouseGoodsGroupDto
{
GoodsId = goodsId ?? 0,
GoodsTitle = goodsTitle,
OrderList = orderListDtos,
OrderListTotal = orderListTotal,
OrderListLength = orderListDtos.Count
});
}
response.Total = total;
return response;
}
/// <summary>
/// 获取预售仓库type=2
/// </summary>
private async Task<WarehouseIndexResponseDto> GetPresaleWarehouseAsync(int userId, WarehouseIndexRequest request)
{
var response = new WarehouseIndexResponseDto();
var total = 0;
var goodsGroups = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 2
&& o.InsuranceIs == 0
&& o.OrderType != 4)
.GroupBy(o => o.GoodsId)
.Select(g => g.Key)
.OrderBy(g => g)
.ToListAsync();
foreach (var goodsId in goodsGroups)
{
var goodsTitle = await GetGoodsTitleAsync(goodsId);
var query = _dbContext.OrderItems
.Where(o => o.GoodsId == goodsId
&& o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 2
&& o.InsuranceIs == 0
&& o.OrderType != 4);
if (!string.IsNullOrEmpty(request.Keyword))
{
query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
}
var orderListItems = await query
.GroupBy(o => o.PrizeCode)
.Select(g => new
{
GoodslistTitle = g.First().GoodslistTitle,
GoodslistImgurl = g.First().GoodslistImgurl,
GoodslistMoney = g.First().GoodslistMoney,
GoodsId = g.First().GoodsId,
ShangId = g.First().ShangId,
PrizeCode = g.Key,
GoodslistSaleTime = g.First().GoodslistSaleTime,
PrizeNum = g.Count()
})
.OrderBy(o => o.ShangId)
.ToListAsync();
var orderListDtos = new List<WarehouseItemDto>();
foreach (var item in orderListItems)
{
var shangTitle = await GetShangTitleAsync(item.ShangId);
orderListDtos.Add(new WarehouseItemDto
{
GoodsListTitle = item.GoodslistTitle ?? string.Empty,
GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
GoodsId = item.GoodsId ?? 0,
ShangId = item.ShangId,
PrizeCode = item.PrizeCode,
PrizeNum = item.PrizeNum,
ShangTitle = shangTitle,
GoodsListSaleTime = item.GoodslistSaleTime > 0
? DateTimeOffset.FromUnixTimeSeconds(item.GoodslistSaleTime).ToString("yyyy-MM-dd")
: null
});
}
var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
total += orderListTotal;
response.Data.Add(new WarehouseGoodsGroupDto
{
GoodsId = goodsId ?? 0,
GoodsTitle = goodsTitle,
OrderList = orderListDtos,
OrderListTotal = orderListTotal,
OrderListLength = orderListDtos.Count
});
}
response.Total = total;
return response;
}
/// <summary>
/// 获取卡册仓库type=3
/// </summary>
private async Task<WarehouseIndexResponseDto> GetCardAlbumWarehouseAsync(int userId, WarehouseIndexRequest request)
{
var response = new WarehouseIndexResponseDto();
var pageSize = 30;
var query = _dbContext.Orders
.Where(o => o.UserId == userId && o.OrderType == 4);
if (!string.IsNullOrEmpty(request.Keyword))
{
query = query.Where(o => o.GoodsTitle != null && o.GoodsTitle.Contains(request.Keyword));
}
if (request.CategoryId > 0)
{
var goodsIdsInCategory = await _dbContext.Goods
.Where(g => g.CategoryId == request.CategoryId)
.Select(g => g.Id)
.ToListAsync();
query = query.Where(o => goodsIdsInCategory.Contains(o.GoodsId));
}
var groupedOrders = await query
.GroupBy(o => o.GoodsId)
.Select(g => new { GoodsId = g.Key, OrderId = g.Max(o => o.Id) })
.OrderByDescending(g => g.OrderId)
.Skip((request.Page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var totalGroups = await query.GroupBy(o => o.GoodsId).CountAsync();
response.LastPage = (int)Math.Ceiling((double)totalGroups / pageSize);
foreach (var group in groupedOrders)
{
var order = await _dbContext.Orders
.Where(o => o.Id == group.OrderId)
.Select(o => new { o.Id, o.GoodsId, o.GoodsTitle, o.GoodsImgurl })
.FirstOrDefaultAsync();
if (order == null) continue;
var goods = await _dbContext.Goods
.Where(g => g.Id == group.GoodsId)
.Select(g => new { g.Title, g.CardBanner })
.FirstOrDefaultAsync();
var goodsTitle = goods?.Title ?? order.GoodsTitle ?? string.Empty;
var goodsImgUrl = FormatImageUrl(goods?.CardBanner ?? order.GoodsImgurl);
var allCount = await _dbContext.GoodsItems
.Where(g => g.GoodsId == group.GoodsId)
.CountAsync();
var buyCount = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.GoodsId == group.GoodsId
&& o.Status == 0)
.GroupBy(o => o.GoodslistId)
.CountAsync();
decimal gailv = 0;
if (buyCount > 0 && allCount > 0)
{
gailv = Math.Round((decimal)buyCount / allCount * 100, 2);
}
response.Data.Add(new WarehouseGoodsGroupDto
{
GoodsId = group.GoodsId,
GoodsTitle = goodsTitle,
OrderList = new List<WarehouseItemDto>
{
new WarehouseItemDto
{
Id = order.Id,
GoodsId = group.GoodsId,
GoodsTitle = goodsTitle,
GoodsListImgUrl = goodsImgUrl,
PrizeNum = buyCount
}
},
OrderListTotal = allCount,
OrderListLength = buyCount
});
}
return response;
}
/// <summary>
/// 获取保险柜仓库type=4
/// </summary>
private async Task<WarehouseIndexResponseDto> GetSafeWarehouseAsync(int userId, WarehouseIndexRequest request)
{
var response = new WarehouseIndexResponseDto();
var total = 0;
var goodsGroups = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 1
&& o.OrderType != 4)
.GroupBy(o => o.GoodsId)
.Select(g => g.Key)
.OrderBy(g => g)
.ToListAsync();
foreach (var goodsId in goodsGroups)
{
var goodsTitle = await GetGoodsTitleAsync(goodsId);
var query = _dbContext.OrderItems
.Where(o => o.GoodsId == goodsId
&& o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 1
&& o.OrderType != 4);
if (!string.IsNullOrEmpty(request.Keyword))
{
query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
}
var orderListItems = await query
.GroupBy(o => o.PrizeCode)
.Select(g => new
{
GoodslistTitle = g.First().GoodslistTitle,
GoodslistImgurl = g.First().GoodslistImgurl,
GoodslistMoney = g.First().GoodslistMoney,
GoodsId = g.First().GoodsId,
ShangId = g.First().ShangId,
PrizeCode = g.Key,
PrizeNum = g.Count()
})
.OrderBy(o => o.ShangId)
.ToListAsync();
var orderListDtos = new List<WarehouseItemDto>();
foreach (var item in orderListItems)
{
var shangTitle = await GetShangTitleAsync(item.ShangId);
orderListDtos.Add(new WarehouseItemDto
{
GoodsListTitle = item.GoodslistTitle ?? string.Empty,
GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
GoodsId = item.GoodsId ?? 0,
ShangId = item.ShangId,
PrizeCode = item.PrizeCode,
PrizeNum = item.PrizeNum,
ShangTitle = shangTitle
});
}
var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
total += orderListTotal;
response.Data.Add(new WarehouseGoodsGroupDto
{
GoodsId = goodsId ?? 0,
GoodsTitle = goodsTitle,
OrderList = orderListDtos,
OrderListTotal = orderListTotal,
OrderListLength = orderListDtos.Count
});
}
response.Total = total;
return response;
}
/// <summary>
/// 获取无限赏仓库type=5
/// </summary>
private async Task<WarehouseIndexResponseDto> GetInfiniteWarehouseAsync(int userId, WarehouseIndexRequest request)
{
var response = new WarehouseIndexResponseDto();
var total = 0;
var goodsGroups = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 1
&& o.InsuranceIs == 0
&& o.OrderType == 2)
.GroupBy(o => o.GoodsId)
.Select(g => g.Key)
.OrderBy(g => g)
.ToListAsync();
foreach (var goodsId in goodsGroups)
{
var goodsTitle = await GetGoodsTitleAsync(goodsId);
var query = _dbContext.OrderItems
.Where(o => o.GoodsId == goodsId
&& o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 1
&& o.InsuranceIs == 0
&& o.OrderType == 2);
if (!string.IsNullOrEmpty(request.Keyword))
{
query = query.Where(o => o.GoodslistTitle != null && o.GoodslistTitle.Contains(request.Keyword));
}
var orderListItems = await query
.GroupBy(o => o.PrizeCode)
.Select(g => new
{
Id = g.First().Id,
GoodslistTitle = g.First().GoodslistTitle,
GoodslistImgurl = g.First().GoodslistImgurl,
GoodslistMoney = g.First().GoodslistMoney,
GoodsId = g.First().GoodsId,
ShangId = g.First().ShangId,
PrizeCode = g.Key,
PrizeNum = g.Count()
})
.OrderBy(o => o.ShangId)
.ToListAsync();
var orderListDtos = new List<WarehouseItemDto>();
foreach (var item in orderListItems)
{
var orderListIds = await _dbContext.OrderItems
.Where(o => o.GoodsId == item.GoodsId
&& o.UserId == userId
&& o.Status == 0
&& o.GoodslistType == 1
&& o.InsuranceIs == 0
&& o.OrderType == 2
&& o.PrizeCode == item.PrizeCode)
.OrderBy(o => o.ShangId)
.Select(o => o.Id)
.ToListAsync();
var shangTitle = await GetShangTitleAsync(item.ShangId);
orderListDtos.Add(new WarehouseItemDto
{
Id = item.Id,
GoodsListTitle = item.GoodslistTitle ?? string.Empty,
GoodsListImgUrl = FormatImageUrl(item.GoodslistImgurl),
GoodsListMoney = ((decimal)item.GoodslistMoney * 100).ToString("0"),
GoodsId = item.GoodsId ?? 0,
ShangId = item.ShangId,
PrizeCode = item.PrizeCode,
PrizeNum = item.PrizeNum,
OrderListIds = orderListIds,
ShangTitle = shangTitle
});
}
var orderListTotal = orderListDtos.Sum(o => o.PrizeNum);
total += orderListTotal;
response.Data.Add(new WarehouseGoodsGroupDto
{
GoodsId = goodsId ?? 0,
GoodsTitle = goodsTitle,
OrderList = orderListDtos,
OrderListTotal = orderListTotal,
OrderListLength = orderListDtos.Count
});
}
response.Total = total;
return response;
}
#endregion
#region Helper Methods
/// <summary>
/// 获取商品标题
/// </summary>
private async Task<string> GetGoodsTitleAsync(int? goodsId)
{
if (goodsId == null) return "其他";
if (goodsId == 0) return "无限令奖品";
if (goodsId == -1) return "周榜奖品";
if (goodsId == -2) return "月榜奖品";
var title = await _dbContext.Goods
.Where(g => g.Id == goodsId)
.Select(g => g.Title)
.FirstOrDefaultAsync();
return title ?? "其他";
}
/// <summary>
/// 获取赏品等级标题
/// </summary>
private async Task<string> GetShangTitleAsync(int shangId)
{
if (shangId <= 0) return string.Empty;
var title = await _dbContext.PrizeLevels
.Where(p => p.Id == shangId)
.Select(p => p.Title)
.FirstOrDefaultAsync();
return title ?? string.Empty;
}
/// <summary>
/// 检查是否显示达达卷
/// </summary>
private async Task<bool> CheckShowDadajuanAsync(int userId, bool hasData)
{
if (!hasData) return false;
var config = await _dbContext.Configs
.Where(c => c.ConfigKey == "app_setting")
.Select(c => c.ConfigValue)
.FirstOrDefaultAsync();
if (string.IsNullOrEmpty(config)) return true;
try
{
var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
if (settings != null && settings.TryGetValue("show_dadajuan_limit", out var limitObj))
{
var limitStr = limitObj?.ToString();
if (!string.IsNullOrEmpty(limitStr) && limitStr != "0" && int.TryParse(limitStr, out var limit))
{
var totalConsumption = await _dbContext.Orders
.Where(o => o.UserId == userId && o.Status == 1)
.SumAsync(o => (decimal?)o.OrderTotal) ?? 0;
return totalConsumption >= limit;
}
}
}
catch
{
// 配置解析失败,默认显示
}
return true;
}
/// <summary>
/// 获取运费配置
/// </summary>
private async Task<ShippingFeeDto> GetShippingFeeConfigAsync(int type)
{
var config = await _dbContext.Configs
.Where(c => c.ConfigKey == "base")
.Select(c => c.ConfigValue)
.FirstOrDefaultAsync();
var result = new ShippingFeeDto();
if (string.IsNullOrEmpty(config)) return result;
try
{
var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
if (settings != null)
{
if (type == 3) // 卡册
{
result.FreePost = settings.TryGetValue("card_free_post", out var fp) && int.TryParse(fp?.ToString(), out var fpVal) ? fpVal : 0;
result.PostMoney = settings.TryGetValue("card_post_money", out var pm) && int.TryParse(pm?.ToString(), out var pmVal) ? pmVal : 0;
}
else
{
result.FreePost = settings.TryGetValue("free_post", out var fp) && int.TryParse(fp?.ToString(), out var fpVal) ? fpVal : 0;
result.PostMoney = settings.TryGetValue("post_money", out var pm) && int.TryParse(pm?.ToString(), out var pmVal) ? pmVal : 0;
}
}
}
catch
{
// 配置解析失败,返回默认值
}
return result;
}
/// <summary>
/// 格式化图片URL
/// </summary>
private static string FormatImageUrl(string? imgUrl)
{
if (string.IsNullOrEmpty(imgUrl))
return string.Empty;
if (imgUrl.StartsWith("http://") || imgUrl.StartsWith("https://"))
return imgUrl;
return imgUrl;
}
#endregion
#region
/// <inheritdoc />
public async Task<RecoveryResultDto> RecoveryPrizesAsync(int userId, RecoveryRequest request)
{
// 1. 验证回收信息
if (string.IsNullOrEmpty(request.RecoveryInfo))
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 2. 检查达达卷消费限制
await CheckDadajuanLimitAsync(userId);
// 3. 检查每日兑换次数限制
await CheckDailyExchangeLimitAsync(userId);
// 4. 解析回收信息
List<RecoveryInfoItem> recoveryItems;
try
{
recoveryItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo)
?? new List<RecoveryInfoItem>();
}
catch
{
throw new InvalidOperationException("回收信息格式错误");
}
if (!recoveryItems.Any())
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 5. 根据prize_code和number获取订单详情ID列表
var orderListIds = new List<int>();
foreach (var item in recoveryItems)
{
var ids = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 0
&& o.PrizeCode == item.PrizeCode)
.OrderBy(o => o.Id)
.Take(item.Number)
.Select(o => o.Id)
.ToListAsync();
orderListIds.AddRange(ids);
}
if (!orderListIds.Any())
{
throw new InvalidOperationException("请刷新重新选择奖品");
}
// 6. 计算回收总金额
var totalMoney = await _dbContext.OrderItems
.Where(o => orderListIds.Contains(o.Id)
&& o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 0)
.SumAsync(o => o.GoodslistMoney);
// 7. 生成回收单号
var recoveryNum = GenerateRecoveryNum();
// 8. 使用事务处理
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
var currentTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// 8.1 创建回收记录
var recoveryRecord = new OrderItemsRecovery
{
UserId = userId,
RecoveryNum = recoveryNum,
Money = totalMoney,
Count = orderListIds.Count,
Addtime = currentTime,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
};
_dbContext.OrderItemsRecoveries.Add(recoveryRecord);
// 8.2 更新订单详情状态
await _dbContext.OrderItems
.Where(o => orderListIds.Contains(o.Id)
&& o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 0)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.RecoveryNum, recoveryNum)
.SetProperty(o => o.Status, (byte)1)
.SetProperty(o => o.ChoiceTime, currentTime)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
// 8.3 增加用户哈尼券money2金额乘以100
var money2Amount = totalMoney * 100;
if (money2Amount > 0)
{
await ChangeMoney2Async(userId, money2Amount, 4, "兑换获得");
}
await _dbContext.SaveChangesAsync();
await transaction.CommitAsync();
// 9. 获取用户当前余额
var userMoney2 = await _dbContext.Users
.Where(u => u.Id == userId)
.Select(u => u.Money2 ?? 0)
.FirstOrDefaultAsync();
return new RecoveryResultDto
{
TotalMoney = (money2Amount).ToString("0.00"),
Count = orderListIds.Count,
RecoveryNum = recoveryNum,
UserMoney = userMoney2.ToString("0.00")
};
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "奖品回收失败: UserId={UserId}", userId);
throw new InvalidOperationException("打包失败");
}
}
/// <summary>
/// 检查达达卷消费限制
/// </summary>
private async Task CheckDadajuanLimitAsync(int userId)
{
var config = await _dbContext.Configs
.Where(c => c.ConfigKey == "app_setting")
.Select(c => c.ConfigValue)
.FirstOrDefaultAsync();
if (string.IsNullOrEmpty(config)) return;
try
{
var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
if (settings != null && settings.TryGetValue("show_dadajuan_limit", out var limitObj))
{
var limitStr = limitObj?.ToString();
if (!string.IsNullOrEmpty(limitStr) && limitStr != "0" && int.TryParse(limitStr, out var limit))
{
var totalConsumption = await _dbContext.Orders
.Where(o => o.UserId == userId && o.Status == 1)
.SumAsync(o => (decimal?)o.OrderTotal) ?? 0;
if (totalConsumption < limit)
{
throw new InvalidOperationException($"消费满{limit}才能兑换达达卷");
}
}
}
}
catch (InvalidOperationException)
{
throw;
}
catch
{
// 配置解析失败,忽略限制
}
}
/// <summary>
/// 检查每日兑换次数限制
/// </summary>
private async Task CheckDailyExchangeLimitAsync(int userId)
{
var config = await _dbContext.Configs
.Where(c => c.ConfigKey == "app_setting")
.Select(c => c.ConfigValue)
.FirstOrDefaultAsync();
if (string.IsNullOrEmpty(config)) return;
try
{
var settings = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
if (settings != null && settings.TryGetValue("cabinet_exchange_limit", out var limitObj))
{
var limitStr = limitObj?.ToString();
if (!string.IsNullOrEmpty(limitStr) && int.TryParse(limitStr, out var limit) && limit > 0)
{
var todayStart = new DateTimeOffset(DateTime.UtcNow.Date).ToUnixTimeSeconds();
var todayEnd = todayStart + 86400 - 1;
var todayCount = await _dbContext.OrderItemsRecoveries
.Where(r => r.UserId == userId
&& r.Addtime >= todayStart
&& r.Addtime <= todayEnd)
.CountAsync();
if (todayCount >= limit)
{
throw new InvalidOperationException("今日兑换次数已达上限");
}
}
}
}
catch (InvalidOperationException)
{
throw;
}
catch
{
// 配置解析失败,忽略限制
}
}
/// <summary>
/// 生成回收单号
/// </summary>
private static string GenerateRecoveryNum()
{
return $"HS_{DateTime.UtcNow:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
}
/// <summary>
/// 变更用户哈尼券money2
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="changeMoney">变动金额(正数增加,负数减少)</param>
/// <param name="type">变动类型1后台充值 2在线充值 3抽赏消费 4背包兑换 5推荐奖励</param>
/// <param name="content">变动说明</param>
private async Task ChangeMoney2Async(int userId, decimal changeMoney, byte type, string content)
{
if (changeMoney == 0) return;
var user = await _dbContext.Users.FindAsync(userId);
if (user == null) return;
var currentMoney2 = user.Money2 ?? 0;
var newMoney2 = currentMoney2 + changeMoney;
// 更新用户余额
user.Money2 = newMoney2;
user.UpdatedAt = DateTime.UtcNow;
// 记录变动明细
var profitRecord = new ProfitMoney2
{
UserId = userId,
ChangeMoney = changeMoney,
Money = newMoney2,
Type = type,
Content = content,
ShareUid = 0,
Other = null,
CreatedAt = DateTime.UtcNow
};
_dbContext.ProfitMoney2s.Add(profitRecord);
}
#endregion
#region
/// <inheritdoc />
public async Task<SendResultDto> SendPrizesAsync(int userId, SendRequest request)
{
// 1. 验证类型参数
if (request.Type != 1 && request.Type != 2)
{
throw new InvalidOperationException("请求参数错误");
}
// 2. 验证发货信息
if (string.IsNullOrEmpty(request.RecoveryInfo))
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 3. 验证收货信息
if (string.IsNullOrEmpty(request.Name) || string.IsNullOrEmpty(request.Mobile) || string.IsNullOrEmpty(request.Address))
{
throw new InvalidOperationException("缺少收货信息");
}
// 4. 解析发货信息
List<RecoveryInfoItem> sendItems;
try
{
sendItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo)
?? new List<RecoveryInfoItem>();
}
catch
{
throw new InvalidOperationException("发货信息格式错误");
}
if (!sendItems.Any())
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 5. 根据prize_code和number获取订单详情ID列表
var orderListIds = new List<int>();
foreach (var item in sendItems)
{
var lim = item.Number;
var ids = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 0
&& o.GoodslistType == 1
&& o.PrizeCode == item.PrizeCode.Trim())
.OrderBy(o => o.Id)
.Take(lim)
.Select(o => o.Id)
.ToListAsync();
orderListIds.AddRange(ids);
}
if (!orderListIds.Any())
{
throw new InvalidOperationException("请刷新重新选择奖品");
}
// 6. 获取发货数量
var count = orderListIds.Count;
// 7. 获取运费配置
var shippingConfig = await GetShippingFeeConfigAsync(request.Type);
var freePost = shippingConfig.FreePost <= 0 ? 0 : shippingConfig.FreePost;
var postMoney = shippingConfig.PostMoney <= 0 ? 0 : shippingConfig.PostMoney;
// 8. 生成发货单号
var sendNum = GenerateSendNum();
var currentTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// 9. 计算实际运费
var actualFreight = postMoney;
if (freePost <= count || postMoney == 0)
{
actualFreight = 0;
}
// 10. 使用事务处理
using var transaction = await _dbContext.Database.BeginTransactionAsync();
try
{
// 10.1 更新订单详情的发货单号
await _dbContext.OrderItems
.Where(o => orderListIds.Contains(o.Id)
&& o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 0
&& o.GoodslistType == 1)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.SendNum, sendNum)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
// 10.2 创建发货记录
var sendRecord = new OrderItemsSend
{
UserId = userId,
SendNum = sendNum,
Freight = actualFreight,
Status = 0, // 0=待支付
Count = count,
Name = request.Name,
Mobile = request.Mobile,
Address = request.Address,
Message = request.Message,
Addtime = currentTime,
PayTime = 0,
SendTime = 0,
ShouTime = 0,
CancelTime = 0,
DeliveryStatus = -1, // -1 表示未查询物流
DeliveryTime = 0,
AdminId = 0,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow
};
_dbContext.OrderItemsSends.Add(sendRecord);
await _dbContext.SaveChangesAsync();
var sendRecordId = sendRecord.Id;
// 10.3 判断是否需要支付运费
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 = payResult.OrderNo,
Res = payResult.Res != null ? new NativePayResultDto
{
AppId = payResult.Res.AppId,
TimeStamp = payResult.Res.TimeStamp,
NonceStr = payResult.Res.NonceStr,
Package = payResult.Res.Package,
SignType = payResult.Res.SignType,
PaySign = payResult.Res.PaySign
} : null
};
}
else
{
// 免运费,直接处理发货
sendRecord.Freight = 0;
sendRecord.Status = 1; // 1=待发货
sendRecord.PayTime = currentTime;
// 更新订单详情状态为已发货
await _dbContext.OrderItems
.Where(o => o.SendNum == sendNum && o.UserId == userId)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.Status, (byte)2)
.SetProperty(o => o.ChoiceTime, currentTime)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
await _dbContext.SaveChangesAsync();
result = new SendResultDto
{
Status = 0, // 免运费
OrderNo = sendNum
};
}
await transaction.CommitAsync();
return result;
}
catch (Exception ex)
{
await transaction.RollbackAsync();
_logger.LogError(ex, "奖品发货失败: UserId={UserId}", userId);
throw new InvalidOperationException("发货失败");
}
}
/// <inheritdoc />
public async Task<bool> ConfirmSendAsync(int userId, int id)
{
// 1. 验证参数
if (id <= 0)
{
throw new InvalidOperationException("非法请求");
}
// 2. 查找发货记录
var sendRecord = await _dbContext.OrderItemsSends
.Where(s => s.Id == id && s.UserId == userId)
.FirstOrDefaultAsync();
if (sendRecord == null)
{
throw new InvalidOperationException("请求参数错误");
}
// 3. 检查状态
if (sendRecord.Status == 3)
{
throw new InvalidOperationException("请勿重复操作");
}
if (sendRecord.Status != 2)
{
throw new InvalidOperationException("该订单暂不能确认收货");
}
// 4. 更新状态为已签收
var currentTime = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
sendRecord.Status = 3; // 3=已签收
sendRecord.ShouTime = currentTime;
sendRecord.UpdatedAt = DateTime.UtcNow;
var result = await _dbContext.SaveChangesAsync();
return result > 0;
}
/// <summary>
/// 生成发货单号
/// </summary>
private static string GenerateSendNum()
{
return $"FH_{DateTime.UtcNow:yyyyMMddHHmmss}{new Random().Next(1000, 9999)}";
}
#endregion
#region
/// <inheritdoc />
public async Task<PageResponse<SendRecordDto>> GetSendRecordsAsync(int userId, int page, int status = 1)
{
// 验证状态参数
if (status != 1 && status != 2 && status != 3)
{
throw new InvalidOperationException("非法请求");
}
var pageSize = 10;
var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
// 自动收货7天后自动签收
var expireTime = currentTime - (7 * 86400);
await _dbContext.OrderItemsSends
.Where(s => s.Status == 2 && s.SendTime <= expireTime && s.SendTime > 0)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.Status, (byte)3)
.SetProperty(o => o.ShouTime, (int)currentTime)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
// 查询发货记录
var query = _dbContext.OrderItemsSends
.Where(s => s.UserId == userId && s.Status == status)
.OrderByDescending(s => s.Id);
var totalCount = await query.CountAsync();
var lastPage = (int)Math.Ceiling((double)totalCount / pageSize);
var records = await query
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var result = new List<SendRecordDto>();
foreach (var record in records)
{
// 获取奖品列表
var orderList = await _dbContext.OrderItems
.Where(o => o.SendNum == record.SendNum)
.Select(o => new SendRecordItemDto
{
Id = o.Id,
GoodsListTitle = o.GoodslistTitle ?? string.Empty,
GoodsListImgUrl = FormatImageUrl(o.GoodslistImgurl),
GoodsListMoney = o.GoodslistMoney.ToString("0.00"),
ShangId = o.ShangId,
PrizeNum = 1,
FhStatus = o.FhStatus
})
.ToListAsync();
// 获取赏品等级标题
foreach (var item in orderList)
{
item.ShangTitle = await GetShangTitleAsync(item.ShangId);
}
result.Add(new SendRecordDto
{
Id = record.Id,
SendNum = record.SendNum ?? string.Empty,
Name = record.Name ?? string.Empty,
Mobile = MaskMobile(record.Mobile),
Address = record.Address ?? string.Empty,
Status = record.Status,
StatusName = GetSendStatusName(record.Status),
Count = record.Count,
Freight = record.Freight.ToString("0.00"),
AddTime = FormatTimestamp(record.Addtime),
CourierNumber = record.CourierNumber,
CourierName = record.CourierName,
UserId = record.UserId,
OrderList = orderList
});
}
return new PageResponse<SendRecordDto>
{
Data = result,
LastPage = lastPage > 0 ? lastPage : 1
};
}
/// <inheritdoc />
public async Task<SendRecordDetailDto> GetSendRecordDetailAsync(int userId, int id)
{
// 验证参数
if (id <= 0)
{
throw new InvalidOperationException("非法请求");
}
// 查询发货记录
var record = await _dbContext.OrderItemsSends
.Where(s => s.Id == id && s.UserId == userId)
.FirstOrDefaultAsync();
if (record == null)
{
throw new InvalidOperationException("请求参数错误");
}
// 验证状态
if (record.Status != 1 && record.Status != 2 && record.Status != 3)
{
throw new InvalidOperationException("请求参数错误");
}
// 获取奖品列表
var goods = await _dbContext.OrderItems
.Where(o => o.SendNum == record.SendNum)
.OrderByDescending(o => o.GoodslistMoney)
.Select(o => new SendRecordItemDto
{
Id = o.Id,
GoodsListTitle = o.GoodslistTitle ?? string.Empty,
GoodsListImgUrl = FormatImageUrl(o.GoodslistImgurl),
GoodsListMoney = o.GoodslistMoney.ToString("0.00"),
ShangId = o.ShangId,
PrizeNum = 1,
FhStatus = o.FhStatus
})
.ToListAsync();
// 获取赏品等级标题
foreach (var item in goods)
{
item.ShangTitle = await GetShangTitleAsync(item.ShangId);
}
return new SendRecordDetailDto
{
Id = record.Id,
SendNum = record.SendNum ?? string.Empty,
Name = record.Name ?? string.Empty,
Mobile = record.Mobile ?? string.Empty,
Address = record.Address ?? string.Empty,
Message = record.Message,
Status = record.Status,
Count = record.Count,
Freight = record.Freight.ToString("0.00"),
AddTime = FormatTimestamp(record.Addtime),
PayTime = FormatTimestamp(record.PayTime),
SendTime = record.SendTime > 0 ? FormatTimestamp(record.SendTime) : "待发货",
ShouTime = record.ShouTime > 0 ? FormatTimestamp(record.ShouTime) : "待收货",
CourierNumber = record.CourierNumber,
CourierName = record.CourierName,
Goods = goods
};
}
/// <inheritdoc />
public async Task<PageResponse<RecoveryRecordDto>> GetRecoveryRecordsAsync(int userId, int page)
{
var pageSize = 10;
var query = _dbContext.OrderItemsRecoveries
.Where(r => r.UserId == userId)
.OrderByDescending(r => r.Id);
var totalCount = await query.CountAsync();
var lastPage = (int)Math.Ceiling((double)totalCount / pageSize);
var records = await query
.Skip((page - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var result = new List<RecoveryRecordDto>();
foreach (var record in records)
{
// 获取奖品列表
var orderList = await _dbContext.OrderItems
.Where(o => o.RecoveryNum == record.RecoveryNum)
.Select(o => new RecoveryRecordItemDto
{
Id = o.Id,
GoodsListTitle = o.GoodslistTitle ?? string.Empty,
GoodsListImgUrl = FormatImageUrl(o.GoodslistImgurl),
GoodsListMoney = o.GoodslistMoney.ToString("0.00")
})
.ToListAsync();
result.Add(new RecoveryRecordDto
{
Id = record.Id,
RecoveryNum = record.RecoveryNum ?? string.Empty,
Money = record.Money.ToString("0.00"),
Count = record.Count,
AddTime = FormatTimestamp(record.Addtime),
OrderList = orderList
});
}
return new PageResponse<RecoveryRecordDto>
{
Data = result,
LastPage = lastPage > 0 ? lastPage : 1
};
}
/// <summary>
/// 获取发货状态名称
/// </summary>
private static string GetSendStatusName(int status)
{
return status switch
{
0 => "待支付",
1 => "待发货",
2 => "已发货",
3 => "已签收",
4 => "已取消",
_ => "未知"
};
}
/// <summary>
/// 手机号脱敏
/// </summary>
private static string MaskMobile(string? mobile)
{
if (string.IsNullOrEmpty(mobile) || mobile.Length < 7)
return mobile ?? string.Empty;
return mobile.Substring(0, 3) + "****" + mobile.Substring(mobile.Length - 4);
}
/// <summary>
/// 格式化时间戳为日期时间字符串
/// </summary>
private static string FormatTimestamp(int timestamp)
{
if (timestamp <= 0) return string.Empty;
return DateTimeOffset.FromUnixTimeSeconds(timestamp).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
}
#endregion
#region
/// <summary>
/// 物流状态名称映射
/// </summary>
private static readonly string[] DeliveryStatusNames =
{
"快递收件(揽件)", // 0
"在途中", // 1
"正在派件", // 2
"已签收", // 3
"派送失败", // 4
"疑难件", // 5
"退件签收", // 6
"其他" // 7
};
/// <inheritdoc />
public async Task<LogisticsDto> GetLogisticsAsync(int userId, int id)
{
// 1. 验证参数
if (id <= 0)
{
throw new InvalidOperationException("非法请求");
}
// 2. 查询发货记录
var sendRecord = await _dbContext.OrderItemsSends
.Where(s => s.Id == id && s.UserId == userId)
.Select(s => new
{
s.Id,
s.SendNum,
s.CourierNumber,
s.CourierName,
s.CourierCode,
s.DeliveryList,
s.DeliveryStatus,
s.DeliveryTime,
s.Count,
s.Mobile
})
.FirstOrDefaultAsync();
if (sendRecord == null)
{
throw new InvalidOperationException("请求参数错误");
}
// 3. 获取奖品图片
var goodsListImgUrl = await _dbContext.OrderItems
.Where(o => o.SendNum == sendRecord.SendNum)
.Select(o => o.GoodslistImgurl)
.FirstOrDefaultAsync();
// 4. 初始化响应
var result = new LogisticsDto
{
CourierNumber = sendRecord.CourierNumber,
CourierName = sendRecord.CourierName,
CourierCode = sendRecord.CourierCode,
Count = sendRecord.Count,
SendNum = sendRecord.SendNum,
GoodsListImgUrl = FormatImageUrl(goodsListImgUrl),
DeliveryStatus = GetDeliveryStatusName(sendRecord.DeliveryStatus),
DeliveryList = ParseDeliveryList(sendRecord.DeliveryList)
};
// 5. 检查是否需要刷新物流信息每10分钟刷新一次
var currentTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var shouldRefresh = !string.IsNullOrEmpty(sendRecord.CourierNumber)
&& (currentTime > sendRecord.DeliveryTime + 600);
if (shouldRefresh)
{
// 6. 处理顺丰快递特殊逻辑需要手机号后4位
var trackingNo = sendRecord.CourierNumber!;
if (sendRecord.CourierCode?.ToUpper() == "SFEXPRESS" && !string.IsNullOrEmpty(sendRecord.Mobile))
{
var mobileSuffix = sendRecord.Mobile.Length >= 4
? sendRecord.Mobile.Substring(sendRecord.Mobile.Length - 4)
: sendRecord.Mobile;
trackingNo = $"{trackingNo}:{mobileSuffix}";
}
// 7. 调用物流查询API
var queryResult = await _logisticsService.QueryLogisticsAsync(
trackingNo,
sendRecord.CourierCode ?? string.Empty);
if (queryResult.Success)
{
// 8. 更新物流信息到数据库
var deliveryListJson = queryResult.TraceList != null
? System.Text.Json.JsonSerializer.Serialize(queryResult.TraceList)
: null;
await _dbContext.OrderItemsSends
.Where(s => s.Id == id)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.DeliveryList, deliveryListJson)
.SetProperty(o => o.DeliveryStatus, (byte)queryResult.DeliveryStatus)
.SetProperty(o => o.DeliveryTime, (int)currentTime)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
// 9. 更新响应
result.DeliveryStatus = GetDeliveryStatusName(queryResult.DeliveryStatus);
result.DeliveryList = queryResult.TraceList;
}
}
return result;
}
/// <summary>
/// 获取物流状态名称
/// </summary>
private static string GetDeliveryStatusName(int status)
{
if (status >= 0 && status < DeliveryStatusNames.Length)
{
return DeliveryStatusNames[status];
}
return "暂无物流轨迹";
}
/// <summary>
/// 解析物流轨迹JSON
/// </summary>
private static List<LogisticsTraceDto>? ParseDeliveryList(string? deliveryListJson)
{
if (string.IsNullOrEmpty(deliveryListJson))
{
return null;
}
try
{
return System.Text.Json.JsonSerializer.Deserialize<List<LogisticsTraceDto>>(deliveryListJson);
}
catch
{
return null;
}
}
#endregion
#region
/// <inheritdoc />
public async Task<bool> MoveIntoSafeAsync(int userId, SafeOperationRequest request)
{
// 1. 验证操作信息
if (string.IsNullOrEmpty(request.RecoveryInfo))
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 2. 解析操作信息
List<RecoveryInfoItem> operationItems;
try
{
operationItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo)
?? new List<RecoveryInfoItem>();
}
catch
{
throw new InvalidOperationException("操作信息格式错误");
}
if (!operationItems.Any())
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 3. 根据prize_code和number获取订单详情ID列表
var orderListIds = new List<int>();
foreach (var item in operationItems)
{
var ids = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 0
&& o.PrizeCode == item.PrizeCode)
.OrderBy(o => o.Id)
.Take(item.Number)
.Select(o => o.Id)
.ToListAsync();
orderListIds.AddRange(ids);
}
if (!orderListIds.Any())
{
throw new InvalidOperationException("请刷新重新选择奖品");
}
// 4. 更新订单详情的保险柜状态
var result = await _dbContext.OrderItems
.Where(o => orderListIds.Contains(o.Id)
&& o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 0)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.InsuranceIs, (byte)1)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
return result > 0;
}
/// <inheritdoc />
public async Task<bool> RemoveFromSafeAsync(int userId, SafeOperationRequest request)
{
// 1. 验证操作信息
if (string.IsNullOrEmpty(request.RecoveryInfo))
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 2. 解析操作信息
List<RecoveryInfoItem> operationItems;
try
{
operationItems = System.Text.Json.JsonSerializer.Deserialize<List<RecoveryInfoItem>>(request.RecoveryInfo)
?? new List<RecoveryInfoItem>();
}
catch
{
throw new InvalidOperationException("操作信息格式错误");
}
if (!operationItems.Any())
{
throw new InvalidOperationException("请选择兑换的赏品");
}
// 3. 根据prize_code和number获取订单详情ID列表从保险柜中
var orderListIds = new List<int>();
foreach (var item in operationItems)
{
var ids = await _dbContext.OrderItems
.Where(o => o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 1
&& o.PrizeCode == item.PrizeCode)
.OrderBy(o => o.Id)
.Take(item.Number)
.Select(o => o.Id)
.ToListAsync();
orderListIds.AddRange(ids);
}
if (!orderListIds.Any())
{
throw new InvalidOperationException("请刷新重新选择奖品");
}
// 4. 更新订单详情的保险柜状态
var result = await _dbContext.OrderItems
.Where(o => orderListIds.Contains(o.Id)
&& o.UserId == userId
&& o.Status == 0
&& o.InsuranceIs == 1)
.ExecuteUpdateAsync(s => s
.SetProperty(o => o.InsuranceIs, (byte)0)
.SetProperty(o => o.UpdatedAt, DateTime.UtcNow));
return result > 0;
}
#endregion
}