From 316876ce8dd7b22f1cb311fc863690af44904ec3 Mon Sep 17 00:00:00 2001 From: Ethereal <3432649580@qq.com> Date: Sat, 19 Jul 2025 09:30:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E9=80=82=E9=85=8D+=E9=80=BB?= =?UTF-8?q?=E8=BE=91=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/choujiang/index.vue | 98 +++++++- src/views/choujiang/lottery/CardItem.vue | 53 ++--- src/views/choujiang/lottery/ControlBar.vue | 55 ++++- src/views/choujiang/lottery/Lottery3D.vue | 335 +++++++++++++++------------ src/views/choujiang/lottery/PrizePanel.vue | 141 +++++++++-- src/views/choujiang/lottery/dataManager.js | 217 +++++++---------- src/views/choujiang/lottery/lotteryEngine.js | 129 +++++++++-- 7 files changed, 656 insertions(+), 372 deletions(-) diff --git a/src/views/choujiang/index.vue b/src/views/choujiang/index.vue index 5e6c271..894f7c3 100644 --- a/src/views/choujiang/index.vue +++ b/src/views/choujiang/index.vue @@ -12,6 +12,14 @@ @export="handleExport" /> + + +
+ +
+ -
{{ (user[0] || "") + "\n" + (user[2] || "") }}
+
{{ (user[0] || "") + "\n" }}
@@ -34,45 +34,39 @@ const props = defineProps({ prize: Boolean, }); const cardStyle = computed(() => { + // 基础样式 + const baseStyle = { + width: "130px", + height: "170px", + border: "1px solid rgb(255,255,255)", + }; + if (props.isBold && props.showTable) { if (lotteryState.value === "idle") { return { - // backgroundColor: "rgba(226, 60, 38, 1)", - background: 'linear-gradient(135deg, rgba(243,153,38,0.7) 0%, rgba(207,56,35,1) 100%)', - width: "130px", - height: "170px", + ...baseStyle, + background: 'linear-gradient(180deg, rgba(243,153,38,0.7) 0%, rgba(207,56,35,1) 100%)', }; } } - // return { - // // background: 'linear-gradient(135deg,rgba(255, 170, 22, 100) 0%, rgba(255, 170, 22, 100) 100%)', - // backgroundColor:'rgba(254, 177, 48, 100)', - // width: '130px', - // height: '170px', - // border: '1px solid rgb(255,255,255)', - // }; - if (lotteryState.value === "result") { - return { - background: 'linear-gradient(135deg,rgba(255, 170, 22, 100) 0%, rgba(255, 170, 22, 100) 100%)', - // backgroundColor: "rgba(254, 177, 48, 100)", - width: "130px", - height: "170px", - border: "1px solid rgb(255,255,255)", - }; - } else { - return { - backgroundColor: "rgba(254, 177, 48, 100)", - width: "130px", - height: "170px", - border: "1px solid rgb(255,255,255)", - }; + + // 如果是result状态且有prize类,不设置背景色,让CSS类控制 + if (lotteryState.value === "result" && props.prize) { + return baseStyle; } + + // 其他情况都显示默认背景色 + return { + ...baseStyle, + backgroundColor: "rgba(254, 177, 48, 100)", + }; }); \ No newline at end of file diff --git a/src/views/choujiang/lottery/Lottery3D.vue b/src/views/choujiang/lottery/Lottery3D.vue index 486c319..4de26e2 100644 --- a/src/views/choujiang/lottery/Lottery3D.vue +++ b/src/views/choujiang/lottery/Lottery3D.vue @@ -29,6 +29,7 @@ import TWEEN from "@tweenjs/tween.js"; import { NUMBER_MATRIX } from "../../../utils/config.js"; import CardItem from "./CardItem.vue"; import { createApp } from "vue"; +import { getUserList } from "../../../api/API"; const threeContainer = ref(null); let renderer, scene, camera, animationId; // let controls; // 移除controls @@ -247,11 +248,20 @@ function selectCard(selectedCardIndex, currentLuckys, duration = 600) { const pageIndex = index % cardsPerPage; const pageLocate = pageLocates[cardPage][pageIndex]; + // 设置初始位置:第一页的卡片正常显示,其他页的卡片从下方隐藏 + let initialY; + if (isVisible) { + initialY = pageLocate.y; + } else { + // 非第一页的卡片从下方隐藏(为后续向上飞出做准备) + initialY = pageLocate.y - 1000; + } + new TWEEN.Tween(object.position) .to( { - x: isVisible ? pageLocate.x : pageLocate.x, - y: isVisible ? pageLocate.y : pageLocate.y + 1000, // 隐藏的卡片移到下方 + x: pageLocate.x, + y: initialY, z: 2200, }, Math.random() * duration + duration @@ -315,16 +325,58 @@ function switchPage(direction) { const object = threeDCards[cardIndex]; const cardPage = Math.floor(index / cardsPerPage); const isVisible = cardPage === newPage; + const wasVisible = cardPage === currentPage.value; // 计算在当前页中的索引 const pageIndex = index % cardsPerPage; const pageLocate = pageLocates[cardPage][pageIndex]; + // 根据切换方向决定动画效果 + let targetY; + if (isVisible) { + // 当前页要显示的卡片 + if (direction === 'next') { + // 索引增大:从下方飞出 + targetY = pageLocate.y; + } else { + // 索引减少:从上方飞出 + targetY = pageLocate.y; + } + } else { + // 当前页要隐藏的卡片 + if (direction === 'next') { + // 索引增大:向上飞走 + targetY = pageLocate.y + 1000; + } else { + // 索引减少:向下飞走 + targetY = pageLocate.y - 1000; + } + } + + // 设置起始位置 + let startY; + if (wasVisible) { + // 当前页的卡片从当前位置开始 + startY = object.position.y; + } else { + // 非当前页的卡片从隐藏位置开始 + if (direction === 'next') { + // 索引增大:从下方开始 + startY = pageLocate.y - 1000; + } else { + // 索引减少:从上方开始 + startY = pageLocate.y + 1000; + } + } + + // 先设置起始位置 + object.position.y = startY; + new TWEEN.Tween(object.position) .to( { x: pageLocate.x, - y: isVisible ? pageLocate.y : pageLocate.y + 1000, + y: targetY, z: 2200, }, duration @@ -345,58 +397,6 @@ function switchPage(direction) { } -// function switchPage(direction) { -// if (isPageTransitioning || totalPages.value <= 1) return; - -// const newPage = direction === 'next' ? currentPage.value + 1 : currentPage.value - 1; -// if (newPage < 0 || newPage >= totalPages.value) return; - -// isPageTransitioning = true; -// const duration = 800; - -// // 使用保存的页面位置信息 -// const pageLocates = window.pageLocates; -// if (!pageLocates) { -// console.error('页面位置信息未找到'); -// isPageTransitioning = false; -// return; -// } - -// // 动画切换卡片位置 -// globalCardIndexes.forEach((cardIndex, index) => { -// const object = threeDCards[cardIndex]; -// const cardPage = Math.floor(index / cardsPerPage); -// const isVisible = cardPage === newPage; - -// // 计算在当前页中的索引 -// const pageIndex = index % cardsPerPage; -// const pageLocate = pageLocates[cardPage][pageIndex]; - -// // 修改目标位置以实现从上方或下方飞出的效果 -// new TWEEN.Tween(object.position) -// .to( -// { -// x: pageLocate.x, -// y: isVisible ? pageLocate.y : (direction === 'next' ? pageLocate.y - 1000 : pageLocate.y + 1000), // 向下翻页时从上方下落,向上翻页时从下方飞出 -// z: 2200, -// }, -// duration -// ) -// .easing(TWEEN.Easing.Cubic.InOut) -// .start(); -// }); - -// new TWEEN.Tween({}) -// .to({}, duration) -// .onUpdate(() => render()) -// .onComplete(() => { -// currentPage.value = newPage; -// isPageTransitioning = false; -// console.log(`切换到第 ${currentPage.value + 1} 页,共 ${totalPages.value} 页`); -// }) -// .start(); -// } - // 鼠标滚轮事件处理 function handleWheel(event) { if (isPageTransitioning || totalPages.value <= 1) return; @@ -443,6 +443,9 @@ function resetCard(selectedCardIndex, duration = 500) { if (window.pageLocates) { delete window.pageLocates; } + + // 清空全局卡片索引数组 + globalCardIndexes = []; selectedCardIndex.forEach((index) => { const object = threeDCards[index]; @@ -481,6 +484,11 @@ function resetCard(selectedCardIndex, duration = 500) { .onComplete(() => { selectedCardIndex.forEach((index) => { const object = threeDCards[index]; + // 恢复原始内容 + if (object.element.dataset.originalContent) { + object.element.innerHTML = object.element.dataset.originalContent; + delete object.element.dataset.originalContent; + } object.element.classList.remove("prize"); }); resolve(); @@ -495,19 +503,22 @@ function changeCard(cardIndex, user) { } const card = threeDCards[cardIndex].element; - // card.innerHTML = `
${ - // user.company || "" - // }
${user[1]}
${ - // user[0] || "" - // }
${user[2] || "PSST"}
`; - - card.style.setProperty('background-color', '#ffffff', 'important'); - - // card.style.backgroundColor = '#ffffff'; - - // card.style.backgroundColor = ''; - + + // 保存原始内容,以便后续恢复 + if (!card.dataset.originalContent) { + card.dataset.originalContent = card.innerHTML; + } + + // 设置中奖内容 - 适配后端返回的数据格式 + // 后端返回的数据格式: { jwcode: "5412", username: "猪八戒22" } + const jwcode = user.jwcode || user[0] || ""; + const username = user.username || user[1] || ""; + const company = user.company || user[2] || "PSST"; + + card.innerHTML = `
${jwcode}
`; + // 添加中奖样式类 + card.classList.add("prize"); } function changeCard1() { @@ -528,10 +539,15 @@ function changeCard1() { globalCardIndexes.forEach(cardIndex => { const card = threeDCards[cardIndex].element; - console.log('取消卡片', cardIndex, '的高光'); - card.style.setProperty('background-color', 'rgba(254, 177, 48, 1)', 'important'); + // console.log('取消卡片', cardIndex, '的高光'); + + // 恢复原始内容 + if (card.dataset.originalContent) { + card.innerHTML = card.dataset.originalContent; + delete card.dataset.originalContent; + } - // 移除prize类,因为CSS规则会覆盖backgroundColor + // 移除prize类,让CardItem组件的样式重新生效 card.classList.remove('prize'); }); // 清空数组 @@ -623,7 +639,7 @@ function getTotalCards() { return threeDCards.length; } -onMounted(() => { + onMounted( async () => { // 初始化 3D 场景 scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera( @@ -650,88 +666,89 @@ onMounted(() => { HIGHLIGHT_CELL: highlightCells, COMPANY: "演示公司", }; - const member = [ - [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], - [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], - [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], - [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], - ]; + + const userList = await getUserList(); + console.log("userList", userList); + // 将用户数据转换为兼容格式,用于3D卡片显示 + const member = userList.data.map(item => [item.jwcode, item.username, "PSST"]); +// const member = [ +// [1], +// [2], +// [3], +// [4], +// [5], +// [6], +// [7], +// [8], +// [9], +// [10], +// [11], +// [12], +// [13], +// [14], +// [15], +// [16], +// [17], +// [18], +// [19], +// [20], +// [21], +// [22], +// [23], +// [24], +// [25], +// [26], +// [27], +// [28], +// [29], +// [30], +// [31], +// [32], +// [33], +// [34], +// [35], +// [36], +// [37], +// [38], +// [39], +// [40], +// [41], +// [42], +// [43], +// [44], +// [45], +// [46], +// [47], +// [48], +// [49], +// [50], +// [51], +// [52], +// [53], +// [54], +// [55], +// [56], +// [57], +// [58], +// [59], +// [60], +// [61], +// [62], +// [63], +// [64], +// [65], +// [66], +// [67], +// [68], +// [69], +// [70], +// [71], +// [72], +// [73], +// [74], +// [75], +// [76], +// ]; const length = member.length; const showTable = true; const position = { @@ -836,6 +853,18 @@ defineExpose({ animation: fadeInOut 2s ease-in-out infinite; } +.price-font{ + font-size: 16px; + font-weight: bold; + color: #ffffff; + text-align: center; + display: flex; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; +} + @keyframes fadeInOut { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } diff --git a/src/views/choujiang/lottery/PrizePanel.vue b/src/views/choujiang/lottery/PrizePanel.vue index 64a348d..f834623 100644 --- a/src/views/choujiang/lottery/PrizePanel.vue +++ b/src/views/choujiang/lottery/PrizePanel.vue @@ -6,9 +6,17 @@ class="prize-panel-item" v-for="(prize, idx) in prizes" :key="prize.type || idx" - :class="{ 'revealed-highlight': idx === lastRevealedIdx }" + :class="{ + 'revealed-highlight': idx === lastRevealedIdx, + disabled: idx === nextRevealIdx && !canRevealPrize(idx), + }" @click="handleReveal(idx)" - style="cursor: pointer" + :style="{ + cursor: + idx === nextRevealIdx && !canRevealPrize(idx) + ? 'not-allowed' + : 'pointer', + }" >
@@ -26,7 +34,7 @@ :style="{ width: getProgressPercent(prize) + '%' }" >
- {{ prize.count - getLeftCount(prize) }}/{{ prize.count }} + {{ getLeftCount(prize) }}/{{ prize.count }}
@@ -84,7 +92,10 @@
-
+
- +
- {{ prizes[lastRevealedIdx].title }} - {{ prizes[lastRevealedIdx].text }} + {{ + prizes[lastRevealedIdx].title + }} + {{ + prizes[lastRevealedIdx].text + }}
- {{ prizes[lastRevealedIdx].count - getLeftCount(prizes[lastRevealedIdx]) }}/{{ prizes[lastRevealedIdx].count }} + {{ getLeftCount(prizes[lastRevealedIdx]) }}/{{ + prizes[lastRevealedIdx].count + }}
@@ -159,16 +182,27 @@ @@ -501,10 +577,37 @@ function getProgressPercent(prize) { border-radius: 8px 8px 8px 8px; } .prize-panel-item.revealed-highlight { - border: 3px solid #ff9800; + /* border: 3px solid #ff9800; */ box-shadow: 0 0 16px 4px #ff9800aa; transform: scale(1.05); z-index: 2; transition: all 0.3s; } + +.prize-panel-item.disabled { + cursor: not-allowed !important; + position: relative; +} + +.prize-panel-item.disabled::after { + content: "请先抽完上一个奖品"; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: rgba(0, 0, 0, 0.8); + color: white; + padding: 8px 12px; + border-radius: 6px; + font-size: 14px; + white-space: nowrap; + z-index: 10; + opacity: 0; + transition: opacity 0.3s; + pointer-events: none; +} + +.prize-panel-item.disabled:hover::after { + opacity: 1; +} \ No newline at end of file diff --git a/src/views/choujiang/lottery/dataManager.js b/src/views/choujiang/lottery/dataManager.js index 6737279..0634555 100644 --- a/src/views/choujiang/lottery/dataManager.js +++ b/src/views/choujiang/lottery/dataManager.js @@ -1,5 +1,5 @@ import { reactive } from 'vue'; - +import { getPrizeList, getUserList } from '../../../api/API'; export function useDataManager() { const state = reactive({ basicData: { @@ -12,94 +12,56 @@ export function useDataManager() { currentPrize: null, currentLuckys: [], isLotting: false, + // 新增:轮次管理 + currentRound: 1, config: { prizes: [], EACH_COUNT: [], COMPANY: '', HIGHLIGHT_CELL: [], - Resolution: 1 + Resolution: 1, + ROW_COUNT: 7, + COLUMN_COUNT: 20 } }); async function getBasicData() { - // 假数据,后续可替换为接口 - const fakePrizes = [ - { type: 0, title: '特别奖', text: 'iPad', count: 10, img: '/src/assets/lottery/ipad.jpg' }, - { type: 1, title: '一等奖', text: 'Kindle', count: 20, img: '/src/assets/lottery/kindle.jpg' }, - { type: 2, title: '二等奖', text: 'MacBook Pro', count: 10, img: '/src/assets/lottery/mbp.jpg' } - ]; - const fakeEachCount = [15, 17, 36]; + // 获取奖品列表 + const prizeList = await getPrizeList(); + const fakePrizes = prizeList.data.map((item, index) => ({ + type: index, // 使用索引作为type + title: item.gradeName, + text: item.prizeName, + count: item.amount, + img: item.imageUrl + })); + + const fakeEachCount = prizeList.data.map(item => item.perWin); + console.log("fakeEachCount", fakeEachCount); const fakeCompany = '前端假公司'; const fakeLuckyData = {}; - fakePrizes.forEach(prize => { - fakeLuckyData[prize.type] = []; + fakePrizes.forEach((prize, index) => { + fakeLuckyData[index] = []; }); - const fakeLeftUsers = [ - [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], - ]; + + // 获取真实用户数据 + const userListResponse = await getUserList(); + console.log("userList", userListResponse); + + // 将后端返回的用户数据转换为兼容格式 + const realUsers = userListResponse.data.map(item => ({ + jwcode: item.jwcode, + username: item.username, + company: fakeCompany // 使用默认公司名称 + })); + state.config.prizes = fakePrizes; state.config.EACH_COUNT = fakeEachCount; state.config.COMPANY = fakeCompany; state.config.HIGHLIGHT_CELL = []; state.basicData.prizes = fakePrizes; - state.basicData.leftUsers = fakeLeftUsers.slice(); + state.basicData.users = realUsers; // 使用真实用户数据 + state.basicData.leftUsers = realUsers.slice(); // 初始化剩余用户为所有用户 state.basicData.luckyUsers = fakeLuckyData; determineCurrentPrize(); return Promise.resolve({ @@ -108,74 +70,24 @@ export function useDataManager() { EACH_COUNT: fakeEachCount, COMPANY: fakeCompany }, - leftUsers: fakeLeftUsers.slice(), + leftUsers: realUsers.slice(), luckyData: fakeLuckyData }); } async function getUsers() { - const fakeUsers = [ - [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], [0, "张三"], - [1, "李四"], - [2, "王五"], - [3, "赵六"], - [4, "孙七"], - [5, "周八"], - [6, "吴九"], - [7, "郑十"], - [8, "钱十一"], - [9, "孙十二"], - [10, "李十三"], - [11, "周十四"], - [12, "吴十五"], - [13, "郑十六"], - [14, "钱十七"], - [15, "孙十八"], - [16, "李十九"], - [17, "周二十"], - [18, "吴二一"], - [19, "郑二二"], - ]; - state.basicData.users = fakeUsers; - return Promise.resolve(fakeUsers); + const userList = await getUserList(); + console.log("userList", userList); + + // 将后端返回的用户数据转换为兼容格式 + const realUsers = userList.data.map(item => ({ + jwcode: item.jwcode, + username: item.username, + company: state.config.COMPANY || '前端假公司' + })); + + state.basicData.users = realUsers; + return Promise.resolve(userList); } function determineCurrentPrize() { @@ -213,6 +125,35 @@ export function useDataManager() { } function updateCurrentPrize() { determineCurrentPrize(); } + // 新增:计算当前奖品的总轮次 + function getTotalRounds(prizeIndex) { + const prize = state.basicData.prizes[prizeIndex]; + const eachCount = state.config.EACH_COUNT[prizeIndex]; + if (!prize || !eachCount) return 0; + return Math.ceil(prize.count / eachCount); + } + + // 新增:计算当前轮次 + function getCurrentRound(prizeIndex) { + const luckyUsers = state.basicData.luckyUsers[prizeIndex] || []; + const eachCount = state.config.EACH_COUNT[prizeIndex]; + if (!eachCount) return 1; + return Math.floor(luckyUsers.length / eachCount) + 1; + } + + // 新增:计算剩余数量 + function getLeftCount(prizeIndex) { + const prize = state.basicData.prizes[prizeIndex]; + const luckyUsers = state.basicData.luckyUsers[prizeIndex] || []; + if (!prize) return 0; + return prize.count - luckyUsers.length; + } + + // 新增:更新当前轮次 + function updateCurrentRound() { + state.currentRound = getCurrentRound(state.currentPrizeIndex); + } + return { state, getBasicData, @@ -224,6 +165,10 @@ export function useDataManager() { getTotalCards, setLotteryStatus, resetAllData, - updateCurrentPrize + updateCurrentPrize, + getTotalRounds, + getCurrentRound, + getLeftCount, + updateCurrentRound }; } \ No newline at end of file diff --git a/src/views/choujiang/lottery/lotteryEngine.js b/src/views/choujiang/lottery/lotteryEngine.js index 1b07618..9adf8db 100644 --- a/src/views/choujiang/lottery/lotteryEngine.js +++ b/src/views/choujiang/lottery/lotteryEngine.js @@ -1,5 +1,6 @@ import { ref } from 'vue'; import { useLotteryStore } from '../../../store/lottery' // 路径根据实际情况调整 +import { drawLottery } from '../../../api/API'; // 导入新的抽奖接口 function getRandomInt(max) { return Math.floor(Math.random() * max); @@ -17,35 +18,113 @@ export function useLotteryEngine(dataManager, renderer3D) { changePrize(); // 重置卡片动画 await renderer3D.resetCard([]); - // 生成中奖卡片索引和中奖用户 - const perCount = dataManager.state.config.EACH_COUNT[dataManager.state.currentPrizeIndex] || 1; - const totalCards = renderer3D.getTotalCards ? renderer3D.getTotalCards() : 50; - const leftUsers = dataManager.state.basicData.leftUsers; - let selectedCardIndex = []; - let currentLuckys = []; - let leftCount = leftUsers.length; - console.log('executeLottery - perCount:', perCount, 'leftCount:', leftCount, 'totalCards:', totalCards); + // 计算本次应该抽奖的人数 + const currentPrizeIndex = dataManager.state.currentPrizeIndex; + const prize = dataManager.state.basicData.prizes[currentPrizeIndex]; + const luckyUsers = dataManager.state.basicData.luckyUsers[currentPrizeIndex] || []; + const remainingPrizeCount = prize.count - luckyUsers.length; // 奖品剩余数量 + const basePerCount = dataManager.state.config.EACH_COUNT[currentPrizeIndex] || 1; + const actualPerCount = Math.min(basePerCount, remainingPrizeCount); // 取最小值 - // 随机抽取中奖用户和卡片索引 - for (let i = 0; i < perCount && leftCount > 0; i++) { - const luckyId = getRandomInt(leftCount); - currentLuckys.push(leftUsers.splice(luckyId, 1)[0]); - leftCount--; - let cardIndex = getRandomInt(totalCards); - while (selectedCardIndex.includes(cardIndex)) { - cardIndex = getRandomInt(totalCards); + console.log('executeLottery - currentPrizeIndex:', currentPrizeIndex, 'prize:', prize, 'basePerCount:', basePerCount, 'remainingPrizeCount:', remainingPrizeCount, 'actualPerCount:', actualPerCount); + + // 请求后端进行抽奖 + try { + const lotteryData = { + gradeName: prize.title, + prizeName: prize.text, + perWin: basePerCount, + round: dataManager.state.currentRound + }; + + console.log('请求后端抽奖,参数:', lotteryData); + const response = await drawLottery(lotteryData); + console.log('后端抽奖返回结果:', response); + + if (response && response.data && Array.isArray(response.data)) { + // 后端返回中奖用户数据 + const currentLuckys = response.data.map(item => ({ + jwcode: item.jwcode, + username: item.username + })); + + console.log('后端返回的中奖用户:', currentLuckys); + + // 生成随机卡片索引用于显示 + const totalCards = dataManager.getTotalCards(); + let selectedCardIndex = []; + for (let i = 0; i < currentLuckys.length; i++) { + let cardIndex = getRandomInt(totalCards); + while (selectedCardIndex.includes(cardIndex)) { + cardIndex = getRandomInt(totalCards); + } + selectedCardIndex.push(cardIndex); + } + + console.log('executeLottery - selectedCardIndex:', selectedCardIndex, 'currentLuckys:', currentLuckys); + + dataManager.state.currentLuckys = currentLuckys; + // 保存中奖用户到对应奖品 + if (!dataManager.state.basicData.luckyUsers[currentPrizeIndex]) { + dataManager.state.basicData.luckyUsers[currentPrizeIndex] = []; + } + dataManager.state.basicData.luckyUsers[currentPrizeIndex].push(...currentLuckys); + // 更新轮次信息 + dataManager.updateCurrentRound(); + // 展示中奖动画 + console.log('executeLottery - calling selectCard'); + await renderer3D.selectCard?.(selectedCardIndex, currentLuckys); + console.log('executeLottery - selectCard completed'); + } else { + console.error('后端抽奖返回数据格式错误:', response); + throw new Error('抽奖失败:后端返回数据格式错误'); + } + } catch (error) { + console.error('抽奖请求失败:', error); + // 如果后端请求失败,可以回退到前端随机抽奖逻辑 + console.log('回退到前端随机抽奖逻辑'); + + const totalCards = dataManager.getTotalCards(); + const leftUsers = dataManager.state.basicData.leftUsers; + let selectedCardIndex = []; + let currentLuckys = []; + let leftCount = leftUsers.length; + + // 随机抽取中奖用户和卡片索引 + for (let i = 0; i < actualPerCount && leftCount > 0; i++) { + const luckyId = getRandomInt(leftCount); + const selectedUser = leftUsers.splice(luckyId, 1)[0]; + // 确保数据格式一致 + currentLuckys.push({ + jwcode: selectedUser.jwcode || selectedUser[0] || "", + username: selectedUser.username || selectedUser[1] || "", + company: selectedUser.company || selectedUser[2] || "PSST" + }); + leftCount--; + let cardIndex = getRandomInt(totalCards); + while (selectedCardIndex.includes(cardIndex)) { + cardIndex = getRandomInt(totalCards); + } + selectedCardIndex.push(cardIndex); + } + + console.log('executeLottery - selectedCardIndex:', selectedCardIndex, 'currentLuckys:', currentLuckys); + + dataManager.state.currentLuckys = currentLuckys; + // 保存中奖用户到对应奖品 + if (!dataManager.state.basicData.luckyUsers[currentPrizeIndex]) { + dataManager.state.basicData.luckyUsers[currentPrizeIndex] = []; } - selectedCardIndex.push(cardIndex); + dataManager.state.basicData.luckyUsers[currentPrizeIndex].push(...currentLuckys); + // 更新轮次信息 + dataManager.updateCurrentRound(); + // 展示中奖动画 + console.log('executeLottery - calling selectCard'); + await renderer3D.selectCard?.(selectedCardIndex, currentLuckys); + console.log('executeLottery - selectCard completed'); } - console.log('executeLottery - selectedCardIndex:', selectedCardIndex, 'currentLuckys:', currentLuckys); - - dataManager.state.currentLuckys = currentLuckys; - // 展示中奖动画 - console.log('executeLottery - calling selectCard'); - await renderer3D.selectCard?.(selectedCardIndex, currentLuckys); - console.log('executeLottery - selectCard completed'); dataManager.setLotteryStatus(false); isLotting.value = false; } @@ -66,6 +145,8 @@ export function useLotteryEngine(dataManager, renderer3D) { lotteryStore.setLotteryState('idle'); // 直接用 await renderer3D.resetCard([]); await dataManager.resetData(); + // 重置轮次 + dataManager.state.currentRound = 1; renderer3D.switchScreen && renderer3D.switchScreen('enter'); }