Files
shoot-miniprograms/src/pages/ranking.vue

561 lines
14 KiB
Vue
Raw Normal View History

2025-05-01 16:36:24 +08:00
<script setup>
2025-06-26 23:41:23 +08:00
import { ref, onMounted } from "vue";
2025-07-13 13:28:21 +08:00
import { onHide } from "@dcloudio/uni-app";
2025-05-23 21:20:38 +08:00
import Container from "@/components/Container.vue";
2025-06-08 20:59:41 +08:00
import Avatar from "@/components/Avatar.vue";
2025-07-02 17:16:56 +08:00
import { getRankListAPI, isGamingAPI } from "@/apis";
2025-06-26 23:41:23 +08:00
import { topThreeColors } from "@/constants";
2025-07-01 17:30:46 +08:00
import { getHomeData } from "@/apis";
2025-06-08 20:59:41 +08:00
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
2025-07-13 13:28:21 +08:00
const { user, device } = storeToRefs(store);
2025-07-01 10:57:49 +08:00
const { getLvlName } = store;
2025-05-02 00:39:37 +08:00
2025-07-13 13:28:21 +08:00
const defaultSeasonData = {
"1v1": { totalGames: 0, winCount: 0, winRate: 0 },
"5m": { totalGames: 0, winCount: 0, winRate: 0 },
"10m": { totalGames: 0, winCount: 0, winRate: 0 },
};
2025-05-02 00:39:37 +08:00
const selectedIndex = ref(0);
2025-07-01 10:57:49 +08:00
const currentList = ref([]);
2025-07-01 17:30:46 +08:00
const seasonName = ref("");
const seasonData = ref([]);
2025-07-13 13:28:21 +08:00
const rankData = ref({ user: {} });
const showSeasonList = ref(false);
const currentSeasonData = ref(defaultSeasonData);
2025-05-02 00:39:37 +08:00
const handleSelect = (index) => {
selectedIndex.value = index;
2025-07-13 13:28:21 +08:00
if (index === 0 && rankData.value.rank) {
2025-07-01 10:57:49 +08:00
currentList.value = rankData.value.rank.slice(0, 10);
2025-07-13 13:28:21 +08:00
} else if (index === 2 && rankData.value.ringRank) {
2025-07-01 10:57:49 +08:00
currentList.value = rankData.value.ringRank.slice(0, 10);
} else {
currentList.value = [];
}
2025-05-02 00:39:37 +08:00
};
2025-05-16 15:56:54 +08:00
2025-06-26 23:41:23 +08:00
onMounted(async () => {
2025-07-13 13:28:21 +08:00
const result = await getHomeData();
currentList.value = result.rank;
rankData.value = result;
const { userGameStats, seasonList } = result;
2025-07-01 17:30:46 +08:00
seasonData.value = seasonList;
2025-07-13 13:28:21 +08:00
updateData();
2025-06-26 23:41:23 +08:00
});
2025-07-02 17:16:56 +08:00
const toTeamMatchPage = async (gameType, teamSize) => {
2025-06-15 22:38:28 +08:00
if (!device.value.deviceId) {
return uni.showToast({
title: "请先绑定设备",
icon: "none",
});
}
2025-07-02 17:16:56 +08:00
const isGaming = await isGamingAPI();
if (isGaming) {
2025-07-03 21:13:55 +08:00
uni.$showHint(1);
2025-07-02 17:16:56 +08:00
return;
}
2025-05-16 15:56:54 +08:00
uni.navigateTo({
2025-06-08 12:52:49 +08:00
url: `/pages/team-match?gameType=${gameType}&teamSize=${teamSize}`,
});
};
2025-07-02 17:16:56 +08:00
const toMeleeMatchPage = async (gameType, teamSize) => {
2025-06-15 22:38:28 +08:00
if (!device.value.deviceId) {
return uni.showToast({
title: "请先绑定设备",
icon: "none",
});
}
2025-07-10 15:34:00 +08:00
if (!user.value.trio) {
return uni.showToast({
title: "请先完成新手试炼",
icon: "none",
});
}
2025-07-02 17:16:56 +08:00
const isGaming = await isGamingAPI();
if (isGaming) {
2025-07-03 21:13:55 +08:00
uni.$showHint(1);
2025-07-02 17:16:56 +08:00
return;
}
2025-06-08 12:52:49 +08:00
uni.navigateTo({
2025-06-09 01:17:18 +08:00
url: `/pages/melee-match?gameType=${gameType}&teamSize=${teamSize}`,
2025-05-16 15:56:54 +08:00
});
};
2025-06-24 13:18:03 +08:00
const toMyGrowthPage = () => {
uni.navigateTo({
url: "/pages/my-growth",
});
};
const toRankListPage = () => {
uni.navigateTo({
url: "/pages/rank-list",
});
};
2025-07-13 13:28:21 +08:00
const onChangeSeason = async (seasonId, name) => {
if (name !== seasonName.value) {
const result = await getHomeData(seasonId);
rankData.value = result;
seasonName.value = name;
handleSelect(selectedIndex.value);
updateData();
}
showSeasonList.value = false;
};
const updateData = () => {
const { userGameStats, seasonList } = rankData.value;
currentSeasonData.value = { ...defaultSeasonData };
if (
userGameStats &&
userGameStats.stats_list &&
userGameStats.stats_list.length
) {
userGameStats.stats_list.forEach((item) => {
if (seasonList.length) {
seasonList.some((s) => {
if (s.seasonId === item.seasonId) {
seasonName.value = s.seasonName;
return true;
}
return false;
});
}
let keyName = "";
if (item.gameType === 1 && item.teamSize === 2) keyName = "1v1";
if (item.gameType === 2 && item.teamSize === 5) keyName = "5m";
if (item.gameType === 2 && item.teamSize === 10) keyName = "10m";
if (keyName) {
currentSeasonData.value[keyName] = {
totalGames: item.totalGames,
winCount: item.winCount,
winRate: Number(((item.winCount / item.totalGames) * 100).toFixed(2)),
};
}
});
}
};
onHide(() => {
showSeasonList.value = false;
});
2025-05-01 16:36:24 +08:00
</script>
<template>
2025-06-04 16:26:07 +08:00
<Container title="排行赛">
2025-07-13 13:28:21 +08:00
<view class="container" @click="() => (showSeasonList = false)">
2025-06-30 17:28:21 +08:00
<view class="ranking-my-data" v-if="user.id">
2025-06-04 16:26:07 +08:00
<view>
<view class="user-info">
2025-07-13 13:28:21 +08:00
<Avatar
:src="user.avatar"
2025-07-14 15:13:10 +08:00
:rankLvl="rankData.user.rankLvl"
2025-07-13 13:28:21 +08:00
:size="30"
/>
2025-06-08 20:59:41 +08:00
<text>{{ user.nickName }}</text>
2025-06-04 16:26:07 +08:00
</view>
2025-07-13 13:28:21 +08:00
<view
class="ranking-season"
v-if="seasonData.length"
@click.stop="() => (showSeasonList = true)"
>
2025-07-01 17:30:46 +08:00
<text>{{ seasonName }}</text>
<image
v-if="seasonData.length > 1"
src="../static/triangle.png"
mode="widthFix"
/>
2025-07-13 13:28:21 +08:00
<view class="season-list" v-if="showSeasonList">
<view
v-for="(item, index) in seasonData"
:key="index"
@click.stop="
() => onChangeSeason(item.seasonId, item.seasonName)
"
>
<text>{{ item.seasonName }}</text>
<image
v-if="item.seasonName === seasonName"
src="../static/triangle.png"
mode="widthFix"
/>
</view>
</view>
2025-05-02 00:39:37 +08:00
</view>
</view>
2025-06-04 16:26:07 +08:00
<view class="my-data">
<view>
<text>段位</text>
2025-07-13 13:28:21 +08:00
<text :style="{ color: '#83CDFF' }">{{
getLvlName(rankData.user.scores) || "-"
}}</text>
2025-06-04 16:26:07 +08:00
</view>
<view>
<text>赛季平均环数</text>
2025-07-03 21:12:59 +08:00
<text :style="{ color: '#FFD947' }">{{
2025-07-13 13:28:21 +08:00
rankData.user.avg_ring ? rankData.user.avg_ring + "环" : "-"
2025-07-03 21:12:59 +08:00
}}</text>
2025-06-04 16:26:07 +08:00
</view>
<view>
<text>赛季胜率</text>
2025-07-03 21:12:59 +08:00
<text :style="{ color: '#FF507E' }">{{
2025-07-13 13:28:21 +08:00
rankData.user.avg_win ? rankData.user.avg_win + "%" : "-"
2025-07-03 21:12:59 +08:00
}}</text>
2025-06-04 16:26:07 +08:00
</view>
2025-05-02 00:39:37 +08:00
</view>
2025-06-04 16:26:07 +08:00
<view class="rank-type">
<image
src="../static/battle1v1.png"
mode="widthFix"
2025-07-13 13:28:21 +08:00
@click.stop="() => toTeamMatchPage(1, 2)"
2025-06-04 16:26:07 +08:00
/>
<image
src="../static/battle5.png"
mode="widthFix"
2025-07-13 13:28:21 +08:00
@click.stop="() => toMeleeMatchPage(2, 5)"
2025-06-04 16:26:07 +08:00
/>
<image
src="../static/battle10.png"
mode="widthFix"
2025-07-13 13:28:21 +08:00
@click.stop="() => toMeleeMatchPage(2, 10)"
2025-06-04 16:26:07 +08:00
/>
2025-05-02 00:39:37 +08:00
</view>
2025-06-04 16:26:07 +08:00
<view class="data-progress">
2025-07-01 17:30:46 +08:00
<text>
{{
`【1 V 1】${currentSeasonData["1v1"].totalGames}场 胜率 ${currentSeasonData["1v1"].winRate}%`
}}
</text>
2025-06-04 16:26:07 +08:00
<view>
2025-07-01 17:30:46 +08:00
<view
:style="{
width: `${currentSeasonData['1v1'].winRate}%`,
backgroundColor: '#FF507E',
}"
/>
2025-06-04 16:26:07 +08:00
</view>
2025-05-02 00:39:37 +08:00
</view>
2025-06-04 16:26:07 +08:00
<view class="data-progress">
2025-07-01 17:30:46 +08:00
<text>
{{
`【5人大乱斗】${currentSeasonData["5m"].totalGames}场 胜率 ${currentSeasonData["5m"].winRate}%`
}}
</text>
2025-06-04 16:26:07 +08:00
<view>
2025-07-01 17:30:46 +08:00
<view
:style="{
width: `${currentSeasonData['5m'].winRate}%`,
backgroundColor: '#FFD947',
}"
/>
2025-06-04 16:26:07 +08:00
</view>
2025-05-02 00:39:37 +08:00
</view>
2025-06-04 16:26:07 +08:00
<view class="data-progress">
2025-07-01 17:30:46 +08:00
<text>
{{
`【10人大乱斗】${currentSeasonData["5m"].totalGames}场 胜率 ${currentSeasonData["10m"].winRate}%`
}}
</text>
2025-06-04 16:26:07 +08:00
<view>
2025-07-01 17:30:46 +08:00
<view
:style="{
width: `${currentSeasonData['10m'].winRate}%`,
backgroundColor: '#FFD947',
}"
/>
2025-06-04 16:26:07 +08:00
</view>
2025-05-02 00:39:37 +08:00
</view>
2025-07-13 13:28:21 +08:00
<view @click.stop="toMyGrowthPage">查看我的比赛记录</view>
2025-05-02 00:39:37 +08:00
</view>
2025-06-04 16:26:07 +08:00
<view class="ranking-data">
2025-05-02 00:39:37 +08:00
<view>
2025-06-04 16:26:07 +08:00
<view
v-for="(rankType, index) in [
2025-07-10 19:55:30 +08:00
'积分榜',
2025-06-04 16:26:07 +08:00
'MVP榜',
'十环榜',
'最牛省份',
]"
:key="index"
:style="{
color: index === selectedIndex ? '#000' : '#fff',
backgroundColor:
index === selectedIndex ? '#FFD947' : 'transparent',
}"
@tap="handleSelect(index)"
>
{{ rankType }}
</view>
2025-05-02 00:39:37 +08:00
</view>
2025-07-01 10:57:49 +08:00
<view
v-for="(item, index) in currentList"
2025-05-02 00:39:37 +08:00
:key="index"
2025-07-01 10:57:49 +08:00
:style="{
backgroundColor: index % 2 === 0 ? '#9898981f' : 'transparent',
}"
class="rank-item"
2025-05-02 00:39:37 +08:00
>
2025-07-01 10:57:49 +08:00
<image
v-if="index === 0"
src="../static/champ1.png"
mode="widthFix"
/>
<image
v-if="index === 1"
src="../static/champ2.png"
mode="widthFix"
/>
<image
v-if="index === 2"
src="../static/champ3.png"
mode="widthFix"
/>
<view v-if="index > 2">{{ index + 1 }}</view>
<image
2025-07-11 00:47:34 +08:00
:src="item.avatar || '../static/user-icon.png'"
2025-07-01 10:57:49 +08:00
mode="widthFix"
:style="{ borderColor: index < 3 ? topThreeColors[index] : '' }"
/>
<view>
<text class="truncate">{{ item.name }}</text>
<text
>{{ getLvlName(item.totalScore) }}{{ item.TotalGames }}</text
2025-06-26 23:41:23 +08:00
>
2025-07-01 10:57:49 +08:00
</view>
<text>{{ item.totalScore }}<text></text></text>
</view>
2025-07-11 00:56:39 +08:00
<view v-if="!currentList.length" class="no-data">
<text>筹备中...</text>
</view>
2025-07-13 13:28:21 +08:00
<view class="see-more" @click.stop="toRankListPage">点击查看更多</view>
2025-05-02 00:39:37 +08:00
</view>
</view>
2025-05-23 21:20:38 +08:00
</Container>
2025-05-01 16:36:24 +08:00
</template>
<style scoped>
2025-06-04 16:26:07 +08:00
.container {
width: 100%;
}
2025-05-02 00:39:37 +08:00
.ranking-my-data,
.ranking-data {
display: flex;
flex-direction: column;
align-items: flex-start;
background-color: #54431d33;
border: 1px solid #54431d;
border-radius: 10px;
margin: 0 15px;
2025-06-24 13:18:03 +08:00
}
2025-06-28 13:42:26 +08:00
.ranking-data {
margin-bottom: 20px;
}
2025-06-24 13:18:03 +08:00
.ranking-my-data {
2025-05-02 00:39:37 +08:00
margin-bottom: 15px;
}
.ranking-my-data {
padding: 15px;
}
.ranking-my-data > view:first-of-type {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
border-bottom: 1px solid #48494e;
padding-bottom: 15px;
}
.user-info {
display: flex;
justify-content: center;
align-items: center;
2025-05-01 16:36:24 +08:00
color: #fff;
font-size: 14px;
}
2025-06-08 20:59:41 +08:00
.user-info > text {
margin-left: 15px;
2025-05-02 00:39:37 +08:00
}
.ranking-season {
display: flex;
justify-content: center;
align-items: center;
2025-07-13 13:28:21 +08:00
position: relative;
2025-05-02 00:39:37 +08:00
}
.ranking-season > image {
width: 12px;
}
.ranking-season > text {
color: #ffd947;
font-size: 14px;
margin-right: 5px;
}
.my-data {
display: flex;
align-items: center;
justify-content: space-around;
color: #b3b3b3;
width: 100%;
margin-top: 15px;
}
.my-data > view {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
height: 60px;
}
.my-data > view:nth-child(2) {
border-left: 1px solid #48494e;
border-right: 1px solid #48494e;
padding: 0 20px;
}
.my-data > view > text:first-child {
font-size: 14px;
}
.my-data > view > text:last-child {
font-size: 18px;
}
.rank-type {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-top: 15px;
}
.rank-type > image {
width: 32%;
}
.data-progress {
width: 100%;
color: #b3b3b3;
display: flex;
flex-direction: column;
align-items: flex-start;
margin-top: 15px;
}
.data-progress > view {
width: 100%;
height: 5px;
border-radius: 10px;
background-color: #696969;
margin-top: 10px;
}
.data-progress > view > view {
height: 5px;
border-radius: 10px;
2025-07-15 18:24:26 +08:00
transition: width 0.3s ease;
2025-05-02 00:39:37 +08:00
}
.ranking-my-data > view:last-child {
color: #39a8ff;
font-size: 14px;
text-align: center;
width: 100%;
padding-top: 15px;
}
.ranking-data > view:first-of-type {
width: calc(100% - 30px);
display: flex;
justify-content: space-around;
font-size: 15px;
padding: 15px;
}
.ranking-data > view:first-of-type > view {
width: 25%;
padding: 7px 10px;
text-align: center;
border-radius: 20px;
}
.rank-item {
width: calc(100% - 30px);
height: 55px;
padding: 0 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
.rank-item > view:first-child {
width: 24px;
height: 24px;
border-radius: 12px;
background-color: #767676;
color: #fff;
text-align: center;
line-height: 24px;
font-size: 14px;
}
.rank-item > image:first-child {
width: 24px;
height: 24px;
}
.rank-item > image:nth-child(2) {
width: 35px;
2025-06-26 23:41:23 +08:00
min-height: 35px;
max-height: 35px;
border-radius: 50%;
border: 1px solid transparent;
2025-05-02 00:39:37 +08:00
}
.rank-item > view:nth-child(3) {
display: flex;
flex-direction: column;
width: 55%;
}
.rank-item > view:nth-child(3) > text:first-child {
color: #fff9;
font-size: 14px;
2025-06-28 12:03:33 +08:00
width: 120px;
2025-05-02 00:39:37 +08:00
}
.rank-item > view:nth-child(3) > text:last-child {
color: #fff4;
font-size: 13px;
}
.rank-item > text:last-child {
color: #fff;
}
.rank-item > text:last-child text {
color: #fff4;
font-size: 13px;
margin-left: 3px;
2025-05-01 16:36:24 +08:00
}
2025-06-24 13:18:03 +08:00
.see-more {
color: #39a8ff;
font-size: 14px;
text-align: center;
width: 100%;
2025-06-28 13:42:26 +08:00
margin-top: 5px;
margin-bottom: 10px;
2025-06-24 13:18:03 +08:00
}
2025-07-11 00:56:39 +08:00
.no-data {
width: 100%;
height: 200px;
display: flex;
justify-content: center;
align-items: center;
color: #fff9;
}
2025-07-13 13:28:21 +08:00
.season-list {
background-color: #000c;
border-radius: 15px;
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
font-size: 12px;
padding: 5px 0;
position: absolute;
width: 220rpx;
top: -44rpx;
right: -30rpx;
letter-spacing: 2px;
}
.season-list > view {
display: flex;
align-items: center;
padding: 10px 20px;
}
.season-list > view > image {
width: 12px;
2025-07-15 18:24:26 +08:00
height: 12px;
2025-07-13 13:28:21 +08:00
margin-left: 10px;
}
2025-05-01 16:36:24 +08:00
</style>