185 lines
3.7 KiB
Vue
185 lines
3.7 KiB
Vue
<script setup>
|
|
import { ref, watch } from "vue";
|
|
const props = defineProps({
|
|
rowCount: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
total: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
arrows: {
|
|
type: Array,
|
|
default: () => [],
|
|
},
|
|
fontSize: {
|
|
type: Number,
|
|
default: 25,
|
|
},
|
|
completeEffect: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
trainingType: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
});
|
|
const items = ref(new Array(props.total).fill(9));
|
|
const bgImages = [
|
|
"../static/complete-light1.png",
|
|
"../static/complete-light2.png",
|
|
];
|
|
const getDisplayText = (arrow) => {
|
|
if (!arrow) return "-";
|
|
if (arrow.ringX) return "X";
|
|
return arrow.ring ?? "-";
|
|
};
|
|
|
|
const isLowScore = (arrow) => {
|
|
if (!arrow) return false;
|
|
if (["rhythm", "stability"].includes(props.trainingType)) {
|
|
return arrow.ok !== true;
|
|
}
|
|
if (arrow.ringX) return false;
|
|
const ring = Number(arrow.ring);
|
|
return Number.isFinite(ring) && ring < 6;
|
|
};
|
|
|
|
watch(
|
|
() => props.total,
|
|
(newValue) => {
|
|
items.value = new Array(newValue).fill(9);
|
|
}
|
|
);
|
|
</script>
|
|
<template>
|
|
<view class="container">
|
|
<template v-if="total > 0 && arrows.length === total && completeEffect">
|
|
<image
|
|
v-for="(image, index) in bgImages"
|
|
:key="image"
|
|
:src="image"
|
|
:class="[
|
|
'complete-light',
|
|
index === 0 ? 'complete-light--first' : 'complete-light--second',
|
|
]"
|
|
:style="{
|
|
width: `calc(${(100 / (rowCount + 2)) * rowCount}vw + ${
|
|
(100 / (total * 2)) * (rowCount * 2 + (total === 12 ? 8 : 24))
|
|
}px)`,
|
|
height: `calc(${(100 / (rowCount + 2)) * (total / rowCount)}vw + ${
|
|
(100 / (total * 2)) *
|
|
((total / rowCount) * 2 + (total === 12 ? 7 : 24))
|
|
}px)`,
|
|
top: `${total === 12 ? -2 : -3}vw`,
|
|
}"
|
|
/>
|
|
</template>
|
|
<view
|
|
v-for="(_, index) in items"
|
|
:key="index"
|
|
class="score-item"
|
|
>
|
|
<image
|
|
class="score-item-bg"
|
|
:src="
|
|
isLowScore(arrows[index])
|
|
? 'https://static.shelingxingqiu.com/shootmini/static/training-difficulty-design/block-gray.png'
|
|
: 'https://static.shelingxingqiu.com/shootmini/static/training-difficulty-design/block-gold.png'
|
|
"
|
|
/>
|
|
<text
|
|
class="score-value"
|
|
:class="{ 'score-value--low': isLowScore(arrows[index]) }"
|
|
>
|
|
{{ getDisplayText(arrows[index]) }}
|
|
</text>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
.container {
|
|
width: 100%;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
box-sizing: border-box;
|
|
position: relative;
|
|
padding: 30rpx 40rpx 0 40rpx;
|
|
}
|
|
.score-item {
|
|
position: relative;
|
|
width: 100rpx;
|
|
height: 56rpx;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
overflow: hidden;
|
|
margin-right: 14rpx;
|
|
margin-bottom: 14rpx;
|
|
}
|
|
|
|
.score-item:nth-child(6n) {
|
|
margin-right: 0;
|
|
}
|
|
|
|
.score-item-bg {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100rpx;
|
|
height: 56rpx;
|
|
}
|
|
|
|
.score-value {
|
|
position: relative;
|
|
z-index: 1;
|
|
min-width: 28rpx;
|
|
text-align: center;
|
|
font-size: 34rpx;
|
|
line-height: 1;
|
|
font-weight: 700;
|
|
font-style: italic;
|
|
color: #f6e3b2;
|
|
text-shadow: 0 2rpx 0 rgba(36, 36, 48, 0.5);
|
|
margin-left: -10rpx;
|
|
}
|
|
|
|
.score-value--low {
|
|
color: #cfcfcf;
|
|
text-shadow: 0 2rpx 0 rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
.complete-light {
|
|
position: absolute;
|
|
}
|
|
.complete-light--first {
|
|
animation: complete-light-first 400ms steps(1, end) infinite;
|
|
}
|
|
.complete-light--second {
|
|
animation: complete-light-second 400ms steps(1, end) infinite;
|
|
}
|
|
@keyframes complete-light-first {
|
|
0%,
|
|
49.9% {
|
|
opacity: 1;
|
|
}
|
|
50%,
|
|
100% {
|
|
opacity: 0;
|
|
}
|
|
}
|
|
@keyframes complete-light-second {
|
|
0%,
|
|
49.9% {
|
|
opacity: 0;
|
|
}
|
|
50%,
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
</style>
|