兼容新版的对对碰,调整了更多的排序方式等内容

This commit is contained in:
tsui110 2025-12-30 15:28:04 +08:00
parent 952a2a2fe7
commit a4dbfd14b7
4 changed files with 214 additions and 19 deletions

View File

@ -9,7 +9,9 @@
<view v-if="grouped && rewardGroups.length > 0">
<view class="prize-level-row" v-for="group in rewardGroups" :key="group.level">
<view class="level-header-row">
<view class="level-badge" :class="{ 'badge-boss': group.level === 'BOSS' }">{{ group.level }}</view>
<view class="level-badge" :class="{ 'badge-boss': group.level === 'BOSS' }">
{{ isMatchingGroup(group.level) ? group.level : `${group.level}` }}
</view>
<text class="level-prob">总概率 {{ group.totalPercent }}%</text>
</view>
<scroll-view class="preview-scroll" scroll-x>
@ -58,6 +60,10 @@ const props = defineProps({
type: Boolean,
default: false
},
playType: {
type: String,
default: 'normal'
},
emptyText: {
type: String,
default: '暂无奖品配置'
@ -66,9 +72,14 @@ const props = defineProps({
defineEmits(['view-all'])
// ""
const isMatchingGroup = (level) => {
return String(level || '').includes('对子')
}
const rewardGroups = computed(() => {
if (!props.grouped) return []
return groupRewardsByLevel(props.rewards)
return groupRewardsByLevel(props.rewards, props.playType)
})
</script>

View File

@ -46,7 +46,8 @@
<RewardsPreview
v-if="tabActive === 'pool'"
:rewards="previewRewards"
:grouped="detail?.play_type !== 'match'"
:grouped="!['match', 'matching'].includes(detail?.play_type)"
:play-type="detail?.play_type || 'normal'"
@view-all="openRewardsPopup"
/>
@ -317,11 +318,18 @@ const currentIssueRewards = computed(() => {
// rewards
const previewRewards = computed(() => {
const isMatchType = detail.value?.play_type === 'match'
const isMatchType = ['match', 'matching'].includes(detail.value?.play_type)
if (isMatchType) {
// min_score
return [...currentIssueRewards.value].sort((a, b) => (a.min_score - b.min_score))
const sorted = [...currentIssueRewards.value].sort((a, b) => (a.min_score - b.min_score))
console.log('[对对碰] previewRewards 排序后:', sorted.map(r => ({
name: r.title,
min_score: r.min_score,
weight: r.weight,
percent: r.percent
})))
return sorted
} else {
//
return currentIssueRewards.value
@ -329,7 +337,7 @@ const previewRewards = computed(() => {
})
const rewardGroups = computed(() => {
const isMatchType = detail.value?.play_type === 'match'
const isMatchType = ['match', 'matching'].includes(detail.value?.play_type)
// min_score
if (isMatchType) {
@ -337,11 +345,20 @@ const rewardGroups = computed(() => {
const sortedRewards = [...currentIssueRewards.value].sort((a, b) => (a.min_score - b.min_score))
//
return sortedRewards.map(item => ({
const groups = sortedRewards.map(item => ({
level: `${item.min_score}对子`,
rewards: [item],
totalPercent: item.percent.toFixed(1)
}))
console.log('[对对碰] rewardGroups 分组后:', groups.map(g => ({
level: g.level,
count: g.rewards.length,
totalPercent: g.totalPercent,
firstItem: g.rewards[0]?.title
})))
return groups
}
//
@ -568,7 +585,7 @@ function normalizeRewards(list, playType = 'normal') {
}))
// play_type
if (playType === 'match') {
if (['match', 'matching'].includes(playType)) {
// min_score min_score=0
enriched.sort((a, b) => (a.min_score - b.min_score))
} else {

View File

@ -66,7 +66,15 @@
<!-- 占位 -->
<view class="header-placeholder"></view>
<view v-if="loading && !items.length" class="loading-wrap"><view class="spinner"></view></view>
<view v-if="loading && !items.length" class="loading-container">
<view class="loading-animation">
<view class="circle circle-1"></view>
<view class="circle circle-2"></view>
<view class="circle circle-3"></view>
<view class="circle circle-4"></view>
</view>
<text class="loading-text">{{ loadingText }}</text>
</view>
<view class="content-container" v-else>
<!-- 商品视图 (网格) -->
@ -138,7 +146,7 @@
<!-- 加载更多 -->
<view v-if="loading && items.length > 0" class="loading-more">
<view class="spinner"></view>
<text>加载更多...</text>
<text>{{ loadingText }}</text>
</view>
<view v-else-if="!hasMore && items.length > 0" class="no-more">- 到底啦 -</view>
</view>
@ -147,7 +155,7 @@
<script setup>
import { onShow, onReachBottom } from '@dcloudio/uni-app'
import { ref, watch } from 'vue'
import { ref, watch, onUnmounted } from 'vue'
import { getStoreItems, redeemProductByPoints, redeemCouponByPoints, redeemItemCardByPoints } from '../../api/appUser'
const loading = ref(false)
@ -159,6 +167,50 @@ const page = ref(1)
const pageSize = 20
const hasMore = ref(true)
//
const loadingTexts = [
'请稍等,正在努力加载中。。。',
'精彩马上就来,请稍候片刻~',
'正在搜寻更多好物,别急哦~',
'加载中,好东西值得等待~',
'正在为您准备惊喜,马上就好~',
'小憩一下,精彩内容即将呈现~',
'努力加载中,比心❤️~',
'正在赶来,马上就到~',
'稍安勿躁,美好值得等待~',
'加载进度99%... 开个玩笑😄'
]
const loadingText = ref(loadingTexts[0])
let loadingTextInterval = null
//
function startLoadingTextRotation() {
if (loadingTextInterval) return
let index = 0
loadingText.value = loadingTexts[index]
loadingTextInterval = setInterval(() => {
index = (index + 1) % loadingTexts.length
loadingText.value = loadingTexts[index]
}, 2000) // 2
}
//
function stopLoadingTextRotation() {
if (loadingTextInterval) {
clearInterval(loadingTextInterval)
loadingTextInterval = null
}
}
// loading
watch(loading, (newVal) => {
if (newVal) {
startLoadingTextRotation()
} else {
stopLoadingTextRotation()
}
})
//
const priceMin = ref('')
const priceMax = ref('')
@ -174,8 +226,8 @@ const activePriceRange = ref('all')
const tabs = [
{ id: 'product', name: '商品' },
{ id: 'coupon', name: '优惠券' },
{ id: 'item_card', name: '道具卡' }
{ id: 'coupon', name: '优惠券' }
// { id: 'item_card', name: '' } //
]
function cleanUrl(u) {
@ -379,6 +431,11 @@ onReachBottom(() => {
watch(keyword, () => applyFilters())
//
onUnmounted(() => {
stopLoadingTextRotation()
})
</script>
<style lang="scss" scoped>
@ -630,6 +687,96 @@ watch(keyword, () => applyFilters())
.empty-img { width: 240rpx; opacity: 0.6; }
.empty-text { color: $text-tertiary; font-size: 26rpx; margin-top: 20rpx; }
/* 酷炫加载动画 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 150rpx;
}
.loading-animation {
position: relative;
width: 160rpx;
height: 160rpx;
margin-bottom: 40rpx;
}
.circle {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
border: 4rpx solid transparent;
}
.circle-1 {
border-top-color: #FF6B6B;
border-right-color: #FF6B6B;
animation: rotate 1.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
}
.circle-2 {
width: 80%;
height: 80%;
top: 10%;
left: 10%;
border-top-color: #4ECDC4;
border-left-color: #4ECDC4;
animation: rotate 2s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite reverse;
}
.circle-3 {
width: 60%;
height: 60%;
top: 20%;
left: 20%;
border-bottom-color: #FFE66D;
border-left-color: #FFE66D;
animation: rotate 2.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite;
}
.circle-4 {
width: 40%;
height: 40%;
top: 30%;
left: 30%;
border-top-color: #95E1D3;
border-bottom-color: #95E1D3;
animation: rotate 3s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite reverse;
}
@keyframes rotate {
0% {
transform: rotate(0deg) scale(1);
opacity: 1;
}
50% {
transform: rotate(180deg) scale(1.1);
opacity: 0.8;
}
100% {
transform: rotate(360deg) scale(1);
opacity: 1;
}
}
.loading-text {
font-size: 28rpx;
color: $text-secondary;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% {
opacity: 0.6;
}
50% {
opacity: 1;
}
}
.loading-wrap { padding: 100rpx 0; display: flex; justify-content: center; }
.spinner {
width: 48rpx; height: 48rpx; border: 4rpx solid #eee; border-top-color: $brand-primary;

View File

@ -147,9 +147,12 @@ export function pickLatestIssueId(list) {
/**
* 按等级分组奖励
* @param {Array} rewards - 奖励列表
* @param {string} playType - 活动类型 ('match', 'matching' 对对碰模式其他为普通模式)
* @returns {Array} 分组后的奖励
*/
export function groupRewardsByLevel(rewards) {
export function groupRewardsByLevel(rewards, playType = 'normal') {
const isMatchType = ['match', 'matching'].includes(playType)
const groups = {}
; (rewards || []).forEach(item => {
let level = item.level || '赏'
@ -160,17 +163,34 @@ export function groupRewardsByLevel(rewards) {
if (!groups[level]) groups[level] = []
groups[level].push(item)
})
return Object.keys(groups).sort((a, b) => {
if (a === 'Last' || a === 'BOSS') return -1
if (b === 'Last' || b === 'BOSS') return 1
// 分组之间按该组最小 weight 排序(升序)
// Last 和 BOSS 优先(仅限普通模式)
if (!isMatchType) {
if (a === 'Last' || a === 'BOSS') return -1
if (b === 'Last' || b === 'BOSS') return 1
}
// 对对碰模式:按 min_score 升序排序
if (isMatchType) {
const extractScore = (key) => {
const match = key.match(/(\d+)对子/)
return match ? parseInt(match[1], 10) : 0
}
return extractScore(a) - extractScore(b)
}
// 普通模式:分组之间按该组最小 weight 排序(升序)
const minWeightA = Math.min(...groups[a].map(item => item.weight || 0))
const minWeightB = Math.min(...groups[b].map(item => item.weight || 0))
return minWeightA - minWeightB
}).map(key => {
const levelRewards = groups[key]
// 确保分组内的奖品按 weight 升序排列(从小到大)
levelRewards.sort((a, b) => (a.weight - b.weight))
// 对对碰模式:保持 min_score 升序(已在 previewRewards 排序)
// 普通模式:确保分组内的奖品按 weight 升序排列(从小到大)
if (!isMatchType) {
levelRewards.sort((a, b) => (a.weight - b.weight))
}
const total = levelRewards.reduce((sum, item) => sum + (Number(item.percent) || 0), 0)
return {
level: key,