Files
shoot-miniprograms/src/pages/point-book-detail-share.vue
2025-11-05 17:53:48 +08:00

435 lines
10 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, computed } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import SButton from "@/components/SButton.vue";
import BowTargetEdit from "@/components/BowTargetEdit.vue";
import ScreenHint2 from "@/components/ScreenHint2.vue";
import RingBarChart from "@/components/RingBarChart.vue";
import { getPointBookDetailAPI, getPointBookConfigAPI } from "@/apis";
const selectedIndex = ref(0);
const showTip = ref(false);
const showTip2 = ref(false);
const data = ref({});
const targetId = ref(0);
const targetSrc = ref("");
const arrows = ref([]);
const record = ref({
groups: [],
user: {},
});
const bowConfig = ref({});
const paddingTop = computed(() => {
const menuBtnInfo = uni.getMenuButtonBoundingClientRect();
return menuBtnInfo.top - 9 - 9;
});
const openTip = (index) => {
if (index === 1) showTip.value = true;
else if (index === 2) showTip2.value = true;
};
const closeTip = () => {
showTip.value = false;
showTip2.value = false;
};
const goBack = () => {
const pages = getCurrentPages();
if (pages.length > 1) {
const currentPage = pages[pages.length - 2];
uni.navigateBack({
delta: currentPage.route === "pages/point-book" ? 1 : 2,
});
} else {
uni.redirectTo({
url: "/pages/index",
});
}
};
const goHome = () => {
uni.redirectTo({
url: "/pages/point-book",
});
};
const ringRates = computed(() => {
const rates = new Array(12).fill(0);
arrows.value.forEach((item) => {
if (item.ring === -1) rates[11] += 1;
else rates[item.ring] += 1;
});
return rates.map((r) => r / arrows.value.length);
});
onLoad(async (options) => {
if (options.id) {
const result = await getPointBookDetailAPI(options.id || 183);
record.value = result;
const config = await getPointBookConfigAPI();
bowConfig.value = config;
config.targetOption.some((item) => {
if (item.id === result.targetType) {
targetId.value = item.id;
targetSrc.value = item.icon;
}
});
if (result.groups) {
data.value = result.groups[0];
arrows.value = result.groups[0].list;
}
}
});
const bowOptionName = computed(() => {
if (bowConfig.value.bowOption && record.value.bowType) {
const data = bowConfig.value.bowOption.find(
(b) => b.id === record.value.bowType
);
if (data) return data.name || "";
}
return "";
});
const targetTypeName = computed(() => {
if (bowConfig.value.targetOption && record.value.targetType) {
const data = bowConfig.value.targetOption.find(
(b) => b.id === record.value.targetType
);
if (data) return data.name || "";
}
return "";
});
</script>
<template>
<view class="container" :style="{ paddingTop: paddingTop + 'px' }">
<image
src="../static/app-bg5.png"
class="bg-image"
mode="aspectFill"
:style="{ height: paddingTop + 60 + 'px' }"
/>
<view class="header">
<image
:src="record.user.avatar || '../static/user-icon.png'"
mode="widthFix"
class="avatar"
/>
<view>
<text>{{ record.user.name }}</text>
<view class="point-book-info">
<text v-if="bowOptionName">{{ bowOptionName }}</text>
<text>{{ record.distance }} </text>
<text v-if="targetTypeName">{{ targetTypeName }}</text>
</view>
</view>
</view>
<view class="detail-data">
<view>
<view
:style="{ display: 'flex', alignItems: 'center' }"
@click="() => openTip(1)"
>
<text>落点稳定性</text>
<image
src="../static/s-question-mark.png"
mode="widthFix"
class="question-mark"
/>
</view>
<text>{{ Number((data.stability || 0).toFixed(2)) }}</text>
</view>
<view>
<view>黄心率</view>
<text>{{ Number((data.yellowRate * 100).toFixed(2)) }}%</text>
</view>
<view>
<view>10环数</view>
<text>{{ data.tenRings }}</text>
</view>
<view>
<view>平均环数</view>
<text>{{ Number((data.averageRing || 0).toFixed(2)) }}</text>
</view>
<view>
<view>总环数</view>
<text>{{ data.userTotalRing }}/{{ data.totalRing }}</text>
</view>
</view>
<view class="title-bar">
<view />
<text>落点分布</text>
<!-- <button hover-class="none" @click="() => openTip(2)">
<image
src="../static/s-question-mark.png"
mode="widthFix"
class="question-mark"
/>
</button> -->
</view>
<view :style="{ transform: 'translateY(-45rpx)' }">
<BowTargetEdit
:id="targetId"
:src="targetSrc"
:arrows="arrows.filter((item) => item.x && item.y)"
/>
</view>
<view :style="{ transform: 'translateY(-60rpx)' }">
<!-- <view class="title-bar">
<view />
<text>环值分布</text>
</view> -->
<view :style="{ padding: '0 30rpx' }">
<RingBarChart :data="ringRates" />
</view>
<!-- <view class="title-bar" :style="{ marginTop: '30rpx' }">
<view />
<text>{{
selectedIndex === 0 ? "每组环数" : `${selectedIndex}组环数`
}}</text>
</view> -->
<view class="ring-text-groups">
<view v-for="(item, index) in record.groups" :key="index">
<view v-if="selectedIndex === 0 && index !== 0">
<text>{{ index }}</text>
<text>{{ item.list.reduce((acc, cur) => acc + cur.ring, 0) }}</text>
<text></text>
</view>
<view
v-if="
(selectedIndex === 0 && index !== 0) ||
(selectedIndex !== 0 && index === selectedIndex)
"
:style="{
marginLeft: selectedIndex === 0 && index !== 0 ? '20rpx' : '0',
}"
>
<text
v-for="(arrow, index2) in item.list"
:key="index2"
:style="{
color:
arrow.ring === 0 || arrow.ring === 10 ? '#FFA118' : '#666',
}"
>
{{
arrow.ring === 0 ? "X" : arrow.ring === -1 ? "M" : arrow.ring
}}
</text>
</view>
</view>
</view>
<SButton :onClick="goHome" :rounded="40">开启我的弓箭记录</SButton>
</view>
<ScreenHint2 :show="showTip || showTip2" :onClose="closeTip">
<view class="tip-content">
<block v-if="showTip">
<text>落点稳定性说明</text>
<text
>通过计算每支箭与其他箭的平均距离衡量射箭的稳定性,数字越小则说明射箭越稳定。该数据只能在用户标记落点的情况下生成。</text
>
</block>
<block v-if="showTip2">
<text>落点分布说明</text>
<text>展示用户某次练习中射箭的点位</text>
</block>
</view>
</ScreenHint2>
</view>
</template>
<style scoped>
.container {
width: 100vw;
height: 100vh;
background: #f5f5f5;
position: relative;
overflow: auto;
}
.header {
overflow: hidden;
display: flex;
align-items: center;
position: relative;
}
.header > image {
border-radius: 50%;
width: 90rpx;
height: 90rpx;
border: 2rpx solid #000;
margin: 0 25rpx;
}
.header > view {
display: flex;
flex-direction: column;
align-items: flex-start;
}
.header > view > text {
color: #000;
margin-bottom: 7rpx;
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.header {
width: 100%;
height: 60px;
}
.detail-data {
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 3vw;
margin: 10rpx 30rpx;
margin-top: 20rpx;
}
.detail-data > view,
.detail-data > button {
border-radius: 10px;
background-color: #fff;
margin-bottom: 20rpx;
padding: 15rpx 24rpx;
}
.detail-data > view > view {
font-size: 13px;
color: #999;
margin-bottom: 6rpx;
}
.detail-data > view > view > text {
word-break: keep-all;
}
.detail-data > view > text {
font-weight: 500;
color: #000;
}
.detail-data > button {
display: flex;
align-items: center;
font-size: 26rpx;
color: #999999;
}
.detail-data > button > image {
width: 28rpx;
height: 28rpx;
margin-right: 10rpx;
margin-left: 20rpx;
}
.question-mark {
width: 28rpx;
height: 28rpx;
margin-left: 3px;
}
.title-bar {
width: 100%;
display: flex;
align-items: center;
font-size: 13px;
color: #999;
position: relative;
z-index: 10;
}
.title-bar > view:first-child {
width: 8rpx;
height: 28rpx;
border-radius: 10px;
background-color: #fed847;
margin-right: 7px;
margin-left: 15px;
}
.title-bar > button {
height: 34rpx;
}
.tip-content {
width: 100%;
padding: 50rpx 44rpx;
display: flex;
flex-direction: column;
color: #000;
}
.tip-content > text {
width: 100%;
}
.tip-content > text:first-child {
text-align: center;
}
.tip-content > text:last-child {
font-size: 13px;
margin-top: 20px;
opacity: 0.8;
}
.ring-text-groups {
display: flex;
flex-direction: column;
padding: 20rpx;
padding-top: 40rpx;
font-size: 24rpx;
color: #999999;
}
.ring-text-groups > view {
display: flex;
justify-content: center;
}
.ring-text-groups > view > view:first-child:nth-last-child(2) {
margin-top: 10rpx;
margin-left: 30rpx;
width: 90rpx;
text-align: center;
justify-content: flex-end;
font-size: 20rpx;
display: flex;
color: #999;
}
.ring-text-groups > view > view:first-child:nth-last-child(2) > text {
line-height: 30rpx;
}
.ring-text-groups
> view
> view:first-child:nth-last-child(2)
> text:nth-child(2) {
font-size: 40rpx;
/* min-width: 45rpx; */
color: #666;
margin-right: 6rpx;
margin-top: -5rpx;
}
.ring-text-groups > view > view:last-child {
width: 80%;
display: flex;
flex-wrap: wrap;
margin-bottom: 30rpx;
transform: translateX(20rpx);
}
.ring-text-groups > view > view:last-child > text {
width: 16.6%;
text-align: center;
margin-bottom: 10rpx;
font-weight: 500;
font-size: 26rpx;
}
.notes-input {
width: calc(100% - 40rpx);
margin: 25rpx 0;
border: 1px solid #eee;
border-radius: 5px;
color: #000;
padding: 20rpx;
}
.point-book-info {
color: #333;
display: flex;
justify-content: center;
}
.point-book-info > text {
border-radius: 6px;
background-color: #fff;
font-size: 10px;
padding: 5px 10px;
margin-right: 5px;
}
</style>