update:代码备份
This commit is contained in:
116
src/pages/training/components/BowData.vue
Normal file
116
src/pages/training/components/BowData.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<script setup>
|
||||
import AppBackground from "@/components/AppBackground.vue";
|
||||
import Avatar from "@/components/Avatar.vue";
|
||||
import BowTarget from "@./BowTarget.vue";
|
||||
import ScorePanel from "./ScorePanel.vue";
|
||||
import useStore from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
const store = useStore();
|
||||
const { user } = storeToRefs(store);
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
onClose: {
|
||||
type: Function,
|
||||
default: () => {},
|
||||
},
|
||||
arrows: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container" :style="{ display: show ? 'flex' : 'none' }">
|
||||
<AppBackground :type="1" />
|
||||
<view class="header">
|
||||
<view>
|
||||
<Avatar :src="user.avatar" :rankLvl="user.rankLvl" :size="45" />
|
||||
<view>
|
||||
<text>{{ user.nickName }}</text>
|
||||
<text>{{ user.lvlName }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view @click="onClose">
|
||||
<image src="../static/close-white.png" mode="widthFix" />
|
||||
</view>
|
||||
</view>
|
||||
<view :style="{ width: '100%', marginBottom: '20px' }">
|
||||
<BowTarget :scores="arrows" />
|
||||
</view>
|
||||
<view class="desc">
|
||||
<text>{{ arrows.length }}</text>
|
||||
<text>支箭,共</text>
|
||||
<text>{{ arrows.reduce((a, b) => a + (b.ring || 0), 0) }}</text>
|
||||
<text>环</text>
|
||||
</view>
|
||||
<ScorePanel
|
||||
:completeEffect="false"
|
||||
:rowCount="total === 12 ? 6 : 9"
|
||||
:total="total"
|
||||
:arrows="arrows"
|
||||
:margin="total === 12 ? 4 : 1"
|
||||
:fontSize="total === 12 ? 25 : 22"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #232323;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
}
|
||||
.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;
|
||||
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;
|
||||
}
|
||||
.desc > text:nth-child(2),
|
||||
.desc > text:nth-child(4) {
|
||||
color: #fed847;
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,6 @@
|
||||
<script setup>
|
||||
import {
|
||||
computed,
|
||||
getCurrentInstance,
|
||||
nextTick,
|
||||
onBeforeUnmount,
|
||||
onMounted,
|
||||
ref,
|
||||
@@ -17,7 +15,6 @@ import useStore from "@/store";
|
||||
import { storeToRefs } from "pinia";
|
||||
const store = useStore();
|
||||
const { user, device } = storeToRefs(store);
|
||||
const instance = getCurrentInstance();
|
||||
|
||||
const props = defineProps({
|
||||
currentRound: {
|
||||
@@ -278,122 +275,6 @@ const showHighlightCanvas = computed(() => {
|
||||
return props.totalRound > 0 && currentHighlightAreas.value.length > 0;
|
||||
});
|
||||
|
||||
const targetImageNaturalSize = ref({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
const targetLayerRect = ref({
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 0,
|
||||
height: 0,
|
||||
ready: false,
|
||||
});
|
||||
|
||||
const targetHighlightLayerStyle = computed(() => ({
|
||||
left: `${targetLayerRect.value.left}px`,
|
||||
top: `${targetLayerRect.value.top}px`,
|
||||
width: `${targetLayerRect.value.width}px`,
|
||||
height: `${targetLayerRect.value.height}px`,
|
||||
}));
|
||||
|
||||
const getRectNumber = (value, fallback = 0) => {
|
||||
const numberValue = Number(value);
|
||||
return Number.isFinite(numberValue) ? numberValue : fallback;
|
||||
};
|
||||
|
||||
const getImageContentRect = (imageRect) => {
|
||||
const naturalWidth = getRectNumber(targetImageNaturalSize.value.width);
|
||||
const naturalHeight = getRectNumber(targetImageNaturalSize.value.height);
|
||||
const imageWidth = getRectNumber(imageRect?.width);
|
||||
const imageHeight = getRectNumber(imageRect?.height);
|
||||
|
||||
if (naturalWidth <= 0 || naturalHeight <= 0 || imageWidth <= 0 || imageHeight <= 0) {
|
||||
return imageRect;
|
||||
}
|
||||
|
||||
const naturalRatio = naturalWidth / naturalHeight;
|
||||
const boxRatio = imageWidth / imageHeight;
|
||||
|
||||
if (naturalRatio > boxRatio) {
|
||||
const contentHeight = imageWidth / naturalRatio;
|
||||
return {
|
||||
left: imageRect.left,
|
||||
top: imageRect.top + (imageHeight - contentHeight) / 2,
|
||||
width: imageWidth,
|
||||
height: contentHeight,
|
||||
};
|
||||
}
|
||||
|
||||
const contentWidth = imageHeight * naturalRatio;
|
||||
return {
|
||||
left: imageRect.left + (imageWidth - contentWidth) / 2,
|
||||
top: imageRect.top,
|
||||
width: contentWidth,
|
||||
height: imageHeight,
|
||||
};
|
||||
};
|
||||
|
||||
const updateTargetLayerRect = async () => {
|
||||
await nextTick();
|
||||
|
||||
const query = uni.createSelectorQuery().in(instance?.proxy);
|
||||
query.select(".target").boundingClientRect();
|
||||
query.select(".target-image").boundingClientRect();
|
||||
query.exec((rects = []) => {
|
||||
const stageRect = rects[0];
|
||||
const imageRect = rects[1];
|
||||
|
||||
if (!stageRect || !imageRect || !imageRect.width || !imageRect.height) {
|
||||
targetLayerRect.value = {
|
||||
...targetLayerRect.value,
|
||||
ready: false,
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const contentRect = getImageContentRect(imageRect);
|
||||
const width = Math.round(getRectNumber(contentRect?.width));
|
||||
const height = Math.round(getRectNumber(contentRect?.height));
|
||||
|
||||
targetLayerRect.value = {
|
||||
left: getRectNumber(contentRect?.left) - getRectNumber(stageRect.left),
|
||||
top: getRectNumber(contentRect?.top) - getRectNumber(stageRect.top),
|
||||
width,
|
||||
height,
|
||||
ready: width > 0 && height > 0,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const onTargetImageLoad = (event) => {
|
||||
const width = getRectNumber(event?.detail?.width);
|
||||
const height = getRectNumber(event?.detail?.height);
|
||||
|
||||
if (width > 0 && height > 0) {
|
||||
targetImageNaturalSize.value = {
|
||||
width,
|
||||
height,
|
||||
};
|
||||
}
|
||||
|
||||
updateTargetLayerRect();
|
||||
};
|
||||
|
||||
const onWindowResize = () => {
|
||||
updateTargetLayerRect();
|
||||
};
|
||||
|
||||
watch(
|
||||
showHighlightCanvas,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
updateTargetLayerRect();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
async function onReceiveMessage(message) {
|
||||
if (Array.isArray(message)) return;
|
||||
if (message.type === MESSAGETYPESV2.ShootResult && message.shootData) {
|
||||
@@ -418,10 +299,6 @@ async function onReceiveMessage(message) {
|
||||
|
||||
onMounted(() => {
|
||||
uni.$on("socket-inbox", onReceiveMessage);
|
||||
setTimeout(updateTargetLayerRect, 30);
|
||||
if (uni.onWindowResize) {
|
||||
uni.onWindowResize(onWindowResize);
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -434,9 +311,6 @@ onBeforeUnmount(() => {
|
||||
dirTimer.value = null;
|
||||
}
|
||||
uni.$off("socket-inbox", onReceiveMessage);
|
||||
if (uni.offWindowResize) {
|
||||
uni.offWindowResize(onWindowResize);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -454,14 +328,10 @@ onBeforeUnmount(() => {
|
||||
class="target-image"
|
||||
src="../../../static/bow-target.png"
|
||||
mode="aspectFit"
|
||||
@load="onTargetImageLoad"
|
||||
/>
|
||||
<TargetCanvas
|
||||
v-if="showHighlightCanvas && targetLayerRect.ready"
|
||||
v-if="showHighlightCanvas"
|
||||
class="target-highlight-layer"
|
||||
:style="targetHighlightLayerStyle"
|
||||
:canvasWidth="targetLayerRect.width"
|
||||
:canvasHeight="targetLayerRect.height"
|
||||
:coordinateRadius="coordinateRadius"
|
||||
:showCrosshair="false"
|
||||
:showQuadrantLabels="false"
|
||||
@@ -573,6 +443,10 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
.target-highlight-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup>
|
||||
import { ref, onMounted, computed } from "vue";
|
||||
import ScreenHint from "@/components/ScreenHint.vue";
|
||||
import BowData from "@/components/BowData.vue";
|
||||
import ScreenHint from "./ScreenHint.vue";
|
||||
import BowData from "./BowData.vue";
|
||||
import UserUpgrade from "@/components/UserUpgrade.vue";
|
||||
import { directionAdjusts } from "@/constants";
|
||||
import useStore from "@/store";
|
||||
|
||||
89
src/pages/training/components/ScreenHint.vue
Normal file
89
src/pages/training/components/ScreenHint.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<script setup>
|
||||
import IconButton from "./IconButton.vue";
|
||||
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
onClose: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
mode: {
|
||||
type: String,
|
||||
default: "normal",
|
||||
},
|
||||
});
|
||||
const getContentHeight = () => {
|
||||
if (props.mode === "tall") return "50vw";
|
||||
if (props.mode === "square") return "74vw";
|
||||
return "36vw";
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container" :style="{ display: show ? 'flex' : 'none' }">
|
||||
<view class="scale-in" :style="{ height: getContentHeight() }">
|
||||
<image
|
||||
v-if="mode === 'normal'"
|
||||
src="../static/screen-hint-bg.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<image
|
||||
v-if="mode === 'tall'"
|
||||
src="../static/coach-comment.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<image
|
||||
v-if="mode === 'square'"
|
||||
src="../static/prompt-bg-square.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<image
|
||||
v-if="mode === 'small'"
|
||||
src="../static/finish-frame.png"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<slot />
|
||||
</view>
|
||||
<IconButton
|
||||
v-if="!!onClose"
|
||||
src="../static/close-gold-outline.png"
|
||||
:width="30"
|
||||
:onClick="onClose"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
}
|
||||
.container > view:first-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
width: 70vw;
|
||||
color: #fff;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.container > view:first-child > image {
|
||||
position: absolute;
|
||||
width: 80vw;
|
||||
left: -7%;
|
||||
bottom: -18vw;
|
||||
z-index: -1;
|
||||
transform: translateY(-75px);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user