feat: 添加商城每日购买次数限制功能 (exchange_times)

This commit is contained in:
zpc 2026-02-12 01:00:23 +08:00
parent dca7ba7b1c
commit 66135678d3
4 changed files with 63 additions and 42 deletions

View File

@ -35,8 +35,7 @@ public class GoodsService : IGoodsService
_logger = logger;
}
// 缓存过期时间
private static readonly TimeSpan GoodsListCacheExpiry = TimeSpan.FromSeconds(30);
// 缓存过期时间(商品详情仍使用缓存)
private static readonly TimeSpan GoodsDetailCacheExpiry = TimeSpan.FromMinutes(5);
/// <inheritdoc />
@ -52,30 +51,7 @@ public class GoodsService : IGoodsService
pageSize = 999;
}
// 尝试从缓存获取 - 缓存键格式与PHP一致: {type}_{userId}_{page}
var cacheKey = $"{type}_{userId}_{page}";
var cachedData = await _cacheService.GetGoodsListCacheAsync(cacheKey);
if (!string.IsNullOrEmpty(cachedData))
{
try
{
var cachedResult = JsonSerializer.Deserialize<PageResponse<GoodsListDto>>(cachedData);
if (cachedResult != null)
{
// 更新参与次数(从缓存获取最新值)
foreach (var item in cachedResult.Data)
{
item.JoinCount = await GetJoinCountAsync(item.Id, item.Type);
}
_logger.LogDebug("商品列表从缓存获取: CacheKey={CacheKey}", cacheKey);
return cachedResult;
}
}
catch (JsonException ex)
{
_logger.LogWarning(ex, "商品列表缓存反序列化失败: CacheKey={CacheKey}", cacheKey);
}
}
// 商品列表不使用缓存,确保库存数据实时更新
// 构建基础查询 - 排除已删除的商品
var query = _dbContext.Goods
@ -205,18 +181,6 @@ public class GoodsService : IGoodsService
LastPage = lastPage
};
// 写入缓存
try
{
var jsonData = JsonSerializer.Serialize(response);
await _cacheService.SetGoodsListCacheAsync(cacheKey, jsonData, GoodsListCacheExpiry);
_logger.LogDebug("商品列表已缓存: CacheKey={CacheKey}", cacheKey);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "商品列表缓存写入失败: CacheKey={CacheKey}", cacheKey);
}
return response;
}

View File

@ -573,6 +573,40 @@ public class OrderService : IOrderService
return 0;
}
/// <summary>
/// 获取商城每日购买次数限制
/// </summary>
private async Task<int> GetExchangeTimesLimitAsync()
{
var config = await _dbContext.Configs
.Where(c => c.ConfigKey == "app_setting")
.Select(c => c.ConfigValue)
.FirstOrDefaultAsync();
if (string.IsNullOrEmpty(config))
{
return 0;
}
try
{
var configObj = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(config);
if (configObj != null && configObj.TryGetValue("exchange_times", out var limitObj))
{
if (int.TryParse(limitObj?.ToString(), out var limit))
{
return limit;
}
}
}
catch
{
// 解析失败返回0
}
return 0;
}
/// <summary>
/// 格式化图片URL
/// </summary>
@ -2276,6 +2310,29 @@ public class OrderService : IOrderService
}
}
// 5.1 验证全局商城每日购买次数限制
var exchangeTimes = await GetExchangeTimesLimitAsync();
if (exchangeTimes > 0)
{
var todayStart2 = DateTime.Today;
var todayStartTimestamp2 = new DateTimeOffset(todayStart2).ToUnixTimeSeconds();
var todayEndTimestamp2 = new DateTimeOffset(todayStart2.AddDays(1)).ToUnixTimeSeconds();
// 统计用户今日在商城type=10的购买次数
var todayMallBuyCount = await _dbContext.Orders
.Where(o => o.UserId == userId
&& o.OrderType == 10
&& o.Status == 1
&& o.Addtime >= todayStartTimestamp2
&& o.Addtime < todayEndTimestamp2)
.CountAsync();
if (todayMallBuyCount >= exchangeTimes)
{
throw new InvalidOperationException($"商城每日限购{exchangeTimes}次,今日已购买{todayMallBuyCount}次");
}
}
// 6. 验证抽奖次数
if (request.PrizeNum != 1 && request.PrizeNum != 3 && request.PrizeNum != 5 && request.PrizeNum != 10 && request.PrizeNum != 50)
{

View File

@ -39,7 +39,7 @@
<a href="https://market.aliyun.com/products/57126001/cmapi021863.html?#sku=yuncode1586300000" target="_blank" class="layui-btn layui-btn-primary layui-btn-sm">购买链接</a>
</div>
</div>
<div class="layui-form-item">
<div class="layui-form-item" style="display: none;">
<label class="layui-form-label">连击赏最大抽取次数</label>
<div class="layui-input-inline">
<input type="text" name="lianji_max_num" value="{$data.lianji_max_num ? $data.lianji_max_num : 0}" lay-verify="required" class="layui-input">

View File

@ -41,7 +41,7 @@
<th>ID</th>
<th>分类</th>
<th>名称</th>
<th>奖品概率</th>
<!-- <th>奖品概率</th> -->
<th>时间</th>
<th>操作</th>
</tr>
@ -58,11 +58,11 @@
{/if}
</td>
<td>{$vo['title']}</td>
<td>
<!-- <td>
{if condition="$vo['type'] eq 2"}
{$vo['probability']}
{/if}
</td>
</td> -->
<td>{$vo['addtime']|date="Y-m-d H:i"}</td>
<td>
<a style="text-decoration:none" title="编辑" href="{:url('/admin/qy_level_jiang_edit',['id'=>$vo['id']])}" class="layui-btn layui-btn-normal layui-btn-xs">