476 lines
12 KiB
Vue
476 lines
12 KiB
Vue
<script setup>
|
||
import { t } from "@/locales";
|
||
|
||
import { computed, ref } from "vue";
|
||
import { onLoad, onShow } from "@dcloudio/uni-app";
|
||
import Container from "@/components/Container.vue";
|
||
import GuideTwo from "@/components/GuideTwo.vue";
|
||
import SButton from "@/components/SButton.vue";
|
||
import SModal from "@/components/SModal.vue";
|
||
import Signin from "@/components/Signin.vue";
|
||
import CreateRoom from "@/components/CreateRoom.vue";
|
||
import Avatar from "@/components/Avatar.vue";
|
||
import ModalDialog from "@/components/ModalDialog.vue";
|
||
|
||
import { getRoomAPI, joinRoomAPI, getBattleDataAPI, getDailyCountAPI } from "@/apis";
|
||
import { debounce, canEenter, getLimitCountText, isLimitReached } from "@/util";
|
||
|
||
import useStore from "@/store";
|
||
import { storeToRefs } from "pinia";
|
||
const store = useStore();
|
||
const { user, device, online, game, dailyCount } = storeToRefs(store);
|
||
const { updateDailyCount } = store;
|
||
|
||
const showModal = ref(false);
|
||
const showSignin = ref(false);
|
||
const warnning = ref("");
|
||
const roomNumber = ref("");
|
||
const data = ref({});
|
||
const roomID = ref("");
|
||
const loading = ref(false);
|
||
const showLimitModal = ref(false);
|
||
const createRoomLoading = ref(false);
|
||
const isSVip = computed(() => user.value.sVip === true);
|
||
const isVip = computed(() => user.value.vip === true && !isSVip.value);
|
||
const challengeLimitText = computed(() =>
|
||
getLimitCountText(t('challenge'), dailyCount.value.challenge)
|
||
);
|
||
|
||
const enterRoom = debounce(async (number) => {
|
||
if (loading.value) return;
|
||
if (!canEenter(user.value, device.value, online.value)) return;
|
||
if (game.value.inBattle) {
|
||
uni.$showHint(1);
|
||
return;
|
||
}
|
||
if (!number) {
|
||
warnning.value = t('please_enter_a_room_number');
|
||
showModal.value = true;
|
||
return;
|
||
}
|
||
loading.value = true;
|
||
let keepLoading = false;
|
||
try {
|
||
const room = await getRoomAPI(number);
|
||
if (!room.number) {
|
||
warnning.value = room.started ? t('this_match_has_already_started_you_cannot_join') : t('room_not_found');
|
||
showModal.value = true;
|
||
return;
|
||
}
|
||
const alreadyIn = room.members.find(
|
||
(item) => item.userInfo.id === user.value.id
|
||
);
|
||
if (!alreadyIn) {
|
||
const result = await joinRoomAPI(number);
|
||
if (result.full) {
|
||
warnning.value = t('room_is_full');
|
||
showModal.value = true;
|
||
return;
|
||
}
|
||
}
|
||
keepLoading = true;
|
||
uni.navigateTo({
|
||
url: "/pages/battle-room?roomNumber=" + number,
|
||
fail: () => {
|
||
loading.value = false;
|
||
},
|
||
});
|
||
} finally {
|
||
if (!keepLoading) loading.value = false;
|
||
}
|
||
});
|
||
const onCreateRoom = debounce(async () => {
|
||
if (createRoomLoading.value) return;
|
||
if (!canEenter(user.value, device.value, online.value)) return;
|
||
createRoomLoading.value = true;
|
||
try {
|
||
const countData = await loadDailyCount();
|
||
if (isLimitReached(countData.challenge)) {
|
||
showLimitModal.value = true;
|
||
return;
|
||
}
|
||
warnning.value = "";
|
||
showModal.value = true;
|
||
} finally {
|
||
createRoomLoading.value = false;
|
||
}
|
||
});
|
||
|
||
const closeLimitModal = () => {
|
||
showLimitModal.value = false;
|
||
};
|
||
|
||
const goVipPage = () => {
|
||
showLimitModal.value = false;
|
||
uni.navigateTo({
|
||
url: "/pages/member/be-vip",
|
||
});
|
||
};
|
||
|
||
const loadDailyCount = async () => {
|
||
if (!user.value.id) return dailyCount.value;
|
||
try {
|
||
const result = await getDailyCountAPI();
|
||
updateDailyCount(result);
|
||
return result || dailyCount.value;
|
||
} catch (error) {
|
||
console.log("load daily count error", error);
|
||
return dailyCount.value;
|
||
}
|
||
};
|
||
const onSignin = () => {
|
||
if (roomID.value && user.value.id) enterRoom(roomID.value);
|
||
showSignin.value = false;
|
||
};
|
||
|
||
/** 跳转到我的战绩页面,默认展示「好友约战」tab */
|
||
const goMyRecord = () => {
|
||
uni.navigateTo({
|
||
url: '/pages/my-growth?tab=1',
|
||
});
|
||
};
|
||
onShow(async () => {
|
||
loading.value = false;
|
||
if (user.value.id) {
|
||
const [result] = await Promise.all([
|
||
getBattleDataAPI(),
|
||
loadDailyCount(),
|
||
]);
|
||
data.value = result;
|
||
}
|
||
});
|
||
onLoad(async (options) => {
|
||
if (options.roomID) {
|
||
roomID.value = options.roomID;
|
||
if (user.value.id) enterRoom(options.roomID);
|
||
else showSignin.value = true;
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<Container :title="t('friend_challenge')" :showBackToGame="true">
|
||
<view :style="{ width: '100%', height: '100%' }">
|
||
<GuideTwo>
|
||
<view class="guide-tips">
|
||
<text class="guide-tips__main">{{ t('invite_friends_for_a_few_matches_and_have_fun_together') }}</text>
|
||
<text class="guide-tips__sub">{{ t('practice_together_level_up_faster_and_join_national_ranked_match') }}</text>
|
||
</view>
|
||
</GuideTwo>
|
||
<view class="my-data">
|
||
<view>
|
||
<Avatar :rankLvl="user.rankLvl" :src="user.avatar" :size="30" />
|
||
<view
|
||
:class="[
|
||
'member-nickname',
|
||
isVip ? 'member-nickname--vip' : '',
|
||
isSVip ? 'member-nickname--svip' : '',
|
||
]"
|
||
>
|
||
<text class="member-nickname__text">{{ user.nickName }}</text>
|
||
<text v-if="isSVip" class="member-nickname__shine">{{
|
||
user.nickName
|
||
}}</text>
|
||
</view>
|
||
<text class="my-record-btn" @click="goMyRecord">{{ t('my_results') }}</text>
|
||
</view>
|
||
<view>
|
||
<view>
|
||
<view>
|
||
<text>{{ data.TotalBattle }}</text>
|
||
<text>{{ t('matches') }}</text>
|
||
</view>
|
||
<text>{{ t('challenges') }}</text>
|
||
</view>
|
||
<view>
|
||
<view>
|
||
<text>{{ data.totalArrow }}</text>
|
||
<text>{{ t('arrows') }}</text>
|
||
</view>
|
||
<text>{{ t('arrows_shot') }}</text>
|
||
</view>
|
||
<view>
|
||
<view class="stars">
|
||
<block v-for="i in 5" :key="i">
|
||
<image v-if="data.totalWinningRate >= i * 0.2" src="https://static.shelingxingqiu.com/shootmini/static/star-full.png" mode="widthFix" />
|
||
<image v-else-if="data.totalWinningRate >= (i - 1) * 0.2 + 0.1" src="https://static.shelingxingqiu.com/shootmini/static/star-half.png"
|
||
mode="widthFix" />
|
||
<image v-else src="https://static.shelingxingqiu.com/shootmini/static/star-empty.png" mode="widthFix" />
|
||
</block>
|
||
</view>
|
||
<text>{{ t('challenge_difficulty') }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="founded-room">
|
||
<image src="https://static.shelingxingqiu.com/shootmini/static/founded-room.png" mode="widthFix" />
|
||
<view>
|
||
<input :placeholder="t('enter_room_number')" v-model="roomNumber" placeholder-style="color: #ccc" />
|
||
<view @click="$clickSound(() => enterRoom(roomNumber))">{{ t('join_room') }}</view>
|
||
</view>
|
||
</view>
|
||
<view class="create-room">
|
||
<image src="https://static.shelingxingqiu.com/attachment/2025-07-15/dbcejys872iyun92h6.png" mode="widthFix" />
|
||
<image src="https://static.shelingxingqiu.com/shootmini/static/room-notfound-title.png" mode="widthFix" />
|
||
<view>
|
||
<image :src="user.avatar" mode="widthFix" />
|
||
<image src="https://static.shelingxingqiu.com/shootmini/static/versus.png" mode="widthFix" />
|
||
<view>
|
||
<image src="https://static.shelingxingqiu.com/shootmini/static/question-mark.png" mode="widthFix" />
|
||
</view>
|
||
</view>
|
||
<view>
|
||
<view v-if="challengeLimitText" class="pp-text">
|
||
{{ challengeLimitText }}
|
||
</view>
|
||
<SButton
|
||
width="80%"
|
||
:rounded="30"
|
||
:disabled="createRoomLoading"
|
||
:onClick="() => { $clickSound(); return onCreateRoom(); }"
|
||
>{{ t('create_challenge_room') }}</SButton>
|
||
</view>
|
||
</view>
|
||
<SModal :show="showModal" :onClose="() => (showModal = false)" height="716rpx">
|
||
<view v-if="warnning" class="warnning">
|
||
{{ warnning }}
|
||
</view>
|
||
<!-- showModal 关闭时立即销毁组件,重开时重建,确保选项重置为 0 -->
|
||
<CreateRoom v-if="!warnning && showModal" :onConfirm="() => (showModal = false)" />
|
||
</SModal>
|
||
<Signin :show="showSignin" :onClose="onSignin" />
|
||
</view>
|
||
</Container>
|
||
<ModalDialog
|
||
:show="showLimitModal"
|
||
:content="t('you_have_used_all_your_challenges_for_today_activate_membership_')"
|
||
:cancelText="t('got_it_335')"
|
||
:confirmText="t('activate')"
|
||
:onCancel="closeLimitModal"
|
||
:onConfirm="goVipPage"
|
||
/>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.guide-tips {
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding-left: 112rpx;
|
||
width: 100%;
|
||
}
|
||
.guide-tips__main {
|
||
font-weight: 400;
|
||
font-size: 26rpx;
|
||
color: rgba(255, 217, 71, 0.8);
|
||
}
|
||
.guide-tips__sub {
|
||
font-weight: 400;
|
||
font-size: 22rpx;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
margin-top: 6rpx;
|
||
}
|
||
|
||
.founded-room {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
background-color: #54431d33;
|
||
border: 1px solid #54431d;
|
||
margin: 15px;
|
||
border-radius: 10px;
|
||
padding: 15px;
|
||
}
|
||
|
||
.founded-room>image {
|
||
width: 16vw;
|
||
}
|
||
|
||
.founded-room>view {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: 15px;
|
||
background-color: #fff;
|
||
border-radius: 30px;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.founded-room>view>input {
|
||
width: 70%;
|
||
text-align: center;
|
||
font-size: 14px;
|
||
height: 40px;
|
||
color: #000;
|
||
}
|
||
|
||
.founded-room>view>view {
|
||
background-color: #fed847;
|
||
width: 30%;
|
||
line-height: 40px;
|
||
border-radius: 30px;
|
||
font-size: 14px;
|
||
padding: 3px 0;
|
||
font-weight: bold;
|
||
color: #000;
|
||
text-align: center;
|
||
}
|
||
|
||
.create-room {
|
||
position: relative;
|
||
margin: 15px;
|
||
height: 50vw;
|
||
}
|
||
|
||
.create-room>image:first-of-type {
|
||
position: absolute;
|
||
width: 100%;
|
||
}
|
||
|
||
.create-room>image:nth-of-type(2) {
|
||
padding: 15px;
|
||
width: 25vw;
|
||
position: relative;
|
||
}
|
||
|
||
.create-room>view:nth-child(3) {
|
||
margin: 12vw auto 5vw auto;
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.create-room>view>image:first-child {
|
||
width: 19vw;
|
||
transform: translateY(-60%);
|
||
border-radius: 50%;
|
||
position: relative;
|
||
}
|
||
|
||
.create-room>view>image:nth-child(2) {
|
||
width: 37vw;
|
||
position: relative;
|
||
}
|
||
|
||
.create-room>view>view:nth-child(3) {
|
||
position: relative;
|
||
width: 19vw;
|
||
height: 19vw;
|
||
border-radius: 50%;
|
||
background-color: #ccc;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
transform: translateY(60%);
|
||
}
|
||
|
||
.create-room>view>view:nth-child(3)>image {
|
||
width: 20px;
|
||
margin-right: 2px;
|
||
}
|
||
|
||
.pp-text{
|
||
color: #fff;
|
||
text-align: center;
|
||
font-size: 22rpx;
|
||
margin-bottom: 20rpx;
|
||
}
|
||
|
||
.warnning {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
color: #fff9;
|
||
}
|
||
|
||
.my-data {
|
||
width: calc(100% - 30px);
|
||
margin: 15px;
|
||
margin-top: 0;
|
||
border-radius: 10px;
|
||
border: 1px solid #54431d;
|
||
overflow: hidden;
|
||
background-color: #54431d33;
|
||
}
|
||
|
||
.my-data>view {
|
||
width: 100%;
|
||
display: flex;
|
||
color: #fff9;
|
||
}
|
||
|
||
.my-data>view:first-child {
|
||
width: calc(100% - 30px);
|
||
align-items: flex-end;
|
||
padding-bottom: 15px;
|
||
border-bottom: 1px solid #48494e;
|
||
margin: 15px;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.my-data>view:first-child>.my-record-btn {
|
||
font-weight: 400;
|
||
font-size: 24rpx;
|
||
color: #76D4FF;
|
||
text-align: center;
|
||
font-style: normal;
|
||
width: auto;
|
||
margin-left: auto;
|
||
}
|
||
|
||
.my-data>view:first-child>.member-nickname {
|
||
color: #fff;
|
||
margin-left: 10px;
|
||
width: 120px;
|
||
}
|
||
|
||
.my-data>view:first-child>.member-nickname__text,
|
||
.my-data>view:first-child>.member-nickname__shine {
|
||
font-size: 17px;
|
||
}
|
||
|
||
.my-data>view:last-child {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
.my-data>view:last-child>view {
|
||
width: 33%;
|
||
margin-top: 15px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.my-data>view:last-child>view>view {
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.my-data>view:last-child>view>view>text:first-child {
|
||
color: #fff;
|
||
font-size: 20px;
|
||
margin-right: 5px;
|
||
transform: translateY(4px);
|
||
}
|
||
|
||
.my-data>view:last-child>view:nth-child(2) {
|
||
border-left: 1px solid #48494e;
|
||
border-right: 1px solid #48494e;
|
||
}
|
||
|
||
.my-data>view:last-child>view>view {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
height: 20px;
|
||
}
|
||
|
||
.stars>image {
|
||
width: 4vw;
|
||
height: 4vw;
|
||
margin: 0 1px;
|
||
}
|
||
</style>
|