feat(活动页): 对接接口数据,完善点击功能

This commit is contained in:
hzj 2025-09-12 19:51:21 +08:00
parent 92855483ad
commit 1bc454319a
4 changed files with 523 additions and 284 deletions

51
src/api/topList.js Normal file
View File

@ -0,0 +1,51 @@
import { get, post } from '../utils/http.js'
// 获取国王/女王榜单
export const getWeekTopList = async (data) => {
try {
const response = await get(
`/activity/king-queen/ranking?type=${data.type}&kingQueenType=${data.kingQueenType}&current=${data.current}&size=${data.size}`
)
return response
} catch (error) {
console.error('Failed to get week top list:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 获取我本周贡献
export const getWeekMyContribution = async () => {
try {
const response = await get(`/activity/king-queen/user-contribute`)
return response
} catch (error) {
console.error('Failed to get week my contribution:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 获取本周奖励和礼物
export const getThisWeekRewardsAndGifts = async () => {
try {
const response = await get(`/activity/king-queen/effective`)
return response
} catch (error) {
console.error('Failed to get this week rewards and gifts:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}
// 获取历史榜首
export const getHistoryTopOne = async () => {
try {
const response = await get(`/activity/king-queen/history`)
return response
} catch (error) {
console.error('Failed to get history top one:', error)
console.error('error:' + error.response.errorMsg)
throw error
}
}

View File

@ -28,4 +28,8 @@ const props = defineProps({
})
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
* {
color: black;
}
</style>

View File

@ -23,7 +23,7 @@
<div
style="
color: #fff;
font-size: 20px;
font-weight: 860;
font-family: 'SF Pro';
margin-bottom: 1%;
@ -61,4 +61,26 @@ const props = defineProps({
})
</script>
<style lang="scss" scoped></style>
<style lang="scss" scoped>
* {
color: black;
}
@media screen and (min-width: 375px) {
* {
font-size: 20px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 30px;
}
}
@media screen and (min-width: 1024px) {
* {
font-size: 40px;
}
}
</style>

View File

@ -20,12 +20,13 @@
@click="historyShow = true"
/>
<!-- 每周榜首 -->
<div style="display: flex; flex-direction: column; align-items: center">
<!-- 主标题 -->
<img src="/src/assets/images/TopList/listTitle.png" alt="" style="width: 90%" />
<!-- 榜首 -->
<div style="width: 100%; display: flex; justify-content: space-around; margin-top: 16px">
<div style="width: 40%">
<div style="width: 40%" v-for="(topUser, index) in listTop" :key="index">
<div
style="
position: relative;
@ -37,11 +38,7 @@
"
>
<!-- 头像框 -->
<img
src="/src/assets/images/TopList/kingFrame.png"
alt=""
style="width: 100%; z-index: 1"
/>
<img :src="topUser.Frame" alt="" style="width: 100%; z-index: 1" />
<!-- 头像 -->
<div
style="
@ -56,67 +53,37 @@
z-index: 0;
"
>
<img src="/src/assets/icon/coin.png" alt="" style="width: 90%" />
<img
:src="topUser.userInfo.userAvatar"
alt=""
width="70%"
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
/>
</div>
<div
style="
color: #fff;
font-weight: 860;
font-size: 13px;
height: 10%;
width: 50%;
position: absolute;
bottom: 8%;
z-index: 2;
"
>
Sukabuliete
</div>
</div>
<div style="color: #fff; font-weight: 590; text-align: center">ID:123456</div>
</div>
<div style="width: 40%">
<div
style="
position: relative;
width: 100%;
min-height: max-content;
display: flex;
justify-content: center;
align-items: center;
"
>
<!-- 头像框 -->
<img
src="/src/assets/images/TopList/queenFrame.png"
alt=""
style="width: 100%; z-index: 1"
/>
<!-- 头像 -->
<div
style="
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 0;
"
:style="{ bottom: topUser.type == 'topKing' ? '9.3%' : '7%' }"
>
<img src="/src/assets/icon/coin.png" alt="" style="width: 90%" />
</div>
<div
style="
color: #fff;
font-weight: 860;
font-size: 13px;
position: absolute;
bottom: 5%;
z-index: 2;
"
>
Sukabuliete
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
class="topName"
>
{{ topUser.userInfo.userNickname }}
</div>
</div>
</div>
<div style="color: #fff; font-weight: 590; text-align: center">ID:123456</div>
@ -152,13 +119,29 @@
>
<div style="width: 80%; display: flex; justify-content: space-around; margin-top: 10%">
<div
v-for="(item, index) in 3"
v-for="(gift, index) in gifts"
:key="index"
style="width: 30%; display: flex; flex-direction: column"
>
<img style="" src="/src/assets/images/TopList/gift.png" alt="" />
<div style="position: relative">
<img style="" src="/src/assets/images/TopList/gift.png" alt="" width="100%" />
<div
style="
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
"
>
<img :src="gift.giftPhoto" alt="" width="50%" />
</div>
</div>
<div style="color: rgba(255, 255, 255, 1); font-weight: 590; text-align: center">
ddd
{{ gift.giftCandy }}
</div>
</div>
</div>
@ -166,7 +149,7 @@
</div>
</div>
<!-- 排行榜 -->
<!-- 排行榜模块 -->
<div style="width: 100vw">
<!-- 排行榜切换按钮 -->
<div style="width: 100%">
@ -222,13 +205,13 @@
padding: 0 15%;
"
>
<div style="flex: 1; display: flex; align-items: center">
<div style="width: 70%; display: flex; align-items: center">
<div style="color: #edb247; font-weight: 700; width: 28px">
{{ index + 100 }}
{{ listItem.rank }}
</div>
<div
style="
width: 30%;
width: 28%;
aspect-ratio: 1/1;
border-radius: 50%;
margin: 0 8px;
@ -244,106 +227,46 @@
"
>
<img
src="/src/assets/images/avatarTest.png"
:src="listItem.userAvatar"
alt=""
style="width: 90%; aspect-ratio: 1/1; border-radius: 50%; object-fit: cover"
/>
</div>
<div style="display: flex; flex-direction: column">
<div style="color: #fff; font-weight: 860">
{{ listItem.name }}
<div
style="width: calc(72% - 28px - 26px); display: flex; flex-direction: column"
>
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 100%;
"
class="topUserNickname"
>
{{ listItem.userNickname }}
</div>
<div style="color: #fff; font-weight: 590">ID:{{ listItem.id }}</div>
<div style="color: #fff; font-weight: 590">ID:{{ listItem.account }}</div>
</div>
</div>
<div style="display: flex; width: 30%; display: flex; align-items: center">
<img src="/src/assets/icon/coin.png" alt="" style="width: 20%; height: 20%" />
<div style="color: #edb247; font-weight: 700">
{{ listItem.recharge }}
{{ listItem.quantity }}
</div>
</div>
</div>
</div>
<!-- 触发加载功能 -->
<div ref="kingListLoadmore" v-show="showKingLoading && visibleKingList"></div>
<!-- 触发加载功能 -->
<div ref="queenListloadmore" v-show="showQueenLoading && !visibleKingList"></div>
</borderImg>
</div>
<!-- 我的排名 -->
<div
style="
position: sticky;
bottom: 0;
left: 0;
widows: 100vw;
background-color: rgba(77, 30, 22, 1);
display: flex;
justify-content: center;
"
>
<img
src="/src/assets/images/TopList/myRankingBg.png"
alt=""
style="width: calc(100% - 1px); display: block"
/>
<div
style="
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0 8%;
"
>
<div style="flex: 1; display: flex; align-items: center">
<div style="color: #edb247; font-weight: 700">
{{ myRanking.ranking }}
</div>
<div
style="
width: 30%;
aspect-ratio: 1/1;
border-radius: 50%;
margin: 0 12px;
background: linear-gradient(
to bottom,
rgba(255, 224, 60, 1),
rgba(255, 189, 19, 1)
);
display: flex;
justify-content: center;
align-items: center;
"
>
<img
src="/src/assets/images/avatarTest.png"
alt=""
style="width: 90%; aspect-ratio: 1/1; border-radius: 50%; object-fit: cover"
/>
</div>
<div style="display: flex; flex-direction: column">
<div style="color: #fff; font-weight: 860">
{{ myRanking.name }}
</div>
<div style="color: #fff; font-weight: 590">ID:{{ myRanking.id }}</div>
</div>
</div>
<div style="display: flex; width: 30%; display: flex; align-items: center">
<img src="/src/assets/icon/coin.png" alt="" style="width: 20%; height: 20%" />
<div style="color: #edb247; font-weight: 700">
{{ myRanking.recharge }}
</div>
</div>
</div>
</div>
</div>
</div>
@ -371,7 +294,11 @@
<div
style="width: 100%; display: flex; justify-content: space-around; margin-top: 16px"
>
<div style="width: 40%">
<div
style="width: 40%"
v-for="(topOne, topIndex) in showTopOne.top"
:key="topIndex"
>
<div
style="
position: relative;
@ -383,11 +310,7 @@
"
>
<!-- 头像框 -->
<img
src="/src/assets/images/TopList/kingFrame.png"
alt=""
style="width: 100%; z-index: 1"
/>
<img :src="topOne.Frame" alt="" style="width: 100%; z-index: 1" />
<!-- 头像 -->
<div
style="
@ -402,70 +325,47 @@
z-index: 0;
"
>
<img src="/src/assets/icon/coin.png" alt="" style="width: 90%" />
<img
:src="topOne.userInfo.userAvatar"
alt=""
width="70%"
style="border-radius: 50%; aspect-ratio: 1/1; object-fit: cover"
/>
</div>
<div
style="
height: 10%;
width: 50%;
color: #fff;
font-weight: 860;
font-size: 13px;
position: absolute;
bottom: 8%;
z-index: 2;
"
>
Sukabuliete
</div>
</div>
<div style="color: #fff; font-weight: 590; text-align: center">ID:123456</div>
</div>
<div style="width: 40%">
<div
style="
position: relative;
width: 100%;
min-height: max-content;
display: flex;
justify-content: center;
align-items: center;
"
>
<!-- 头像框 -->
<img
src="/src/assets/images/TopList/queenFrame.png"
alt=""
style="width: 100%; z-index: 1"
/>
<!-- 头像 -->
<div
style="
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
font-weight: 860;
font-size: 12px;
display: flex;
justify-content: center;
align-items: center;
z-index: 0;
"
:style="{ bottom: topOne.type == 'topKing' ? '9.3%' : '7%' }"
>
<img src="/src/assets/icon/coin.png" alt="" style="width: 90%" />
</div>
<div
style="
color: #fff;
font-weight: 860;
font-size: 13px;
position: absolute;
bottom: 5%;
z-index: 2;
"
>
Sukabuliete
<div
style="
color: #fff;
font-weight: 860;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
class="topName"
>
{{ topOne.userInfo.userNickname }}
</div>
</div>
</div>
<div style="color: #fff; font-weight: 590; text-align: center">ID:123456</div>
<div style="color: #fff; font-weight: 590; text-align: center">
ID:{{ topOne.userInfo.account }}
</div>
</div>
</div>
<div
@ -481,6 +381,7 @@
alt=""
width="18px"
height="18px"
@click="changeHistoryIndex(1)"
/>
<div
style="
@ -494,17 +395,17 @@
rgba(255, 238, 198, 1)
);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
"
>
2025-09-05
{{ showTopOne.group }}
</div>
<img
src="/src/assets/images/TopList/timeNext.png"
alt=""
width="18px"
height="18px"
@click="changeHistoryIndex(-1)"
/>
</div>
</div>
@ -570,30 +471,61 @@
</div>
<!-- 奖励榜 -->
<div
v-for="(rewardsTop, top) in rewardsList"
:key="top"
style="display: flex; flex-direction: column; align-items: center"
>
<img :src="topImg[top]" alt="" style="width: 40%; margin: 24px 0" />
<div v-for="(rewardsTop, top) in rewardsList" :key="top">
<div
style="
width: 100%;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 3%;
"
style="display: flex; flex-direction: column; align-items: center"
v-if="rewardsTop.rewards.length > 0"
>
<img
:src="topImg[Number(rewardsTop.rankRange) - 1]"
alt=""
style="width: 40%; margin: 24px 0"
/>
<div
v-for="(reward, rewardIndex) in rewardsTop"
:key="rewardIndex"
style="width: 100%"
style="
width: 100%;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 3%;
"
>
<img style="" src="/src/assets/images/TopList/gift.png" alt="" width="100%" />
<div
style="color: rgba(255, 255, 255, 1); font-weight: 590; text-align: center"
v-for="(reward, rewardIndex) in rewardsTop.rewards"
:key="rewardIndex"
style="width: 100%"
>
{{ reward.goodsId }}
<div style="position: relative">
<img
style=""
src="/src/assets/images/TopList/gift.png"
alt=""
width="100%"
/>
<div
style="
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
"
>
<img :src="reward.cover" alt="" width="50%" style="aspect-ratio: 1/1" />
</div>
</div>
<div
style="
color: rgba(255, 255, 255, 1);
font-weight: 590;
text-align: center;
"
>
{{ reward.name }}
</div>
</div>
</div>
</div>
@ -604,6 +536,86 @@
</div>
</div>
</maskLayer>
<!-- 我的排名 -->
<div
style="
position: sticky;
bottom: 0;
left: 0;
widows: 100vw;
background-color: rgba(77, 30, 22, 1);
display: flex;
justify-content: center;
margin-top: 10px;
"
>
<img
src="/src/assets/images/TopList/myRankingBg.png"
alt=""
style="width: calc(100% - 1px); display: block"
/>
<div
style="
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 0 8%;
"
>
<div style="flex: 1; display: flex; align-items: center">
<div style="color: #edb247; font-weight: 700">
<!-- {{ myRanking.ranking }} -->
100
</div>
<div
style="
width: 30%;
aspect-ratio: 1/1;
border-radius: 50%;
margin: 0 12px;
background: linear-gradient(to bottom, rgba(255, 224, 60, 1), rgba(255, 189, 19, 1));
display: flex;
justify-content: center;
align-items: center;
"
>
<img
:src="myRanking.userAvatar"
alt=""
style="width: 90%; aspect-ratio: 1/1; border-radius: 50%; object-fit: cover"
/>
</div>
<div style="display: flex; flex-direction: column">
<div style="color: #fff; font-weight: 860">
{{ myRanking.userNickname }}
</div>
</div>
</div>
<div style="display: flex; width: 30%; display: flex; align-items: center">
<img src="/src/assets/icon/coin.png" alt="" style="width: 20%; height: 20%" />
<!-- 1:,0: -->
<div
v-if="myRanking.userSex == 1"
style="color: #edb247; font-weight: 700; margin-left: 8px"
>
{{ myRanking.wealthQuantity }}
</div>
<div v-else style="color: #edb247; font-weight: 700; margin-left: 8px">
{{ myRanking.charmQuantity }}
</div>
</div>
</div>
</div>
</div>
</template>
@ -612,84 +624,96 @@ import { isInApp } from '../../utils/appBridge.js'
import { computed, onMounted, ref } from 'vue'
import borderImg from '../../components/TopList/borderImg.vue'
import maskLayer from '../../components/MaskLayer.vue'
import {
getWeekTopList,
getWeekMyContribution,
getThisWeekRewardsAndGifts,
getHistoryTopOne,
} from '@/api/topList.js'
import { useDebounce, useThrottle } from '@/utils/useDebounce'
const visibleKingList = ref(true)
// APP
const isInAppEnvironment = ref(false)
const isInAppEnvironment = ref(false) // APP
//
const historyList = ref([
{
time: '2025-9-5',
topUser: [{}],
},
])
//
const myRanking = ref({
id: '666',
name: 'aaa',
recharge: '12345',
ranking: '999',
const historyList = ref([]) //
const showTopOne = computed(() => {
return {
group: historyList.value[historyIndex.value].group,
top: [
{
type: 'topKing',
Frame: '/src/assets/images/TopList/kingFrame.png',
userInfo: historyList.value[historyIndex.value].wealth,
},
{
type: 'topQueen',
Frame: '/src/assets/images/TopList/queenFrame.png',
userInfo: historyList.value[historyIndex.value].charm,
},
],
}
})
const historyIndex = ref(0)
//
const kingList = ref(
Array.from({ length: 12 }, () => {
return { id: '666', name: 'aaa', recharge: '12345' }
})
)
const changeHistoryIndex = (num) => {
let index = historyIndex.value + num
let length = historyList.value.length
if (index >= 0 && index < length) {
historyIndex.value = index
}
}
//
const queenList = ref(
Array.from({ length: 12 }, () => {
return { id: '888', name: 'bbb', recharge: '45678' }
})
)
const myRanking = ref({}) //
const kingListCurrent = ref(1) //
const kingListParams = computed(() => ({
type: 'THIS_WEEK',
kingQueenType: 'WEALTH',
current: kingListCurrent.value,
size: 10,
}))
const kingList = ref([]) //
const queenListCurrent = ref(1) //
const queenListParams = computed(() => ({
type: 'THIS_WEEK',
kingQueenType: 'CHARM',
current: queenListCurrent.value,
size: 10,
}))
const queenList = ref([]) //
const listTop = ref([
{
type: 'topKing',
Frame: '/src/assets/images/TopList/kingFrame.png',
userInfo: {},
},
{
type: 'topQueen',
Frame: '/src/assets/images/TopList/queenFrame.png',
userInfo: {},
},
]) //top1
//
const topList = computed(() => {
return visibleKingList.value ? kingList.value : queenList.value
})
//
const visibleKingRewards = ref(true)
const showKingLoading = ref(true) //
const showQueenLoading = ref(true) //
// top
const topImg = ref([
'/src/assets/images/TopList/top1.png',
'/src/assets/images/TopList/top2.png',
'/src/assets/images/TopList/top3.png',
])
const kingRewards = ref([
Array.from({ length: 6 }, () => {
return { goodsId: '111', name: 'aaa' }
}),
Array.from({ length: 6 }, () => {
return { goodsId: '222', name: 'aaa' }
}),
Array.from({ length: 3 }, () => {
return { goodsId: '333', name: 'aaa' }
}),
])
const queenRewards = ref([
Array.from({ length: 3 }, () => {
return { goodsId: '444', name: 'aaa' }
}),
Array.from({ length: 3 }, () => {
return { goodsId: '555', name: 'aaa' }
}),
Array.from({ length: 3 }, () => {
return { goodsId: '666', name: 'aaa' }
}),
])
]) // top
const visibleKingRewards = ref(true) //
const kingRewards = ref([]) //
const queenRewards = ref([]) //
const rewardsList = computed(() => {
return visibleKingRewards.value ? kingRewards.value : queenRewards.value
})
}) //
const maskLayerShow = computed(() => {
return helpInfoShow.value || historyShow.value || rewardsShow.value
@ -698,6 +722,65 @@ const helpInfoShow = ref(false)
const historyShow = ref(false)
const rewardsShow = ref(false)
// div
const kingListLoadmore = ref(null)
const queenListloadmore = ref(null)
const debouceGetKingList = useThrottle(() => {
getTopList(kingListParams.value)
}, 1000)
const debouceGetQueenList = useThrottle(() => {
getTopList(queenListParams.value)
}, 1000)
const gifts = ref([])
//
const getTopList = async (params) => {
const resWeekTopList = await getWeekTopList(params)
if (resWeekTopList.status && resWeekTopList.body) {
if (params.kingQueenType == 'WEALTH') {
if (kingList.value.length == 0) listTop.value[0].userInfo = resWeekTopList.body.records[0] //king
kingList.value.push(...resWeekTopList.body.records)
if (params.current * params.size >= resWeekTopList.body.total) showKingLoading.value = false
} else {
if (queenList.value.length == 0) listTop.value[1].userInfo = resWeekTopList.body.records[0] //king
queenList.value.push(...resWeekTopList.body.records)
if (params.current * params.size >= resWeekTopList.body.total) showQueenLoading.value = false
}
}
}
//
const getMyContribution = async () => {
const resWeekMyContribution = await getWeekMyContribution()
console.log('resWeekMyContribution:', resWeekMyContribution)
if (resWeekMyContribution.status && resWeekMyContribution.body) {
myRanking.value = resWeekMyContribution.body
}
}
//
const getRewardsAndGifts = async () => {
const resRewardsAndGifts = await getThisWeekRewardsAndGifts()
if (resRewardsAndGifts.status && resRewardsAndGifts.body) {
gifts.value = resRewardsAndGifts.body.gifts
kingRewards.value = resRewardsAndGifts.body.butOneRewards
queenRewards.value = resRewardsAndGifts.body.butTwoRewards
console.log('kingRewards:', kingRewards.value)
console.log('queenRewards:', queenRewards.value)
}
}
const getAllTopOne = async () => {
const resHistoryTopOne = await getHistoryTopOne()
if (resHistoryTopOne.status && resHistoryTopOne.body) {
historyList.value = resHistoryTopOne.body
}
}
//
const closedPopup = () => {
helpInfoShow.value = false
@ -705,15 +788,50 @@ const closedPopup = () => {
rewardsShow.value = false
}
// IntersectionObserver
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.intersectionRatio > 0) {
console.log('监控到底部')
if (entry.target == kingListLoadmore.value && kingList.value.length != 0) {
console.log('kingListLoadmore')
kingListCurrent.value++
debouceGetKingList()
}
if (entry.target == queenListloadmore.value && queenList.value.length != 0) {
console.log('queenListloadmore')
queenListCurrent.value++
debouceGetQueenList()
}
}
})
})
//
onMounted(() => {
isInAppEnvironment.value = isInApp()
getTopList(kingListParams.value) //
getTopList(queenListParams.value) //
getMyContribution() //
getRewardsAndGifts() //top
getAllTopOne() //
if (kingListLoadmore.value) {
observer.observe(kingListLoadmore.value)
} //
if (queenListloadmore.value) {
observer.observe(queenListloadmore.value)
} //
})
</script>
<style scoped>
* {
color: black;
font-family: 'SF Pro';
font-size: 16px;
}
.fullPage {
@ -729,4 +847,48 @@ onMounted(() => {
background-repeat: no-repeat;
position: relative;
}
.topUserNickname::-webkit-scrollbar {
display: none;
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
.topName {
font-size: 8px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 12px;
}
.topName {
font-size: 10px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
.topName {
font-size: 20px;
}
}
@media screen and (min-width: 1024px) {
* {
font-size: 32px;
}
.topName {
font-size: 30px;
}
}
</style>