This commit is contained in:
kron
2025-06-24 13:18:03 +08:00
parent fa219892e0
commit c507a40aad
31 changed files with 780 additions and 167 deletions

View File

@@ -194,4 +194,10 @@ button::after {
font-size: 14px;
margin-bottom: 10px;
}
.truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
}
</style>

View File

@@ -18,7 +18,7 @@ const tabs = [
];
function handleTabClick(index) {
if (index !== 0 && !user.value.id) return props.signin();
if (index === 1 && !user.value.id) return props.signin();
if (index === 0) {
uni.navigateTo({
url: "/pages/be-vip",

View File

@@ -52,6 +52,8 @@ const props = defineProps({
:rowCount="arrows.length === 12 ? 6 : 9"
:total="arrows.length"
:scores="arrows.map((a) => a.ring)"
:margin="arrows.length === 12 ? 4 : 1"
:fontSize="arrows.length === 12 ? 25 : 22"
/>
</view>
</template>

View File

@@ -1,6 +1,12 @@
<script setup>
import { ref, watch } from "vue";
import BowPower from "@/components/BowPower.vue";
import { simulShootAPI } from "@/apis";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { device } = storeToRefs(store);
const props = defineProps({
totalRound: {
type: Number,
@@ -38,6 +44,10 @@ const props = defineProps({
type: Boolean,
default: true,
},
start: {
type: Boolean,
default: false,
},
showE: {
type: Boolean,
default: true,
@@ -73,6 +83,9 @@ function calcRealY(num) {
const len = num < 0 ? Math.abs(num) + 20 : 20 - num;
return `calc(${(len / 40) * 100}% - 10px)`;
}
const simulShoot = async () => {
if (device.value.deviceId) await simulShootAPI(device.value.deviceId);
};
</script>
<template>
@@ -90,8 +103,9 @@ function calcRealY(num) {
<view
v-if="scores.length && showRoundTips && showLatestArrow && showE"
class="e-value fade-in"
>经验 +1</view
>
经验 +1
</view>
<view
v-if="scores.length && showRoundTips && showLatestArrow"
class="round-tip fade-in"
@@ -133,6 +147,9 @@ function calcRealY(num) {
<image :src="avatar" mode="widthFix" />
</view>
<text v-if="tips">{{ tips }}</text>
<view class="simul" @click="simulShoot" :style="{ color: '#fff' }">
模拟射箭
</view>
</view>
</template>
@@ -141,9 +158,11 @@ function calcRealY(num) {
width: calc(100% - 30px);
padding: 15px;
/* overflow: hidden; */
position: relative;
}
.target {
position: relative;
padding: 5px;
}
.e-value {
position: absolute;
@@ -166,7 +185,7 @@ function calcRealY(num) {
z-index: 2;
}
.round-tip > text {
font-size: 18px;
font-size: 24px;
margin-left: 5px;
}
.target > image:last-child {
@@ -217,4 +236,11 @@ function calcRealY(num) {
display: block;
margin-top: 20px;
}
.simul {
position: absolute;
bottom: 20px;
right: 20px;
color: #fff;
margin-left: 20px;
}
</style>

View File

@@ -1,14 +1,19 @@
<script setup>
defineProps({
tall: {
type: Boolean,
default: false,
},
noBg: {
type: Boolean,
default: false,
},
type: {
type: Number,
default: 0,
},
});
const bubbleTypes = [
"../static/long-bubble.png",
"../static/long-bubble-middle.png",
"../static/long-bubble-tall.png",
];
</script>
<template>
@@ -17,10 +22,8 @@ defineProps({
<view>
<image
v-if="!noBg"
:src="
tall ? '../static/long-bubble-tall.png' : '../static/long-bubble.png'
"
:style="{ top: tall ? '-6%' : '-12%' }"
:src="bubbleTypes[type]"
:style="{ top: type === 2 ? '-5%' : '-12%' }"
mode="widthFix"
/>
<slot />

View File

@@ -1,10 +1,5 @@
<script setup>
import { ref, onMounted } from "vue";
import useStore from "@/store";
import { simulShootAPI } from "@/apis";
import { storeToRefs } from "pinia";
const store = useStore();
const { device } = storeToRefs(store);
const isIos = ref(true);
const props = defineProps({
@@ -18,12 +13,6 @@ const props = defineProps({
},
});
const simulShoot = async () => {
if (device.value.deviceId) {
await simulShootAPI(device.value.deviceId);
}
};
const onClick = () => {
if (props.onBack) props.onBack();
else uni.navigateBack();
@@ -41,7 +30,6 @@ onMounted(() => {
<image src="../static/back.png" mode="widthFix" />
</view>
<text>{{ title }}</text>
<view class="simul" @click="simulShoot">模拟射箭</view>
</view>
</template>
@@ -67,8 +55,4 @@ onMounted(() => {
.container > text {
color: #fff;
}
.simul {
color: #fff;
margin-left: 20px;
}
</style>

View File

@@ -77,13 +77,14 @@ const onSelect = (userId) => {
<BowTarget
:scores="scores"
:showLatestArrow="false"
:avatar="currentUser.avatar"
:avatar="currentUser ? currentUser.avatar : ''"
/>
</view>
<view class="score-text"
><text :style="{ color: '#fed847' }">12</text>支箭<text
:style="{ color: '#fed847' }"
>100</text
><text :style="{ color: '#fed847' }">{{ scores.length }}</text
>支箭<text :style="{ color: '#fed847' }">{{
scores.reduce((last, next) => last + next.ring, 0)
}}</text
></view
>
<view class="score-row">

View File

@@ -53,16 +53,15 @@ const rowCount = new Array(6).fill(0);
<style scoped>
.container {
width: calc(100% - 75px);
width: calc(100% - 70px);
display: flex;
align-items: center;
border: 1px solid #fff3;
margin: 10px 0;
margin-left: 40px;
margin-left: 35px;
border-radius: 15px;
padding: 10px;
color: #fff9;
margin-right: 20px;
font-size: 14px;
position: relative;
}

View File

@@ -44,7 +44,8 @@ watch(
margin: margin + 'px',
}"
>
{{ scores[index] }}
<image src="../static/score-bg.png" mode="widthFix" />
<text>{{ scores[index] }}</text>
</view>
</view>
</template>
@@ -58,13 +59,22 @@ watch(
margin: 0 5vw;
}
.score-item {
background-image: url("../static/score-bg.png");
/* background-image: url("../static/score-bg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
background-position: center; */
color: #fed847;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.score-item > image {
position: absolute;
width: 100%;
top: 5%;
}
.score-item > text {
position: relative;
}
</style>

View File

@@ -52,11 +52,7 @@ setTimeout(() => {
<image src="../static/finish-frame.png" mode="widthFix" />
<text
>完成<text class="gold-text">{{ total }}</text
>获得<text class="gold-text">{{
result.arrows
.map((a) => a.ring)
.reduce((last, next) => last + next, 0)
}}</text
>获得<text class="gold-text">{{ total }}</text
>点经验</text
>
</view>

View File

@@ -118,6 +118,7 @@ onUnmounted(() => {
}
.container > view:first-child > button:last-child > image {
width: 50px;
transform: translateX(10px);
}
.container > view:last-child {
z-index: -1;

View File

@@ -137,7 +137,7 @@ const handleLogin = () => {
align-items: center;
margin-bottom: 20px;
border-bottom: 1px solid #fff3;
padding: 20px 2px;
line-height: 55px;
}
.avatar {
margin: 0;

View File

@@ -22,6 +22,7 @@ const redScores = ref([]);
const blueScores = ref([]);
const tabs = ref(["所有轮次"]);
const players = ref([]);
const allRoundsScore = ref({});
const onClickTab = (index) => {
selected.value = index;
redScores.value = [];
@@ -29,14 +30,22 @@ const onClickTab = (index) => {
const { bluePlayers, redPlayers, roundsData } = props.data;
if (index === 0) {
Object.keys(bluePlayers).forEach((p) => {
allRoundsScore.value[p] = [];
Object.values(roundsData).forEach((round) => {
allRoundsScore.value[p].push(
round[p].reduce((last, next) => last + next.ring, 0)
);
round[p].forEach((arrow) => {
blueScores.value.push(arrow);
});
});
});
Object.keys(redPlayers).forEach((p) => {
allRoundsScore.value[p] = [];
Object.values(roundsData).forEach((round) => {
allRoundsScore.value[p].push(
round[p].reduce((last, next) => last + next.ring, 0)
);
round[p].forEach((arrow) => {
redScores.value.push(arrow);
});
@@ -108,6 +117,15 @@ watch(
:src="player.avatar"
:borderColor="data.bluePlayers[player.playerId] ? 1 : 2"
/>
<view
v-if="selected === 0"
v-for="(ring, index) in allRoundsScore[player.playerId]"
:key="index"
class="score-item"
:style="{ width: '13vw', height: '13vw' }"
>
{{ ring }}
</view>
<view
v-if="selected > 0"
v-for="(score, index) in data.roundsData[selected][player.playerId]"

View File

@@ -10,6 +10,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
onSignin: {
type: Function,
default: () => {},
},
});
const nextLvlPoints = ref("");
const containerWidth = computed(() => (props.showRank ? "72vw" : "100vw"));
@@ -39,7 +43,13 @@ onMounted(() => {
<template>
<view class="container" :style="{ width: containerWidth }">
<Avatar :frame="true" :src="user.avatar" :onClick="toUserPage" :size="42" />
<block v-if="user.id"
><Avatar
:frame="true"
:src="user.avatar"
:onClick="toUserPage"
:size="42"
/>
<view class="user-details">
<view class="user-name">
<text>{{ user.nickName }}</text>
@@ -79,6 +89,19 @@ onMounted(() => {
></text
> -->
</view>
</block>
<block v-else>
<view class="signin">
<image src="../static/user-icon.png" mode="widthFix" />
<view @click="() => (showModal = true)">
<text>新来的弓箭手你好呀~</text>
<view @click="onSignin">
<text>微信登录</text>
<image src="../static/enter-arrow-blue.png" mode="widthFix" />
</view>
</view>
</view>
</block>
</view>
</template>
@@ -163,23 +186,54 @@ onMounted(() => {
}
.rank-info {
width: 68px;
text-align: left;
font-size: 12px;
position: relative;
color: #b3b3b3;
padding-left: 8px;
margin-left: 8px;
display: flex;
flex-direction: column;
}
.rank-info-image {
position: absolute;
top: -6px;
left: -9px;
width: 90px;
}
.rank-info > text {
text-align: center;
}
.rank-number {
display: block;
}
.signin {
display: flex;
align-items: center;
}
.signin > image {
width: 40px;
height: 40px;
}
.signin > view {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
margin-left: 12px;
font-size: 14px;
}
.signin > view > view:last-child {
display: flex;
align-items: center;
}
.signin > view > view:last-child > text {
color: #39a8ff;
margin-top: 2px;
}
.signin > view > view:last-child > image {
width: 15px;
margin-top: 2px;
}
</style>

View File

@@ -68,6 +68,15 @@
},
{
"path": "pages/battle-result"
},
{
"path": "pages/team-bow-data"
},
{
"path": "pages/melee-bow-data"
},
{
"path": "pages/mine-bow-data"
}
],
"globalStyle": {

View File

@@ -2,8 +2,6 @@
import { ref, onMounted } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import { getGameAPI } from "@/apis";
import TeamResult from "@/components/TeamResult.vue";
import MeleeResult from "@/components/MeleeResult.vue";
import Avatar from "@/components/Avatar.vue";
import { getHomeData } from "@/apis";
import useStore from "@/store";
@@ -16,13 +14,12 @@ const battleId = ref("");
const ifWin = ref(false);
const data = ref({});
const totalPoints = ref(0);
const show = ref(false);
onLoad(async (options) => {
battleId.value = options.battleId;
const result = await getGameAPI(
// options.battleId || "BATTLE-1749386862250435325-854"
options.battleId || "BATTLE-1750142722977234017-746"
// options.battleId || "BATTLE-1750688685843436271-553"
options.battleId || "BATTLE-1750688536849458226-518"
);
data.value = result;
if (result.mode === 1 && result.redPlayers[user.value.id]) {
@@ -45,6 +42,18 @@ onMounted(async () => {
const result = await getHomeData();
if (result.user) updateUser(result.user);
});
const checkBowData = () => {
if (data.value.mode === 1) {
uni.navigateTo({
url: `/pages/team-bow-data?battleId=${battleId.value}`,
});
} else if (data.value.mode === 2) {
uni.navigateTo({
url: `/pages/melee-bow-data?battleId=${battleId.value}`,
});
}
};
</script>
<template>
@@ -56,7 +65,7 @@ onMounted(async () => {
mode="widthFix"
/>
<block v-if="data.mode === 1">
<view class="header-team">
<view class="header-team" :style="{ marginTop: '25%' }">
<image src="../static/battle-result.png" mode="widthFix" />
</view>
<view class="battle-winner">
@@ -73,7 +82,13 @@ onMounted(async () => {
<view />
</view>
<view class="players">
<view v-for="(player, index) in data.players" :key="index">
<view
v-for="(player, index) in data.players"
:key="index"
:style="{
border: player.playerId === user.id ? '1px solid #B04630' : 'none',
}"
>
<image
v-if="index === 0"
class="player-bg"
@@ -111,7 +126,7 @@ onMounted(async () => {
mode="widthFix"
/>
<view v-if="index > 2" class="view-crown">{{ index + 1 }}</view>
<Avatar src="../static/avatar.png" :size="36" />
<Avatar :src="player.avatar" :size="36" />
<view class="player-title">
<text>{{ player.name }}</text>
<text>钻石三级</text>
@@ -133,21 +148,9 @@ onMounted(async () => {
>好成绩全国排位赛等着你</text
>
<view class="op-btn">
<view @click="() => (show = true)">查看靶纸</view>
<view @click="checkBowData">查看靶纸</view>
<view @click="exit">退出</view>
</view>
<TeamResult
v-if="data.mode === 1"
:show="show"
:onClose="() => (show = false)"
:data="data"
/>
<MeleeResult
v-if="data.mode === 2"
:show="show"
:onClose="() => (show = false)"
:data="data"
/>
</view>
</template>
@@ -155,12 +158,12 @@ onMounted(async () => {
.container {
width: 100vw;
height: 100vh;
background-color: #000;
background-color: #292929;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
justify-content: flex-start;
}
.tag {
position: absolute;
@@ -199,14 +202,16 @@ onMounted(async () => {
}
.battle-winner > text:nth-child(3) {
font-size: 30px;
margin: 10px;
margin-bottom: 5px;
font-weight: bold;
color: #fed847;
}
.battle-winner > text:nth-child(4) {
margin-bottom: 10px;
}
.battle-e {
width: 100%;
height: 60px;
margin: 20px 0;
}
.battle-e > image {
position: absolute;
@@ -251,6 +256,7 @@ onMounted(async () => {
justify-content: center;
width: 100%;
margin-bottom: 30px;
margin-top: 25%;
}
.header-melee > view {
height: 1px;
@@ -280,6 +286,7 @@ onMounted(async () => {
background-color: #ffffff1a;
display: flex;
align-items: center;
box-sizing: border-box;
}
.player-bg {
position: absolute;

View File

@@ -3,12 +3,15 @@ import { ref } from "vue";
import Container from "@/components/Container.vue";
import Avatar from "@/components/Avatar.vue";
import SButton from "@/components/SButton.vue";
import SModal from "@/components/SModal.vue";
import Signin from "@/components/Signin.vue";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user, config } = storeToRefs(store);
const selectedVIP = ref(0);
const showModal = ref(false);
const chooseVip = (index) => {
selectedVIP.value = index;
@@ -16,10 +19,8 @@ const chooseVip = (index) => {
const onPay = () => {
if (!user.value.id) {
return uni.showToast({
title: "请先登录",
icon: "none",
});
showModal.value = true;
} else {
}
};
</script>
@@ -29,7 +30,7 @@ const onPay = () => {
<view v-if="user.id" class="header">
<view>
<Avatar :src="user.avatar" :size="35" :border="true" />
<text>{{ user.nickName }}</text>
<text class="truncate">{{ user.nickName }}</text>
</view>
<text>5月5号到期</text>
</view>
@@ -76,6 +77,9 @@ const onPay = () => {
</view>
</view>
<SButton :onClick="onPay">支付</SButton>
<SModal :show="showModal" :onClose="() => (showModal = false)">
<Signin :onClose="() => (showModal = false)" />
</SModal>
</view>
</Container>
</template>
@@ -97,6 +101,8 @@ const onPay = () => {
}
.header > view > text:last-child {
margin-left: 10px;
width: 120px;
text-align: left;
}
.header > text:nth-child(2) {
color: #fed847;

View File

@@ -118,8 +118,12 @@ const onClose = () => {
<view class="container">
<Guide
v-if="step !== 4"
:tall="
(step === 1 && user.nickName.length > 6) || step === 2 || step === 5
:type="
step === 2
? 2
: step === 5 || (step === 1 && user.nickName.length > 6)
? 1
: 0
"
>
<text v-if="step === 0">

View File

@@ -67,21 +67,19 @@ onMounted(async () => {
console.error("获取配置失败:", error);
}
});
const comingSoon = () => {
uni.showToast({
title: "敬请期待",
icon: "none",
});
};
</script>
<template>
<view class="root-container" :style="{ paddingTop: isIos ? '45px' : '40px' }">
<AppBackground />
<!-- 根据登录状态显示用户信息或登录按钮 -->
<block v-if="user.id">
<UserHeader showRank />
</block>
<block v-else>
<view class="signin-btn" @click="() => (showModal = true)">
<text>新来的弓箭手你好呀~</text>
<text>微信登录 &gt;</text>
</view>
</block>
<UserHeader showRank :onSignin="() => (showModal = true)" />
<view class="container">
<view class="feature-grid">
<view class="bow-card">
@@ -141,6 +139,7 @@ onMounted(async () => {
v-for="(region, index) in ['广东', '湖南', '内蒙', '海南', '四川']"
:key="index"
class="region-item"
@click="comingSoon"
>
<image src="../static/region-bg.png" mode="widthFix" />
<image
@@ -174,7 +173,7 @@ onMounted(async () => {
<text></text>
</view>
</view>
<view class="region-more">
<view class="region-more" @click="comingSoon">
<image src="../static/region-more.png" mode="widthFix" />
<text>...</text>
<text>更多</text>
@@ -385,16 +384,4 @@ onMounted(async () => {
line-height: 20px;
margin-bottom: 5px;
}
.signin-btn {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
margin-left: 10px;
font-size: 14px;
}
.signin-btn > text:last-child {
color: #39a8ff;
margin-top: 2px;
}
</style>

View File

@@ -4,21 +4,23 @@ import { onLoad } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import BattleHeader from "@/components/BattleHeader.vue";
import Avatar from "@/components/Avatar.vue";
import TeamResult from "@/components/TeamResult.vue";
import MeleeResult from "@/components/MeleeResult.vue";
// import TeamResult from "@/components/TeamResult.vue";
// import MeleeResult from "@/components/MeleeResult.vue";
import PlayerScore from "@/components/PlayerScore.vue";
import { getGameAPI } from "@/apis";
const blueTeam = ref([]);
const redTeam = ref([]);
const roundsData = ref([]);
const battleId = ref("");
const data = ref({
players: [],
});
const show = ref(false);
// const show = ref(false);
onLoad(async (options) => {
if (options.id) {
battleId.value = options.id;
const result = await getGameAPI(options.id);
data.value = result;
if (result.mode === 1) {
@@ -51,6 +53,18 @@ onLoad(async (options) => {
}
}
});
const checkBowData = () => {
if (data.value.mode === 1) {
uni.navigateTo({
url: `/pages/team-bow-data?battleId=${battleId.value}`,
});
} else if (data.value.mode === 2) {
uni.navigateTo({
url: `/pages/melee-bow-data?battleId=${battleId.value}`,
});
}
};
</script>
<template>
@@ -93,7 +107,7 @@ onLoad(async (options) => {
:style="{ border: 'none', padding: '5px 15px' }"
>
<text>大乱斗</text>
<view @click="() => (show = true)">
<view @click="checkBowData">
<text>查看靶纸</text>
<image src="../static/back.png" mode="widthFix" />
</view>
@@ -114,7 +128,7 @@ onLoad(async (options) => {
>
<view class="score-header">
<text>{{ index + 1 }}</text>
<view @click="() => (show = true)">
<view @click="checkBowData">
<text>查看靶纸</text>
<image src="../static/back.png" mode="widthFix" />
</view>
@@ -150,7 +164,7 @@ onLoad(async (options) => {
</view>
<view :style="{ height: '20px' }"></view>
</view>
<TeamResult
<!-- <TeamResult
v-if="data.mode === 1"
:show="show"
:onClose="() => (show = false)"
@@ -161,7 +175,7 @@ onLoad(async (options) => {
:show="show"
:onClose="() => (show = false)"
:data="data"
/>
/> -->
</Container>
</template>

View File

@@ -0,0 +1,187 @@
<script setup>
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import BowTarget from "@/components/BowTarget.vue";
import Avatar from "@/components/Avatar.vue";
import { roundsName } from "@/constants";
import { getGameAPI } from "@/apis";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user } = storeToRefs(store);
const scores = ref([]);
const currentUser = ref({});
const data = ref({});
onLoad(async (options) => {
if (options.battleId) {
const result = await getGameAPI(options.battleId);
data.value = result;
const mine = result.players.find((p) => p.playerId === user.value.id);
currentUser.value = mine;
if (mine && mine.arrowHistory) {
scores.value = mine.arrowHistory;
}
}
});
const onSelect = (userId) => {
const user = data.value.players.find((p) => p.playerId === userId);
currentUser.value = user;
if (user && user.arrowHistory) {
scores.value = user.arrowHistory;
}
};
</script>
<template>
<Container title="5人大乱斗 - 靶纸">
<view class="container">
<view class="rank-rows">
<view
v-for="(player, index) in data.players"
:key="index"
@click="() => onSelect(player.playerId)"
>
<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" class="rank-view">{{ index + 1 }}</view>
<Avatar :src="player.avatar" :size="24" />
<text
>积分
{{
player.totalScore > 0
? "+" + player.totalScore
: player.totalScore
}}</text
>
<text>{{ player.totalRings }}</text>
<text v-for="(arrow, index2) in player.arrowHistory" :key="index2">
{{ arrow.ring }}
</text>
</view>
</view>
<view :style="{ margin: '20px 0' }">
<BowTarget
:scores="scores"
:showLatestArrow="false"
:avatar="currentUser ? currentUser.avatar : ''"
/>
</view>
<view class="score-text"
><text :style="{ color: '#fed847' }">{{ scores.length }}</text
>支箭<text :style="{ color: '#fed847' }">{{
scores.reduce((last, next) => last + next.ring, 0)
}}</text
></view
>
<view class="score-row">
<view
v-for="(score, index) in scores"
:key="index"
class="score-item"
:style="{ width: '13vw', height: '13vw' }"
>
{{ score.ring }}
</view>
</view>
</view>
</Container>
</template>
<style scoped>
.container {
width: 100%;
flex-direction: column;
justify-content: center;
align-items: center;
}
.score-text {
width: 100%;
color: #fff;
text-align: center;
font-size: 16px;
margin-bottom: 6px;
}
.score-row {
margin: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
.score-item {
background-image: url("../static/score-bg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
color: #fed847;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
margin: 3px;
}
.rank-rows {
display: flex;
flex-direction: column;
width: 100%;
border-top: 1px solid #fff3;
}
.rank-rows > view {
width: clac(100% - 20px);
color: #fff9;
border-bottom: 1px solid #fff3;
padding: 7px 10px;
display: flex;
align-items: center;
font-size: 14px;
overflow-x: auto;
}
.rank-rows > view::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
}
.rank-rows > view > image:first-child,
.rank-rows > view > view:first-child {
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
font-size: 12px;
margin-right: 10px;
flex: 0 0 auto;
}
.rank-rows > view > view:first-child {
background-color: #6d6d6d;
border-radius: 50%;
}
.rank-rows > view > text {
margin-left: 10px;
flex: 0 0 auto;
display: block;
width: 25px;
}
.rank-rows > view > text:nth-child(3) {
width: 80px;
}
.rank-rows > view > text:nth-child(4) {
color: #fed847;
padding-right: 10px;
border-right: 1px solid #fff3;
width: 32px;
}
</style>

102
src/pages/mine-bow-data.vue Normal file
View File

@@ -0,0 +1,102 @@
<script setup>
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import Avatar from "@/components/Avatar.vue";
import BowTarget from "@/components/BowTarget.vue";
import ScorePanel from "@/components/ScorePanel.vue";
import { getPractiseAPI } from "@/apis";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user } = storeToRefs(store);
const arrows = ref([]);
onLoad(async (options) => {
if (options.id) {
const result = await getPractiseAPI(options.id);
arrows.value = result.arrows;
}
});
</script>
<template>
<Container title="个人练习 - 靶纸">
<view class="container">
<!-- <view class="header">
<view>
<Avatar :src="user.avatar" frame />
<view>
<text>{{ user.nickName }}</text>
<text>{{ user.lvlName }}</text>
</view>
</view>
</view> -->
<view :style="{ marginBottom: '20px' }">
<BowTarget :scores="arrows" :showLatestArrow="false" />
</view>
<view class="desc">
<text>{{ arrows.length }}</text>
<text>支箭</text>
<text>{{ arrows.reduce((a, b) => a + b.ring, 0) }}</text>
<text></text>
</view>
<ScorePanel
:rowCount="arrows.length === 12 ? 6 : 9"
:total="arrows.length"
:scores="arrows.map((a) => a.ring)"
:margin="arrows.length === 12 ? 4 : 1"
:fontSize="arrows.length === 12 ? 25 : 22"
/>
</view>
</Container>
</template>
<style scoped>
.container {
width: 100%;
flex-direction: column;
justify-content: center;
align-items: center;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
width: calc(100% - 20px);
padding: 10px;
}
.header > view:first-child {
display: flex;
align-items: center;
margin-left: 10px;
}
.header > view:first-child > view:last-child {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-left: 10px;
color: #fff;
}
.header > view:first-child > view:last-child > text:last-child {
font-size: 10px;
color: #fff9;
background-color: #5f51ff;
padding: 2px 5px;
border-radius: 10px;
margin-top: 5px;
}
.header > view:last-child > image {
width: 40px;
}
.desc {
color: #fff;
margin-bottom: 40px;
width: 100%;
text-align: center;
}
.desc > text:nth-child(2),
.desc > text:nth-child(4) {
color: #fed847;
}
</style>

View File

@@ -4,11 +4,7 @@ import Container from "@/components/Container.vue";
import Avatar from "@/components/Avatar.vue";
import BowData from "@/components/BowData.vue";
import ScrollList from "@/components/ScrollList.vue";
import {
getBattleListAPI,
getPractiseResultListAPI,
getPractiseAPI,
} from "@/apis";
import { getBattleListAPI, getPractiseResultListAPI } from "@/apis";
import { ref } from "vue";
@@ -16,8 +12,8 @@ const selectedIndex = ref(0);
const matchList = ref([]);
const battleList = ref([]);
const practiseList = ref([]);
const showBowData = ref(false);
const arrows = ref([]);
// const showBowData = ref(false);
// const arrows = ref([]);
const toMatchDetail = (id) => {
uni.navigateTo({
@@ -25,9 +21,9 @@ const toMatchDetail = (id) => {
});
};
const getPractiseDetail = async (id) => {
const result = await getPractiseAPI(id);
arrows.value = result.arrows;
showBowData.value = true;
uni.navigateTo({
url: `/pages/mine-bow-data?id=${id}`,
});
};
const onMatchLoading = async (page) => {
const result = await getBattleListAPI(page, 2);
@@ -175,11 +171,11 @@ const onPractiseLoading = async (page) => {
</view>
</ScrollList>
</view>
<BowData
<!-- <BowData
:arrows="arrows"
:show="showBowData"
:onClose="() => (showBowData = false)"
/>
/> -->
</Container>
</template>

View File

@@ -48,7 +48,7 @@ const subTitles = ["排位赛积分", "本周MVP次数", "本周十环次数"];
<text>{{ subTitles[selectedIndex] }}</text>
</view>
<view
v-for="(_, index) in new Array(10).fill(1)"
v-for="(_, index) in new Array(100).fill(1)"
:key="index"
class="rank-list-item"
:style="{

View File

@@ -36,6 +36,16 @@ const toMeleeMatchPage = (gameType, teamSize) => {
url: `/pages/melee-match?gameType=${gameType}&teamSize=${teamSize}`,
});
};
const toMyGrowthPage = () => {
uni.navigateTo({
url: "/pages/my-growth",
});
};
const toRankListPage = () => {
uni.navigateTo({
url: "/pages/rank-list",
});
};
</script>
<template>
@@ -101,7 +111,7 @@ const toMeleeMatchPage = (gameType, teamSize) => {
<view :style="{ width: '45%', backgroundColor: '#FFD947' }" />
</view>
</view>
<view>查看我的比赛记录</view>
<view @click="toMyGrowthPage">查看我的比赛记录</view>
</view>
<view class="ranking-data">
<view>
@@ -143,6 +153,7 @@ const toMeleeMatchPage = (gameType, teamSize) => {
<text>8850<text>分</text></text>
</view>
</view>
<view class="see-more" @click="toRankListPage">点击查看更多</view>
</view>
</Container>
</template>
@@ -160,6 +171,8 @@ const toMeleeMatchPage = (gameType, teamSize) => {
border: 1px solid #54431d;
border-radius: 10px;
margin: 0 15px;
}
.ranking-my-data {
margin-bottom: 15px;
}
.ranking-my-data {
@@ -318,4 +331,12 @@ const toMeleeMatchPage = (gameType, teamSize) => {
font-size: 13px;
margin-left: 3px;
}
.see-more {
color: #39a8ff;
font-size: 14px;
text-align: center;
width: 100%;
margin-top: 10px;
margin-bottom: 20px;
}
</style>

180
src/pages/team-bow-data.vue Normal file
View File

@@ -0,0 +1,180 @@
<script setup>
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
import BowTarget from "@/components/BowTarget.vue";
import Avatar from "@/components/Avatar.vue";
import { roundsName } from "@/constants";
import { getGameAPI } from "@/apis";
const selected = ref(0);
const redScores = ref([]);
const blueScores = ref([]);
const tabs = ref(["所有轮次"]);
const players = ref([]);
const allRoundsScore = ref({});
const data = ref({});
onLoad(async (options) => {
if (options.battleId) {
const result = await getGameAPI(options.battleId);
data.value = result;
if (result.winner === 0) {
players.value = [
...Object.values(result.redPlayers),
...Object.values(result.bluePlayers),
];
} else if (result.winner === 1) {
players.value = [
...Object.values(result.bluePlayers),
...Object.values(result.redPlayers),
];
}
Object.keys(result.roundsData).forEach((key) => {
tabs.value.push(`${roundsName[key]}`);
});
onClickTab(0);
}
});
const onClickTab = (index) => {
selected.value = index;
redScores.value = [];
blueScores.value = [];
const { bluePlayers, redPlayers, roundsData } = data.value;
if (index === 0) {
Object.keys(bluePlayers).forEach((p) => {
allRoundsScore.value[p] = [];
Object.values(roundsData).forEach((round) => {
allRoundsScore.value[p].push(
round[p].reduce((last, next) => last + next.ring, 0)
);
round[p].forEach((arrow) => {
blueScores.value.push(arrow);
});
});
});
Object.keys(redPlayers).forEach((p) => {
allRoundsScore.value[p] = [];
Object.values(roundsData).forEach((round) => {
allRoundsScore.value[p].push(
round[p].reduce((last, next) => last + next.ring, 0)
);
round[p].forEach((arrow) => {
redScores.value.push(arrow);
});
});
});
} else {
Object.keys(bluePlayers).forEach((p) => {
roundsData[index][p].forEach((arrow) => {
blueScores.value.push(arrow);
});
});
Object.keys(redPlayers).forEach((p) => {
roundsData[index][p].forEach((arrow) => {
redScores.value.push(arrow);
});
});
}
};
</script>
<template>
<Container title="1v1排位赛 - 靶纸">
<view class="container">
<view>
<view
v-for="(tab, index) in tabs"
:key="index"
@click="() => onClickTab(index)"
:class="selected === index ? 'selected-tab' : ''"
>
{{ tab }}
</view>
</view>
<view :style="{ margin: '20px 0' }">
<BowTarget
:scores="redScores"
:blueScores="blueScores"
:showLatestArrow="false"
/>
</view>
<view class="score-row" v-for="(player, index) in players" :key="index">
<Avatar
:src="player.avatar"
:borderColor="data.bluePlayers[player.playerId] ? 1 : 2"
/>
<view
v-if="selected === 0"
v-for="(ring, index) in allRoundsScore[player.playerId]"
:key="index"
class="score-item"
:style="{ width: '13vw', height: '13vw' }"
>
{{ ring }}
</view>
<view
v-if="selected > 0"
v-for="(score, index) in data.roundsData[selected][player.playerId]"
:key="index"
class="score-item"
:style="{ width: '13vw', height: '13vw' }"
>
{{ score.ring }}
</view>
</view>
</view>
</Container>
</template>
<style scoped>
.container {
width: 100%;
flex-direction: column;
justify-content: center;
align-items: center;
}
.container > view:nth-child(1) {
display: flex;
align-items: center;
justify-content: flex-start;
width: calc(100% - 20px);
color: #fff9;
padding: 10px;
overflow-x: auto;
}
.container > view:nth-child(1)::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
}
.container > view:nth-child(1) > view {
border: 1px solid #fff9;
border-radius: 20px;
padding: 7px 10px;
margin: 0 5px;
font-size: 14px;
flex: 0 0 auto;
}
.selected-tab {
background-color: #fed847;
border-color: #fed847 !important;
color: #000;
}
.score-row {
margin: 10px 20px;
display: flex;
align-items: center;
justify-content: flex-start;
}
.score-item {
background-image: url("../static/score-bg.png");
background-size: cover;
background-repeat: no-repeat;
background-position: center;
color: #fed847;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
margin-left: 10px;
}
</style>

View File

@@ -150,7 +150,7 @@ onUnmounted(() => {
:redTeam="redTeam"
:blueTeam="blueTeam"
/>
<Guide noBg v-if="!start && matching">
<Guide noBg v-if="!start && battleId">
<view :style="{ display: 'flex', justifyContent: 'space-between' }">
<view :style="{ display: 'flex', flexDirection: 'column' }">
<text :style="{ color: '#fed847' }">请预先射几箭测试</text>
@@ -159,7 +159,7 @@ onUnmounted(() => {
<BowPower :power="45" />
</view>
</Guide>
<ShootProgress v-if="start" :tips="tips" :seq="seq" :total="30" />
<ShootProgress v-if="start" :tips="tips" :seq="seq" :total="15" />
<PlayersRow
v-if="start"
:currentShooterId="currentShooterId"
@@ -167,7 +167,7 @@ onUnmounted(() => {
:redTeam="redTeam"
/>
<BowTarget
v-if="matching"
v-if="battleId"
:showE="start && user.id === currentShooterId"
:power="start ? power : 0"
:currentRound="currentRound"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
src/static/user-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

View File

@@ -33,7 +33,7 @@ export function renderScores(ctx, arrows = []) {
item.ring,
18,
"#fed847",
30 + (i % 9) * 30,
29.5 + (i % 9) * 30,
310 + Math.ceil((i + 1) / 9) * 30,
"center"
);
@@ -171,22 +171,22 @@ export function generateCanvasImage(canvasId, type, user, data) {
} else if (type == 3) {
titleImage = "../static/practise-two-title.png";
}
ctx.drawImage(titleImage, (width - 160) / 2 - 5, 160, 160, 40);
ctx.drawImage(titleImage, (width - 160) / 2, 160, 160, 40);
const subTitleWidth = ctx.measureText(subTitle).width;
renderText(
ctx,
subTitle,
18,
"#fff",
width / 2 - subTitleWidth - (type > 1 ? 15 : 13),
width / 2 - subTitleWidth - (type > 1 ? 15 : 9),
220
);
renderText(ctx, "共", 14, "#fff", 124, 300);
renderText(ctx, "共", 14, "#fff", 122, 300);
const totalRing = data.arrows.reduce((last, next) => last + next.ring, 0);
renderText(ctx, totalRing, 14, "#fed847", 150, 300, "center");
renderText(ctx, "环", 14, "#fff", 163, 300);
renderLine(ctx, 80);
renderLine(ctx, 187);
renderText(ctx, totalRing, 14, "#fed847", 148, 300, "center");
renderText(ctx, "环", 14, "#fff", 161, 300);
renderLine(ctx, 77);
renderLine(ctx, 185);
renderScores(ctx, data.arrows);
ctx.drawImage(
"../static/device-icon.png",

View File

@@ -5,9 +5,9 @@ let reconnectTimer = null;
// 重连配置
const RECONNECT_CONFIG = {
MAX_COUNT: 10, // 最大重连次数
MAX_COUNT: 999, // 最大重连次数
INITIAL_DELAY: 2000, // 初始重连延迟2秒
MAX_DELAY: 60000, // 最大重连延迟(1分钟
MAX_DELAY: 5000, // 最大重连延迟(5秒
};
/**