Files
shoot-miniprograms/src/pages/friend-battle.vue

365 lines
8.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup>
import { 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 { getRoomAPI, joinRoomAPI, getBattleDataAPI } from "@/apis";
import { debounce, canEenter } from "@/util";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user, device, online, game } = storeToRefs(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 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 = "请输入房间号";
showModal.value = true;
return;
}
try {
const room = await getRoomAPI(number);
if (!room.number) {
warnning.value = room.started ? "该房间对战已开始,无法加入" : "查无此房";
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 = "房间已满员";
showModal.value = true;
return;
}
}
loading.value = true;
uni.navigateTo({
url: "/pages/battle-room?roomNumber=" + number,
});
} finally {
loading.value = false;
}
});
const onCreateRoom = async () => {
if (!canEenter(user.value, device.value, online.value)) return;
warnning.value = "";
showModal.value = true;
};
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 () => {
if (user.value.id) {
const result = await getBattleDataAPI();
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="好友约战" :showBackToGame="true">
<view :style="{ width: '100%', height: '100%' }">
<GuideTwo>
<text :style="{color: 'rgba(255,217,71,0.8)'}">约上朋友开几局欢乐多不寂寞</text>
<text>一起练升级更快早日加入全国排位赛</text>
</GuideTwo>
<view class="my-data">
<view>
<Avatar :rankLvl="user.rankLvl" :src="user.avatar" :size="30" />
<text class="truncate">{{ user.nickName }}</text>
<text class="my-record-btn" @click="goMyRecord">我的战绩</text>
</view>
<view>
<view>
<view>
<text>{{ data.TotalBattle }}</text>
<text></text>
</view>
<text>约战数量</text>
</view>
<view>
<view>
<text>{{ data.totalArrow }}</text>
<text></text>
</view>
<text>射箭量</text>
</view>
<view>
<view class="stars">
<block v-for="i in 5" :key="i">
<image v-if="data.totalWinningRate >= i * 0.2" src="../static/star-full.png" mode="widthFix" />
<image v-else-if="data.totalWinningRate >= (i - 1) * 0.2 + 0.1" src="../static/star-half.png"
mode="widthFix" />
<image v-else src="../static/star-empty.png" mode="widthFix" />
</block>
</view>
<text>挑战难度</text>
</view>
</view>
</view>
<view class="founded-room">
<image src="../static/founded-room.png" mode="widthFix" />
<view>
<input placeholder="输入房间号" v-model="roomNumber" placeholder-style="color: #ccc" />
<view @click="enterRoom(roomNumber)">进入房间</view>
</view>
</view>
<view class="create-room">
<image src="https://static.shelingxingqiu.com/attachment/2025-07-15/dbcejys872iyun92h6.png" mode="widthFix" />
<image src="../static/room-notfound-title.png" mode="widthFix" />
<view>
<image :src="user.avatar" mode="widthFix" />
<image src="../static/versus.png" mode="widthFix" />
<view>
<image src="../static/question-mark.png" mode="widthFix" />
</view>
</view>
<view>
<SButton width="80%" :rounded="30" :onClick="onCreateRoom">
创建约战房
</SButton>
</view>
</view>
<SModal :show="showModal" :onClose="() => (showModal = false)" height="716rpx">
<view v-if="warnning" class="warnning">
{{ warnning }}
</view>
<CreateRoom v-if="!warnning" :onConfirm="() => (showModal = false)" />
</SModal>
<Signin :show="showSignin" :onClose="onSignin" />
</view>
</Container>
</template>
<style scoped>
.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;
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;
}
.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>text {
color: #fff;
font-size: 17px;
margin-left: 10px;
width: 120px;
}
.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>