This commit is contained in:
zpc 2026-02-08 11:41:30 +08:00
parent 284b0c20f0
commit 4e4849eac1
9 changed files with 406 additions and 143 deletions

View File

@ -113,6 +113,28 @@ public class PrizeCreateRequest
/// 系统会自动为所有箱号中的同一父奖品创建对应的子奖品 /// 系统会自动为所有箱号中的同一父奖品创建对应的子奖品
/// </summary> /// </summary>
public int GoodsListId { get; set; } public int GoodsListId { get; set; }
/// <summary>
/// 奖励配置列表
/// 用于配置抽中该奖品时发放的货币奖励
/// </summary>
public List<PrizeRewardItem>? Rewards { get; set; }
}
/// <summary>
/// 奖品奖励配置项
/// </summary>
public class PrizeRewardItem
{
/// <summary>
/// 奖励类型1=钻石(HH币) 2=UU币(积分) 3=哈尼券
/// </summary>
public int Type { get; set; }
/// <summary>
/// 奖励数量
/// </summary>
public int Amount { get; set; }
} }
/// <summary> /// <summary>
@ -272,6 +294,11 @@ public class PrizeDto
/// </summary> /// </summary>
public int GoodsListId { get; set; } public int GoodsListId { get; set; }
/// <summary>
/// 奖励配置列表
/// </summary>
public List<PrizeRewardItem>? Rewards { get; set; }
/// <summary> /// <summary>
/// 创建时间 /// 创建时间
/// </summary> /// </summary>

View File

@ -307,6 +307,51 @@ public class GoodsService : IGoodsService
#region #region
/// <summary>
/// 创建奖品奖励配置
/// 在 rewards 表中创建对应的奖励记录
/// </summary>
/// <param name="prizeCode">奖品编码,用作 reward_id</param>
/// <param name="rewards">奖励配置列表</param>
/// <param name="now">当前时间</param>
/// <returns>生成的 reward_id</returns>
private async Task<string> CreatePrizeRewardsAsync(string prizeCode, List<PrizeRewardItem> rewards, DateTime now)
{
// 使用 prize_code 作为 reward_id确保唯一性
var rewardId = $"PRIZE_{prizeCode}";
// 删除已存在的同 reward_id 的记录(如果有)
var existingRewards = await _dbContext.Rewards
.Where(r => r.RewardId == rewardId)
.ToListAsync();
if (existingRewards.Any())
{
_dbContext.Rewards.RemoveRange(existingRewards);
}
// 创建新的奖励记录
foreach (var item in rewards.Where(r => r.Amount > 0))
{
var reward = new HoneyBox.Model.Entities.Reward
{
RewardId = rewardId,
RewardType = item.Type,
RewardValue = item.Amount,
RewardExtend = null,
CreatedAt = now,
UpdatedAt = now
};
_dbContext.Rewards.Add(reward);
}
await _dbContext.SaveChangesAsync();
_logger.LogInformation("创建奖品奖励配置: RewardId={RewardId}, Count={Count}",
rewardId, rewards.Count(r => r.Amount > 0));
return rewardId;
}
/// <inheritdoc /> /// <inheritdoc />
public async Task<List<PrizeDto>> GetPrizesAsync(int goodsId) public async Task<List<PrizeDto>> GetPrizesAsync(int goodsId)
{ {
@ -337,7 +382,31 @@ public class GoodsService : IGoodsService
.Where(pl => shangIds.Contains(pl.Id)) .Where(pl => shangIds.Contains(pl.Id))
.ToDictionaryAsync(pl => pl.Id, pl => new PrizeLevelInfo { Title = pl.Title, Color = pl.Color }); .ToDictionaryAsync(pl => pl.Id, pl => new PrizeLevelInfo { Title = pl.Title, Color = pl.Color });
return prizes.Select(p => MapToPrizeDto(p, prizeLevels)).ToList(); // 获取所有奖励ID
var rewardIds = prizes
.Where(p => !string.IsNullOrEmpty(p.RewardId))
.Select(p => p.RewardId!)
.Distinct()
.ToList();
// 批量查询奖励配置
var rewardsDict = new Dictionary<string, List<PrizeRewardItem>>();
if (rewardIds.Any())
{
var rewards = await _dbContext.Rewards
.AsNoTracking()
.Where(r => rewardIds.Contains(r.RewardId))
.ToListAsync();
rewardsDict = rewards
.GroupBy(r => r.RewardId)
.ToDictionary(
g => g.Key,
g => g.Select(r => new PrizeRewardItem { Type = r.RewardType, Amount = (int)r.RewardValue }).ToList()
);
}
return prizes.Select(p => MapToPrizeDto(p, prizeLevels, rewardsDict)).ToList();
} }
/// <summary> /// <summary>
@ -362,6 +431,13 @@ public class GoodsService : IGoodsService
var now = DateTime.Now; var now = DateTime.Now;
var prizeCode = GeneratePrizeCode(); var prizeCode = GeneratePrizeCode();
// 处理奖励配置:如果有 rewards 配置,创建 rewards 表记录
var rewardId = request.RewardId;
if (request.Rewards != null && request.Rewards.Count > 0)
{
rewardId = await CreatePrizeRewardsAsync(prizeCode, request.Rewards, now);
}
// 根据商品类型决定添加逻辑 // 根据商品类型决定添加逻辑
// 无限赏(2)、盲盒(8)、扭蛋(9)、福利屋(15)、连抽赏(16)、大乱斗(17)num = 0模板奖品只添加一条 // 无限赏(2)、盲盒(8)、扭蛋(9)、福利屋(15)、连抽赏(16)、大乱斗(17)num = 0模板奖品只添加一条
// 一番赏(1)、擂台赏(3)、福袋(5)、幸运赏(6)、积分商城(10)、转转赏(11):为每个箱子都添加一条奖品 // 一番赏(1)、擂台赏(3)、福袋(5)、幸运赏(6)、积分商城(10)、转转赏(11):为每个箱子都添加一条奖品
@ -370,7 +446,7 @@ public class GoodsService : IGoodsService
// 处理宝箱子奖品的情况 // 处理宝箱子奖品的情况
if (request.GoodsListId > 0) if (request.GoodsListId > 0)
{ {
return await AddChildPrizeAsync(goodsId, request, now); return await AddChildPrizeAsync(goodsId, request, now, rewardId);
} }
if (templateTypes.Contains(goods.Type)) if (templateTypes.Contains(goods.Type))
@ -399,7 +475,7 @@ public class GoodsService : IGoodsService
PrizeCode = prizeCode, PrizeCode = prizeCode,
Type = (byte)request.Type, Type = (byte)request.Type,
LianJiType = (byte)request.LianJiType, LianJiType = (byte)request.LianJiType,
RewardId = request.RewardId, RewardId = rewardId,
Doubling = request.Doubling, Doubling = request.Doubling,
IsLingzhu = (byte)request.IsLingzhu, IsLingzhu = (byte)request.IsLingzhu,
PrizeNum = 1, PrizeNum = 1,
@ -456,7 +532,7 @@ public class GoodsService : IGoodsService
PrizeCode = prizeCode, // 同一个 prize_code表示是同一个奖品配置 PrizeCode = prizeCode, // 同一个 prize_code表示是同一个奖品配置
Type = (byte)request.Type, Type = (byte)request.Type,
LianJiType = (byte)request.LianJiType, LianJiType = (byte)request.LianJiType,
RewardId = request.RewardId, RewardId = rewardId,
Doubling = request.Doubling, Doubling = request.Doubling,
IsLingzhu = (byte)request.IsLingzhu, IsLingzhu = (byte)request.IsLingzhu,
PrizeNum = 1, PrizeNum = 1,
@ -486,7 +562,7 @@ public class GoodsService : IGoodsService
/// 添加宝箱子奖品 /// 添加宝箱子奖品
/// 当父奖品存在于多个箱号中时,会为每个箱号的父奖品都创建对应的子奖品 /// 当父奖品存在于多个箱号中时,会为每个箱号的父奖品都创建对应的子奖品
/// </summary> /// </summary>
private async Task<int> AddChildPrizeAsync(int goodsId, PrizeCreateRequest request, DateTime now) private async Task<int> AddChildPrizeAsync(int goodsId, PrizeCreateRequest request, DateTime now, string? rewardId = null)
{ {
// 获取父奖品信息 // 获取父奖品信息
var parentPrize = await _dbContext.GoodsItems var parentPrize = await _dbContext.GoodsItems
@ -507,6 +583,12 @@ public class GoodsService : IGoodsService
// 子奖品生成自己的 prize_code // 子奖品生成自己的 prize_code
var childPrizeCode = GeneratePrizeCode(); var childPrizeCode = GeneratePrizeCode();
// 如果有 rewards 配置但没有传入 rewardId创建 rewards 表记录
if (string.IsNullOrEmpty(rewardId) && request.Rewards != null && request.Rewards.Count > 0)
{
rewardId = await CreatePrizeRewardsAsync(childPrizeCode, request.Rewards, now);
}
// 查找所有箱号中具有相同 prize_code 的父奖品(同一个宝箱配置在不同箱号中的记录) // 查找所有箱号中具有相同 prize_code 的父奖品(同一个宝箱配置在不同箱号中的记录)
var sameParentPrizes = await _dbContext.GoodsItems var sameParentPrizes = await _dbContext.GoodsItems
.AsNoTracking() .AsNoTracking()
@ -542,7 +624,7 @@ public class GoodsService : IGoodsService
PrizeCode = childPrizeCode, // 子奖品使用自己的 prize_code PrizeCode = childPrizeCode, // 子奖品使用自己的 prize_code
Type = (byte)request.Type, Type = (byte)request.Type,
LianJiType = (byte)request.LianJiType, LianJiType = (byte)request.LianJiType,
RewardId = request.RewardId, RewardId = rewardId,
Doubling = request.Doubling, Doubling = request.Doubling,
IsLingzhu = (byte)request.IsLingzhu, IsLingzhu = (byte)request.IsLingzhu,
PrizeNum = 1, PrizeNum = 1,
@ -572,6 +654,17 @@ public class GoodsService : IGoodsService
throw new BusinessException(BusinessErrorCodes.NotFound, "奖品不存在"); throw new BusinessException(BusinessErrorCodes.NotFound, "奖品不存在");
} }
var now = DateTime.Now;
// 处理奖励配置:如果有 rewards 配置,创建/更新 rewards 表记录
var rewardId = request.RewardId;
if (request.Rewards != null && request.Rewards.Count > 0)
{
// 使用现有的 prize_code 或生成新的
var prizeCode = prize.PrizeCode ?? GeneratePrizeCode();
rewardId = await CreatePrizeRewardsAsync(prizeCode, request.Rewards, now);
}
prize.Title = request.Title; prize.Title = request.Title;
prize.ImgUrl = request.ImgUrl; prize.ImgUrl = request.ImgUrl;
prize.ImgUrlDetail = request.ImgUrlDetail; prize.ImgUrlDetail = request.ImgUrlDetail;
@ -590,10 +683,10 @@ public class GoodsService : IGoodsService
prize.CardNo = request.CardNo; prize.CardNo = request.CardNo;
prize.Type = (byte)request.Type; prize.Type = (byte)request.Type;
prize.LianJiType = (byte)request.LianJiType; prize.LianJiType = (byte)request.LianJiType;
prize.RewardId = request.RewardId; prize.RewardId = rewardId;
prize.Doubling = request.Doubling; prize.Doubling = request.Doubling;
prize.IsLingzhu = (byte)request.IsLingzhu; prize.IsLingzhu = (byte)request.IsLingzhu;
prize.UpdatedAt = DateTime.Now; prize.UpdatedAt = now;
var result = await _dbContext.SaveChangesAsync() > 0; var result = await _dbContext.SaveChangesAsync() > 0;
@ -944,7 +1037,7 @@ public class GoodsService : IGoodsService
/// <summary> /// <summary>
/// 映射奖品到DTO /// 映射奖品到DTO
/// </summary> /// </summary>
private PrizeDto MapToPrizeDto(GoodsItem prize, Dictionary<int, PrizeLevelInfo>? prizeLevels = null) private PrizeDto MapToPrizeDto(GoodsItem prize, Dictionary<int, PrizeLevelInfo>? prizeLevels = null, Dictionary<string, List<PrizeRewardItem>>? rewardsDict = null)
{ {
string? shangTitle = null; string? shangTitle = null;
string? shangColor = null; string? shangColor = null;
@ -955,6 +1048,13 @@ public class GoodsService : IGoodsService
shangColor = level.Color; shangColor = level.Color;
} }
// 获取奖励配置
List<PrizeRewardItem>? rewards = null;
if (!string.IsNullOrEmpty(prize.RewardId) && rewardsDict != null && rewardsDict.TryGetValue(prize.RewardId, out var rewardList))
{
rewards = rewardList;
}
return new PrizeDto return new PrizeDto
{ {
Id = prize.Id, Id = prize.Id,
@ -985,6 +1085,7 @@ public class GoodsService : IGoodsService
Doubling = prize.Doubling, Doubling = prize.Doubling,
IsLingzhu = prize.IsLingzhu, IsLingzhu = prize.IsLingzhu,
GoodsListId = prize.GoodsListId, GoodsListId = prize.GoodsListId,
Rewards = rewards,
CreatedAt = prize.CreatedAt, CreatedAt = prize.CreatedAt,
UpdatedAt = prize.UpdatedAt UpdatedAt = prize.UpdatedAt
}; };

View File

@ -245,11 +245,18 @@ export interface PrizeItem {
doubling: number doubling: number
isLingzhu: number isLingzhu: number
goodsListId: number // 父奖品ID0表示父奖品>0表示子奖品 goodsListId: number // 父奖品ID0表示父奖品>0表示子奖品
rewards?: PrizeRewardItem[] // 奖励配置
createdAt: string | null createdAt: string | null
updatedAt: string updatedAt: string
children?: PrizeItem[] // 子奖品列表(前端构建树形结构用) children?: PrizeItem[] // 子奖品列表(前端构建树形结构用)
} }
/** 奖品奖励配置项 */
export interface PrizeRewardItem {
type: number // 奖励类型1=钻石 2=UU币 3=哈尼券
amount: number // 数量
}
/** 创建奖品请求 */ /** 创建奖品请求 */
export interface PrizeCreateRequest { export interface PrizeCreateRequest {
title: string title: string
@ -273,6 +280,7 @@ export interface PrizeCreateRequest {
doubling: number doubling: number
isLingzhu: number isLingzhu: number
goodsListId?: number // 父奖品ID添加宝箱子奖品时使用 goodsListId?: number // 父奖品ID添加宝箱子奖品时使用
rewards?: PrizeRewardItem[] // 奖励配置
} }
/** 更新奖品请求 */ /** 更新奖品请求 */

View File

@ -168,36 +168,9 @@
<!-- 赠送货币配置 --> <!-- 赠送货币配置 -->
<el-divider content-position="left">赠送配置</el-divider> <el-divider content-position="left">赠送配置</el-divider>
<el-row :gutter="20"> <el-form-item label="赠送奖励">
<el-col :span="8"> <PrizeRewardConfig v-model="formData.rewards" />
<el-form-item label="赠送余额">
<el-input-number
v-model="formData.giveMoney"
:min="0"
style="width: 100%"
placeholder="赠送余额"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="赠送积分">
<el-input-number
v-model="formData.rewardNum"
:min="0"
style="width: 100%"
placeholder="赠送积分"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="奖励ID">
<el-input
v-model="formData.rewardId"
placeholder="奖励配置ID"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 连击赏配置 --> <!-- 连击赏配置 -->
<el-row :gutter="20" v-if="showLianji"> <el-row :gutter="20" v-if="showLianji">
@ -255,6 +228,12 @@ import {
} from '@/api/business/goods' } from '@/api/business/goods'
import { getPrizeLevelOptionsByType, type PrizeLevelOptionResponse } from '@/api/business/prizelevel' import { getPrizeLevelOptionsByType, type PrizeLevelOptionResponse } from '@/api/business/prizelevel'
import ImageUpload from '@/components/ImageUpload/index.vue' import ImageUpload from '@/components/ImageUpload/index.vue'
import PrizeRewardConfig from './PrizeRewardConfig.vue'
interface RewardItem {
type: number
amount: number
}
interface Props { interface Props {
modelValue: boolean modelValue: boolean
@ -346,6 +325,7 @@ const formData = reactive({
cardNo: '', cardNo: '',
lianJiType: 0, lianJiType: 0,
rewardId: '', rewardId: '',
rewards: [] as RewardItem[],
}) })
// //
@ -382,6 +362,7 @@ const resetForm = () => {
formData.cardNo = '' formData.cardNo = ''
formData.lianJiType = 0 formData.lianJiType = 0
formData.rewardId = '' formData.rewardId = ''
formData.rewards = []
formRef.value?.resetFields() formRef.value?.resetFields()
} }
@ -435,6 +416,7 @@ const handleSubmit = async () => {
doubling: formData.doubling, doubling: formData.doubling,
isLingzhu: formData.isLingzhu, isLingzhu: formData.isLingzhu,
goodsListId: props.parentPrizeId, // ID goodsListId: props.parentPrizeId, // ID
rewards: formData.rewards.length > 0 ? formData.rewards : undefined,
} }
await addPrize(props.goodsId, requestData) await addPrize(props.goodsId, requestData)

View File

@ -169,36 +169,9 @@
<!-- 赠送货币配置 --> <!-- 赠送货币配置 -->
<el-divider content-position="left">赠送配置</el-divider> <el-divider content-position="left">赠送配置</el-divider>
<el-row :gutter="20"> <el-form-item label="赠送奖励">
<el-col :span="8"> <PrizeRewardConfig v-model="formData.rewards" />
<el-form-item label="赠送余额">
<el-input-number
v-model="formData.giveMoney"
:min="0"
style="width: 100%"
placeholder="赠送余额"
/>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="赠送积分">
<el-input-number
v-model="formData.rewardNum"
:min="0"
style="width: 100%"
placeholder="赠送积分"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="奖励ID">
<el-input
v-model="formData.rewardId"
placeholder="奖励配置ID"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 连击赏配置 --> <!-- 连击赏配置 -->
<el-row :gutter="20" v-if="showLianji"> <el-row :gutter="20" v-if="showLianji">
@ -263,6 +236,12 @@ import {
} from '@/api/business/goods' } from '@/api/business/goods'
import { getPrizeLevelOptionsByType, type PrizeLevelOptionResponse } from '@/api/business/prizelevel' import { getPrizeLevelOptionsByType, type PrizeLevelOptionResponse } from '@/api/business/prizelevel'
import ImageUpload from '@/components/ImageUpload/index.vue' import ImageUpload from '@/components/ImageUpload/index.vue'
import PrizeRewardConfig from './PrizeRewardConfig.vue'
interface RewardItem {
type: number
amount: number
}
interface Props { interface Props {
modelValue: boolean modelValue: boolean
@ -342,6 +321,7 @@ const formData = reactive({
cardNo: '', cardNo: '',
lianJiType: 0, lianJiType: 0,
rewardId: '', rewardId: '',
rewards: [] as RewardItem[],
}) })
// //
@ -377,6 +357,12 @@ const fillFormData = (data: PrizeItem) => {
formData.cardNo = data.cardNo || '' formData.cardNo = data.cardNo || ''
formData.lianJiType = data.lianJiType formData.lianJiType = data.lianJiType
formData.rewardId = data.rewardId || '' formData.rewardId = data.rewardId || ''
//
if (data.rewards && data.rewards.length > 0) {
formData.rewards = data.rewards.map(r => ({ type: r.type, amount: r.amount }))
} else {
formData.rewards = []
}
} }
// //
@ -402,6 +388,7 @@ const resetForm = () => {
formData.cardNo = '' formData.cardNo = ''
formData.lianJiType = 0 formData.lianJiType = 0
formData.rewardId = '' formData.rewardId = ''
formData.rewards = []
formRef.value?.resetFields() formRef.value?.resetFields()
} }
@ -458,6 +445,7 @@ const handleSubmit = async () => {
rewardId: formData.rewardId || undefined, rewardId: formData.rewardId || undefined,
doubling: formData.doubling, doubling: formData.doubling,
isLingzhu: formData.isLingzhu, isLingzhu: formData.isLingzhu,
rewards: formData.rewards.length > 0 ? formData.rewards : undefined,
} }
await updatePrize(props.prizeId, requestData) await updatePrize(props.prizeId, requestData)

View File

@ -0,0 +1,119 @@
<template>
<div class="prize-reward-config">
<div v-for="(item, index) in rewardList" :key="index" class="reward-item">
<el-select
v-model="item.type"
placeholder="奖励类型"
style="width: 120px"
@change="handleChange"
>
<el-option
v-for="opt in rewardTypeOptions"
:key="opt.value"
:label="opt.label"
:value="opt.value"
/>
</el-select>
<el-input-number
v-model="item.amount"
:min="0"
:max="999999999"
placeholder="数量"
style="width: 150px; margin-left: 8px"
@change="handleChange"
/>
<el-button
type="danger"
:icon="Delete"
circle
size="small"
style="margin-left: 8px"
@click="removeItem(index)"
/>
</div>
<el-button type="primary" link @click="addItem" style="margin-top: 8px">
<el-icon><Plus /></el-icon>
</el-button>
</div>
</template>
<script setup lang="ts">
import { ref, watch, onMounted } from 'vue'
import { Plus, Delete } from '@element-plus/icons-vue'
interface RewardItem {
type: number
amount: number
}
interface Props {
modelValue: RewardItem[]
}
const props = withDefaults(defineProps<Props>(), {
modelValue: () => []
})
const emit = defineEmits<{
(e: 'update:modelValue', value: RewardItem[]): void
}>()
//
const rewardTypeOptions = [
{ label: '钻石', value: 1 },
{ label: 'HH币', value: 2 },
{ label: '哈尼券', value: 3 }
]
//
const rewardList = ref<RewardItem[]>([])
//
watch(() => props.modelValue, (newVal) => {
if (Array.isArray(newVal) && newVal.length > 0) {
rewardList.value = newVal.map(item => ({ ...item }))
} else {
rewardList.value = []
}
}, { immediate: true, deep: true })
//
const handleChange = () => {
// 0
const validList = rewardList.value.filter(item => item.amount > 0)
emit('update:modelValue', validList)
}
//
const addItem = () => {
rewardList.value.push({ type: 1, amount: 0 })
}
//
const removeItem = (index: number) => {
rewardList.value.splice(index, 1)
handleChange()
}
onMounted(() => {
if (Array.isArray(props.modelValue) && props.modelValue.length > 0) {
rewardList.value = props.modelValue.map(item => ({ ...item }))
}
})
</script>
<style scoped>
.prize-reward-config {
width: 100%;
}
.reward-item {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.reward-item:last-child {
margin-bottom: 0;
}
</style>

View File

@ -120,8 +120,8 @@ export const defaultFieldConfig: GoodsTypeFieldConfig = {
showLianji: false, showLianji: false,
showTimeConfig: false, showTimeConfig: false,
showAutoXiajia: false, showAutoXiajia: false,
showCoupon: true, showCoupon: false,
showIntegral: true, showIntegral: false,
showDescription: false, showDescription: false,
showQuanjuXiangou: false, showQuanjuXiangou: false,
showShowIs: true, showShowIs: true,
@ -148,7 +148,7 @@ export const GoodsTypeFieldConfigs: Record<number, GoodsTypeFieldConfig> = {
showStock: true, showLock: true, showDailyLimit: true, showStock: true, showLock: true, showDailyLimit: true,
showRage: false, showItemCard: false, showLingzhu: false, showRage: false, showItemCard: false, showLingzhu: false,
showLianji: false, showTimeConfig: false, showAutoXiajia: false, showLianji: false, showTimeConfig: false, showAutoXiajia: false,
showCoupon: true, showIntegral: true, showDescription: false, showCoupon: false, showIntegral: false, showDescription: false,
showQuanjuXiangou: false, showShowIs: true, showUnlockAmount: true, showQuanjuXiangou: false, showShowIs: true, showUnlockAmount: true,
showCoverImage: true, showDetailImage: true, showCoverImage: true, showDetailImage: true,
showPrice: true, showShouZhe: true, showPrice: true, showShouZhe: true,
@ -158,7 +158,7 @@ export const GoodsTypeFieldConfigs: Record<number, GoodsTypeFieldConfig> = {
showStock: false, showLock: false, showDailyLimit: false, showStock: false, showLock: false, showDailyLimit: false,
showRage: false, showItemCard: false, showLingzhu: false, showRage: false, showItemCard: false, showLingzhu: false,
showLianji: false, showTimeConfig: false, showAutoXiajia: false, showLianji: false, showTimeConfig: false, showAutoXiajia: false,
showCoupon: true, showIntegral: true, showDescription: false, showCoupon: false, showIntegral: false, showDescription: false,
showQuanjuXiangou: false, showShowIs: false, showUnlockAmount: true, showQuanjuXiangou: false, showShowIs: false, showUnlockAmount: true,
showCoverImage: true, showDetailImage: true, showCoverImage: true, showDetailImage: true,
showPrice: true, showShouZhe: true, showPrice: true, showShouZhe: true,

View File

@ -89,6 +89,14 @@ public class WelfareLotteryService : BackgroundService
.Where(gi => gi.GoodsId == goods.Id && gi.Num == 0) .Where(gi => gi.GoodsId == goods.Id && gi.Num == 0)
.ToListAsync(stoppingToken); .ToListAsync(stoppingToken);
// 添加调试日志:输出所有奖品信息
_logger.LogInformation("福利屋奖品列表: GoodsId={GoodsId}, 奖品数量={Count}", goods.Id, prizeList.Count);
foreach (var p in prizeList)
{
_logger.LogInformation(" 奖品: Id={Id}, Title={Title}, GoodsType={GoodsType}, RewardId={RewardId}, Stock={Stock}, SurplusStock={SurplusStock}, ScMoney={ScMoney}",
p.Id, p.Title, p.GoodsType, p.RewardId ?? "(空)", p.Stock, p.SurplusStock, p.ScMoney);
}
// 展开奖品列表(根据库存数量) // 展开奖品列表(根据库存数量)
var expandedPrizes = new List<GoodsItem>(); var expandedPrizes = new List<GoodsItem>();
foreach (var prize in prizeList) foreach (var prize in prizeList)
@ -176,9 +184,14 @@ public class WelfareLotteryService : BackgroundService
} }
// 发放奖励 // 发放奖励
// 添加调试日志
_logger.LogInformation("准备发放奖励: PrizeId={PrizeId}, Title={Title}, GoodsType={GoodsType}, RewardId={RewardId}, ScMoney={ScMoney}, UserId={UserId}",
prize.Id, prize.Title, prize.GoodsType, prize.RewardId ?? "(空)", prize.ScMoney, participant.UserId);
// 1. 如果有reward_id字符串类型奖励码通过奖励配置发放 // 1. 如果有reward_id字符串类型奖励码通过奖励配置发放
if (!string.IsNullOrEmpty(prize.RewardId)) if (!string.IsNullOrEmpty(prize.RewardId))
{ {
_logger.LogInformation("尝试通过RewardId发放奖励: RewardId={RewardId}", prize.RewardId);
var rewardSent = await SendRewardByCodeAsync(dbContext, participant.UserId, prize.RewardId, var rewardSent = await SendRewardByCodeAsync(dbContext, participant.UserId, prize.RewardId,
$"{goods.Title}开奖-{prize.Title}", stoppingToken); $"{goods.Title}开奖-{prize.Title}", stoppingToken);
if (rewardSent) if (rewardSent)
@ -188,13 +201,14 @@ public class WelfareLotteryService : BackgroundService
} }
else else
{ {
_logger.LogWarning("奖励配置不存在: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, RewardCode={RewardCode}", _logger.LogWarning("奖励配置不存在或发放失败: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, RewardCode={RewardCode}",
goods.Id, participant.UserId, prize.Title, prize.RewardId); goods.Id, participant.UserId, prize.Title, prize.RewardId);
} }
} }
// 2. 如果是货币类型奖品GoodsType=3且没有reward_id直接发放ScMoney金额 // 2. 如果是货币类型奖品GoodsType=3且没有reward_id直接发放ScMoney金额
else if (prize.GoodsType == 3 && prize.ScMoney > 0) else if (prize.GoodsType == 3 && prize.ScMoney > 0)
{ {
_logger.LogInformation("尝试通过GoodsType=3发放货币奖品: ScMoney={ScMoney}", prize.ScMoney);
await SendCurrencyPrizeAsync(dbContext, participant.UserId, prize.ScMoney, await SendCurrencyPrizeAsync(dbContext, participant.UserId, prize.ScMoney,
$"{goods.Title}开奖-{prize.Title}", stoppingToken); $"{goods.Title}开奖-{prize.Title}", stoppingToken);
_logger.LogInformation("发放货币奖品成功: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, Amount={Amount}", _logger.LogInformation("发放货币奖品成功: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, Amount={Amount}",
@ -202,8 +216,8 @@ public class WelfareLotteryService : BackgroundService
} }
else else
{ {
_logger.LogInformation("发放奖品成功: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}", _logger.LogInformation("实物奖品,无需发放货币: GoodsId={GoodsId}, UserId={UserId}, Prize={Prize}, GoodsType={GoodsType}",
goods.Id, participant.UserId, prize.Title); goods.Id, participant.UserId, prize.Title, prize.GoodsType);
} }
prizeIndex++; prizeIndex++;
@ -240,6 +254,7 @@ public class WelfareLotteryService : BackgroundService
/// <summary> /// <summary>
/// 通过奖励码发放奖励 /// 通过奖励码发放奖励
/// 支持同一个 reward_id 对应多条奖励记录(如同时赠送钻石和积分)
/// </summary> /// </summary>
/// <param name="dbContext">数据库上下文</param> /// <param name="dbContext">数据库上下文</param>
/// <param name="userId">用户ID</param> /// <param name="userId">用户ID</param>
@ -254,17 +269,28 @@ public class WelfareLotteryService : BackgroundService
string remark, string remark,
CancellationToken stoppingToken) CancellationToken stoppingToken)
{ {
// 通过奖励码查询奖励配置 _logger.LogInformation("SendRewardByCodeAsync开始: UserId={UserId}, RewardCode={RewardCode}", userId, rewardCode);
var reward = await dbContext.Rewards
.Where(r => r.RewardId == rewardCode)
.FirstOrDefaultAsync(stoppingToken);
if (reward == null) // 通过奖励码查询所有奖励配置(同一个 reward_id 可能有多条记录)
var rewards = await dbContext.Rewards
.Where(r => r.RewardId == rewardCode)
.ToListAsync(stoppingToken);
_logger.LogInformation("查询rewards表结果: RewardCode={RewardCode}, 找到记录数={Count}", rewardCode, rewards?.Count ?? 0);
if (rewards == null || rewards.Count == 0)
{ {
_logger.LogWarning("奖励配置不存在: RewardCode={RewardCode}", rewardCode); _logger.LogWarning("奖励配置不存在: RewardCode={RewardCode}", rewardCode);
return false; return false;
} }
// 输出每条奖励记录的详情
foreach (var r in rewards)
{
_logger.LogInformation(" 奖励记录: Id={Id}, RewardId={RewardId}, RewardType={RewardType}, RewardValue={RewardValue}",
r.Id, r.RewardId, r.RewardType, r.RewardValue);
}
var user = await dbContext.Users var user = await dbContext.Users
.Where(u => u.Id == userId) .Where(u => u.Id == userId)
.FirstOrDefaultAsync(stoppingToken); .FirstOrDefaultAsync(stoppingToken);
@ -275,12 +301,17 @@ public class WelfareLotteryService : BackgroundService
return false; return false;
} }
var rewardTypeName = ""; _logger.LogInformation("用户当前余额: UserId={UserId}, Money={Money}, Integral={Integral}, Money2={Money2}",
userId, user.Money, user.Integral, user.Money2);
// 根据奖励类型发放 var rewardDetails = new List<string>();
// 遍历所有奖励记录,根据类型发放
foreach (var reward in rewards)
{
switch (reward.RewardType) switch (reward.RewardType)
{ {
case 1: // 钻石/余额 (HH币) case 1: // 钻石
user.Money += reward.RewardValue; user.Money += reward.RewardValue;
// 记录流水 // 记录流水
dbContext.ProfitMoneys.Add(new ProfitMoney dbContext.ProfitMoneys.Add(new ProfitMoney
@ -293,12 +324,12 @@ public class WelfareLotteryService : BackgroundService
ShareUid = 0, ShareUid = 0,
CreatedAt = DateTime.Now CreatedAt = DateTime.Now
}); });
rewardTypeName = "钻石/HH币"; rewardDetails.Add($"钻石{reward.RewardValue}");
_logger.LogInformation("发放钻石: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}", _logger.LogInformation("发放钻石: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}",
userId, reward.RewardValue, user.Money, remark); userId, reward.RewardValue, user.Money, remark);
break; break;
case 2: // 积分/UU case 2: // HH
user.Integral += reward.RewardValue; user.Integral += reward.RewardValue;
// 记录流水 // 记录流水
dbContext.ProfitIntegrals.Add(new ProfitIntegral dbContext.ProfitIntegrals.Add(new ProfitIntegral
@ -311,12 +342,12 @@ public class WelfareLotteryService : BackgroundService
ShareUid = 0, ShareUid = 0,
CreatedAt = DateTime.Now CreatedAt = DateTime.Now
}); });
rewardTypeName = "积分/UU币"; rewardDetails.Add($"HH币{reward.RewardValue}");
_logger.LogInformation("发放积分: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}", _logger.LogInformation("发放HH币: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}",
userId, reward.RewardValue, user.Integral, remark); userId, reward.RewardValue, user.Integral, remark);
break; break;
case 3: // 哈尼券/达达卷 case 3: // 哈尼券
user.Money2 = (user.Money2 ?? 0) + reward.RewardValue; user.Money2 = (user.Money2 ?? 0) + reward.RewardValue;
// 记录流水 // 记录流水
dbContext.ProfitMoney2s.Add(new ProfitMoney2 dbContext.ProfitMoney2s.Add(new ProfitMoney2
@ -329,20 +360,27 @@ public class WelfareLotteryService : BackgroundService
ShareUid = 0, ShareUid = 0,
CreatedAt = DateTime.Now CreatedAt = DateTime.Now
}); });
rewardTypeName = "哈尼券"; rewardDetails.Add($"哈尼券{reward.RewardValue}");
_logger.LogInformation("发放哈尼券: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}", _logger.LogInformation("发放哈尼券: UserId={UserId}, Amount={Amount}, After={After}, Remark={Remark}",
userId, reward.RewardValue, user.Money2, remark); userId, reward.RewardValue, user.Money2, remark);
break; break;
default: default:
_logger.LogWarning("未知奖励类型: Type={Type}, RewardCode={RewardCode}", reward.RewardType, rewardCode); _logger.LogWarning("未知奖励类型: Type={Type}, RewardCode={RewardCode}", reward.RewardType, rewardCode);
break;
}
}
if (rewardDetails.Count == 0)
{
_logger.LogWarning("没有有效的奖励类型: RewardCode={RewardCode}", rewardCode);
return false; return false;
} }
await dbContext.SaveChangesAsync(stoppingToken); await dbContext.SaveChangesAsync(stoppingToken);
_logger.LogInformation("福利屋奖励发放成功: UserId={UserId}, RewardCode={RewardCode}, Type={Type}, Value={Value}, Remark={Remark}", _logger.LogInformation("福利屋奖励发放成功: UserId={UserId}, RewardCode={RewardCode}, Rewards={Rewards}, Remark={Remark}",
userId, rewardCode, rewardTypeName, reward.RewardValue, remark); userId, rewardCode, string.Join("+", rewardDetails), remark);
return true; return true;
} }

View File

@ -123,16 +123,16 @@ public class RewardService : IRewardService
detail.Message = $"获得钻石*{rewardValue}"; detail.Message = $"获得钻石*{rewardValue}";
break; break;
case 2: // UU币 (Integral) case 2: // HH币 (Integral)
await AddIntegralAsync(userId, user, rewardValue, source); await AddIntegralAsync(userId, user, rewardValue, source);
detail.Success = true; detail.Success = true;
detail.Message = $"获得UU币*{rewardValue}"; detail.Message = $"获得HH币*{rewardValue}";
break; break;
case 3: // 达达券 (Money2) case 3: // 哈尼券 (Money2)
await AddMoney2Async(userId, user, rewardValue, source); await AddMoney2Async(userId, user, rewardValue, source);
detail.Success = true; detail.Success = true;
detail.Message = $"获得达达券*{rewardValue}"; detail.Message = $"获得哈尼券*{rewardValue}";
break; break;
case 4: // 优惠券 case 4: // 优惠券