计分本细节更新

This commit is contained in:
kron
2025-11-04 11:54:22 +08:00
parent 1d086c83d4
commit 3498bc5027
8 changed files with 284 additions and 35 deletions

View File

@@ -510,3 +510,11 @@ export const laserCloseAPI = async () => {
export const getDeviceBatteryAPI = async () => { export const getDeviceBatteryAPI = async () => {
return request("GET", "/user/device/battery"); return request("GET", "/user/device/battery");
}; };
export const addNoteAPI = async (id, remark) => {
return request("POST", "/user/score/sheet/remark", { id, remark });
};
export const removePointRecord = async (id) => {
return request("DELETE", `/user/score/sheet/delete?id=${id}`);
};

View File

@@ -215,6 +215,8 @@ class AudioManager {
// 播放指定音频 // 播放指定音频
play(key) { play(key) {
const pages = getCurrentPages();
if (pages.length <= 1) return;
// 如果有正在播放的音频,先停止 // 如果有正在播放的音频,先停止
if (this.currentPlayingKey) { if (this.currentPlayingKey) {
this.stop(this.currentPlayingKey); this.stop(this.currentPlayingKey);
@@ -222,6 +224,7 @@ class AudioManager {
const audio = this.audioMap.get(key); const audio = this.audioMap.get(key);
if (audio) { if (audio) {
console.log("播放音频:", key);
audio.play(); audio.play();
this.currentPlayingKey = key; this.currentPlayingKey = key;
} else { } else {

View File

@@ -63,6 +63,30 @@ const onMeterChange = (e) => {
meter.value = e.detail.value; meter.value = e.detail.value;
props.onSelect(props.itemIndex, e.detail.value); props.onSelect(props.itemIndex, e.detail.value);
}; };
const sets = ref(null);
const onSetsChange = (e) => {
sets.value = e.detail.value;
if (!sets.value) return;
if (arrowAmount.value || groupArrows[secondSelectIndex.value]) {
props.onSelect(
props.itemIndex,
`${e.detail.value}/${
arrowAmount.value || groupArrows[secondSelectIndex.value]
}`
);
}
};
const arrowAmount = ref("");
const onArrowAmountChange = (e) => {
arrowAmount.value = e.detail.value;
if (!arrowAmount.value) return;
if (sets.value || selectedIndex.value !== -1) {
props.onSelect(
props.itemIndex,
`${sets.value || selectedIndex.value}/${e.detail.value}`
);
}
};
watch( watch(
() => props.value, () => props.value,
(newValue) => { (newValue) => {
@@ -219,7 +243,7 @@ onMounted(async () => {
<view v-if="itemIndex === 3"> <view v-if="itemIndex === 3">
<view class="amount-items"> <view class="amount-items">
<view <view
v-for="i in 12" v-for="i in 4"
:key="i" :key="i"
:style="{ :style="{
borderColor: selectedIndex === i ? '#fed847' : '#eeeeee', borderColor: selectedIndex === i ? '#fed847' : '#eeeeee',
@@ -229,6 +253,21 @@ onMounted(async () => {
<text>{{ i }}</text> <text>{{ i }}</text>
<text></text> <text></text>
</view> </view>
<view
:style="{
borderColor: selectedIndex === 5 ? '#fed847' : '#eeeeee',
}"
>
<input
v-model="sets"
placeholder="自定义"
type="number"
placeholder-style="color: #DDDDDD"
@focus="() => (selectedIndex = 5)"
@change="onSetsChange"
/>
<text></text>
</view>
</view> </view>
<view <view
:style="{ marginTop: '5px', marginBottom: '10px', color: '#999999' }" :style="{ marginTop: '5px', marginBottom: '10px', color: '#999999' }"
@@ -246,6 +285,21 @@ onMounted(async () => {
<text>{{ item }}</text> <text>{{ item }}</text>
<text></text> <text></text>
</view> </view>
<view
:style="{
borderColor: secondSelectIndex === 4 ? '#fed847' : '#eeeeee',
}"
>
<input
v-model="arrowAmount"
placeholder="自定义"
type="number"
placeholder-style="color: #DDDDDD"
@focus="() => (secondSelectIndex = 4)"
@change="onArrowAmountChange"
/>
<text></text>
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -352,4 +406,12 @@ onMounted(async () => {
width: 100%; width: 100%;
text-align: center; text-align: center;
} }
.amount-items > view:last-child {
grid-column: 1 / -1;
width: 100%;
}
.amount-items > view:last-child > input {
width: 85%;
text-align: center;
}
</style> </style>

View File

@@ -6,6 +6,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => {}, default: () => {},
}, },
longPress: {
type: Function,
default: () => {},
},
}); });
const bowOptions = ref({}); const bowOptions = ref({});
const targetOptions = ref({}); const targetOptions = ref({});
@@ -28,7 +32,7 @@ onMounted(() => {
</script> </script>
<template> <template>
<view class="container" @click="toDetailPage"> <view class="container" @click="toDetailPage" @longpress="longPress(props.data)">
<view> <view>
<view class="labels"> <view class="labels">
<view></view> <view></view>
@@ -54,9 +58,9 @@ onMounted(() => {
<view> <view>
<image src="../static/bow-target.png" mode="widthFix" /> <image src="../static/bow-target.png" mode="widthFix" />
<view class="arrow-amount"> <view class="arrow-amount">
<text></text> <text>{{ data.actualTotalRing }}</text>
<text>{{ data.arrows * data.groups }}</text> <text>/</text>
<text></text> <text>{{ data.totalRing }}</text>
</view> </view>
</view> </view>
</view> </view>
@@ -124,19 +128,18 @@ onMounted(() => {
.arrow-amount { .arrow-amount {
position: absolute; position: absolute;
background-color: #0009; background-color: #0009;
border-radius: 10px; border-radius: 12px;
color: #fffc; color: #fffc;
font-size: 12px; font-size: 24rpx;
line-height: 22px; line-height: 26px;
width: 60px; width: 64px;
display: flex; display: flex;
justify-content: center; justify-content: center;
top: calc(50% - 13px); top: calc(50% - 15px);
left: calc(50% - 30px); left: calc(50% - 32px);
} }
.arrow-amount > text:nth-child(2) { .arrow-amount > text:nth-child(1) {
font-size: 30rpx;
color: #fff; color: #fff;
font-size: 14px;
margin: 0 3px;
} }
</style> </style>

View File

@@ -61,6 +61,7 @@ const ringText = (ring) => {
{{ b && b.ring !== undefined ? b.ring : "" }} {{ b && b.ring !== undefined ? b.ring : "" }}
</text> </text>
</view> </view>
<text>环值</text>
</view> </view>
</template> </template>
@@ -70,9 +71,18 @@ const ringText = (ring) => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
position: relative;
}
.container > text {
position: absolute;
bottom: 2rpx;
left: 0;
font-size: 18rpx;
color: #999999;
} }
.container > view { .container > view {
padding: 0 10rpx; padding-left: 40rpx;
padding-right: 10rpx;
} }
.container > view:first-child { .container > view:first-child {
display: flex; display: flex;
@@ -93,14 +103,15 @@ const ringText = (ring) => {
transition: all 0.3s ease; transition: all 0.3s ease;
height: 0; height: 0;
} }
.container > view:last-child { .container > view:nth-child(2) {
display: grid; display: grid;
grid-template-columns: repeat(12, 1fr); grid-template-columns: repeat(12, 1fr);
border-top: 1rpx solid #333; border-top: 1rpx solid #333;
font-size: 22rpx; font-size: 22rpx;
color: #333333; color: #333333;
padding-top: 2rpx;
} }
.container > view:last-child > text { .container > view:nth-child(2) > text {
text-align: center; text-align: center;
} }
</style> </style>

View File

@@ -7,25 +7,40 @@ import ScreenHint2 from "@/components/ScreenHint2.vue";
import SButton from "@/components/SButton.vue"; import SButton from "@/components/SButton.vue";
import RingBarChart from "@/components/RingBarChart.vue"; import RingBarChart from "@/components/RingBarChart.vue";
import { getPointBookDetailAPI } from "@/apis"; import { getPointBookDetailAPI, addNoteAPI } from "@/apis";
const selectedIndex = ref(0); const selectedIndex = ref(0);
const showTip = ref(false); const showTip = ref(false);
const showTip2 = ref(false); const showTip2 = ref(false);
const showTip3 = ref(false);
const groups = ref([]); const groups = ref([]);
const data = ref({}); const data = ref({});
const targetId = ref(0); const targetId = ref(0);
const targetSrc = ref(""); const targetSrc = ref("");
const arrows = ref([]); const arrows = ref([]);
const notes = ref("");
const draftNotes = ref("");
const recordId = ref("");
const openTip = (index) => { const openTip = (index) => {
if (index === 1) showTip.value = true; if (index === 1) showTip.value = true;
else if (index === 2) showTip2.value = true; else if (index === 2) showTip2.value = true;
else if (index === 3) showTip3.value = true;
}; };
const closeTip = () => { const closeTip = () => {
showTip.value = false; showTip.value = false;
showTip2.value = false; showTip2.value = false;
showTip3.value = false;
};
const saveNote = async () => {
notes.value = draftNotes.value;
draftNotes.value = "";
showTip3.value = false;
if (recordId.value) {
await addNoteAPI(recordId.value, notes.value);
}
}; };
const onSelect = (index) => { const onSelect = (index) => {
@@ -54,6 +69,8 @@ const ringRates = computed(() => {
onLoad(async (options) => { onLoad(async (options) => {
if (options.id) { if (options.id) {
const result = await getPointBookDetailAPI(options.id || 164); const result = await getPointBookDetailAPI(options.id || 164);
recordId.value = result.id;
notes.value = result.remark || "";
const config = uni.getStorageSync("point-book-config"); const config = uni.getStorageSync("point-book-config");
config.targetOption.some((item) => { config.targetOption.some((item) => {
if (item.id === result.targetType) { if (item.id === result.targetType) {
@@ -132,6 +149,10 @@ onLoad(async (options) => {
<view>总环数</view> <view>总环数</view>
<text>{{ data.userTotalRing }}/{{ data.totalRing }}</text> <text>{{ data.userTotalRing }}/{{ data.totalRing }}</text>
</view> </view>
<button hover-class="none" @click="() => openTip(3)">
<image src="../static/edit.png" mode="widthFix" />
<text>备注</text>
</button>
</view> </view>
<view class="title-bar"> <view class="title-bar">
<view /> <view />
@@ -168,14 +189,21 @@ onLoad(async (options) => {
</view> </view>
<view class="ring-text-groups"> <view class="ring-text-groups">
<view v-for="(item, index) in groups" :key="index"> <view v-for="(item, index) in groups" :key="index">
<text v-if="selectedIndex === 0 && index !== 0">{{ <view v-if="selectedIndex === 0 && index !== 0">
`${index}` <text>{{ index }}</text>
}}</text> <text>{{
item.list.reduce((acc, cur) => acc + cur.ring, 0)
}}</text>
<text></text>
</view>
<view <view
v-if=" v-if="
(selectedIndex === 0 && index !== 0) || (selectedIndex === 0 && index !== 0) ||
(selectedIndex !== 0 && index === selectedIndex) (selectedIndex !== 0 && index === selectedIndex)
" "
:style="{
marginLeft: selectedIndex === 0 && index !== 0 ? '20rpx' : '0',
}"
> >
<text <text
v-for="(arrow, index2) in item.list" v-for="(arrow, index2) in item.list"
@@ -186,11 +214,7 @@ onLoad(async (options) => {
}" }"
> >
{{ {{
arrow.ring === 0 arrow.ring === 0 ? "X" : arrow.ring === -1 ? "M" : arrow.ring
? "X"
: arrow.ring === -1
? "M"
: arrow.ring + "环"
}} }}
</text> </text>
</view> </view>
@@ -200,7 +224,10 @@ onLoad(async (options) => {
<SButton :onClick="goBack" :rounded="50">关闭</SButton> <SButton :onClick="goBack" :rounded="50">关闭</SButton>
</view> </view>
</view> </view>
<ScreenHint2 :show="showTip || showTip2" :onClose="closeTip"> <ScreenHint2
:show="showTip || showTip2 || showTip3"
:onClose="!notes && showTip3 ? null : closeTip"
>
<view class="tip-content"> <view class="tip-content">
<block v-if="showTip"> <block v-if="showTip">
<text>落点稳定性说明</text> <text>落点稳定性说明</text>
@@ -212,6 +239,22 @@ onLoad(async (options) => {
<text>落点分布说明</text> <text>落点分布说明</text>
<text>展示用户某次练习中射箭的点位</text> <text>展示用户某次练习中射箭的点位</text>
</block> </block>
<block v-if="showTip3">
<text>笔记</text>
<text v-if="notes">{{ notes }}</text>
<textarea
v-if="!notes"
v-model="draftNotes"
rows="4"
class="notes-input"
placeholder="写下本次射箭的补充信息与心得"
placeholder-style="color: #ccc;"
/>
<view v-if="!notes">
<button hover-class="none" @click="showTip3 = false">取消</button>
<button hover-class="none" @click="saveNote">保存备注</button>
</view>
</block>
</view> </view>
</ScreenHint2> </ScreenHint2>
</view> </view>
@@ -265,7 +308,8 @@ onLoad(async (options) => {
column-gap: 3vw; column-gap: 3vw;
margin: 10rpx 30rpx; margin: 10rpx 30rpx;
} }
.detail-data > view { .detail-data > view,
.detail-data > button {
border-radius: 10px; border-radius: 10px;
background-color: #fff; background-color: #fff;
margin-bottom: 20rpx; margin-bottom: 20rpx;
@@ -283,6 +327,18 @@ onLoad(async (options) => {
font-weight: 500; font-weight: 500;
color: #000; 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 { .question-mark {
width: 28rpx; width: 28rpx;
height: 28rpx; height: 28rpx;
@@ -326,6 +382,33 @@ onLoad(async (options) => {
margin-top: 20px; margin-top: 20px;
opacity: 0.8; opacity: 0.8;
} }
.tip-content > view {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.tip-content > view > input {
width: 80%;
height: 44px;
border-radius: 22px;
border: 1px solid #eeeeee;
padding: 0 12px;
font-size: 14px;
color: #000;
}
.tip-content > view > button {
width: 48%;
background: linear-gradient(180deg, #fbfbfb 0%, #f5f5f5 100%);
border-radius: 22px;
border: 1px solid #eeeeee;
padding: 12px 0;
font-size: 14px;
color: #000;
}
.tip-content > view > button:last-child {
background: #fed847;
}
.ring-text-groups { .ring-text-groups {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -338,22 +421,43 @@ onLoad(async (options) => {
display: flex; display: flex;
justify-content: center; justify-content: center;
} }
.ring-text-groups > view > text { .ring-text-groups > view > view:first-child:nth-last-child(2) {
width: 82rpx; width: 82rpx;
text-align: center; text-align: center;
font-size: 27rpx; font-size: 20rpx;
display: flex;
color: #999;
} }
.ring-text-groups > view > view { .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;
color: #666;
margin-right: 6rpx;
}
.ring-text-groups > view > view:last-child {
flex: 1; flex: 1;
display: grid; display: grid;
grid-template-columns: repeat(6, auto); grid-template-columns: repeat(6, auto);
grid-gap: 10rpx; grid-gap: 10rpx;
margin-bottom: 30rpx; margin-bottom: 30rpx;
margin-left: 20rpx;
} }
.ring-text-groups > view > view > text { .ring-text-groups > view > view:last-child > text {
width: 1fr; width: 1fr;
text-align: center; text-align: center;
margin-bottom: 10rpx; margin-bottom: 10rpx;
} }
.notes-input {
width: calc(100% - 40rpx);
margin: 25rpx 0;
border: 1px solid #eee;
border-radius: 5px;
padding: 5px;
color: #000;
padding: 20rpx;
}
</style> </style>

View File

@@ -5,14 +5,17 @@ import SModal from "@/components/SModal.vue";
import EditOption from "@/components/EditOption.vue"; import EditOption from "@/components/EditOption.vue";
import PointRecord from "@/components/PointRecord.vue"; import PointRecord from "@/components/PointRecord.vue";
import ScrollList from "@/components/ScrollList.vue"; import ScrollList from "@/components/ScrollList.vue";
import { getPointBookListAPI } from "@/apis"; import ScreenHint2 from "@/components/ScreenHint2.vue";
import { getPointBookListAPI, removePointRecord } from "@/apis";
const showTip = ref(false);
const bowType = ref({}); const bowType = ref({});
const distance = ref(0); const distance = ref(0);
const bowtargetType = ref({}); const bowtargetType = ref({});
const showModal = ref(false); const showModal = ref(false);
const selectorIndex = ref(0); const selectorIndex = ref(0);
const list = ref([]); const list = ref([]);
const removeId = ref("");
const onListLoading = async (page) => { const onListLoading = async (page) => {
const result = await getPointBookListAPI( const result = await getPointBookListAPI(
@@ -34,6 +37,22 @@ const openSelector = (index) => {
showModal.value = true; showModal.value = true;
}; };
const onLongPress = (item) => {
removeId.value = item.id;
showTip.value = true;
};
const confirmRemove = async () => {
try {
showTip.value = false;
await removePointRecord(removeId.value);
list.value = list.value.filter((it) => it.id !== removeId.value);
uni.showToast({ title: "已删除", icon: "none" });
} catch (e) {
uni.showToast({ title: "删除失败,请重试", icon: "none" });
}
};
const onSelectOption = (itemIndex, value) => { const onSelectOption = (itemIndex, value) => {
if (itemIndex === 0) { if (itemIndex === 0) {
bowType.value = value.name === bowType.value.name ? {} : value; bowType.value = value.name === bowType.value.name ? {} : value;
@@ -78,7 +97,7 @@ const onSelectOption = (itemIndex, value) => {
<view class="point-records"> <view class="point-records">
<ScrollList :onLoading="onListLoading"> <ScrollList :onLoading="onListLoading">
<view v-for="(item, index) in list" :key="index"> <view v-for="(item, index) in list" :key="index">
<PointRecord :data="item" /> <PointRecord :data="item" :longPress="onLongPress" />
</view> </view>
<view class="no-data" v-if="list.length === 0">暂无数据</view> <view class="no-data" v-if="list.length === 0">暂无数据</view>
</ScrollList> </ScrollList>
@@ -119,6 +138,15 @@ const onSelectOption = (itemIndex, value) => {
/> />
</view> </view>
</SModal> </SModal>
<ScreenHint2 :show="showTip">
<view class="tip-content">
<text>确认删除该记录吗</text>
<view>
<button hover-class="none" @click="showTip = false">取消</button>
<button hover-class="none" @click="confirmRemove">确认</button>
</view>
</view>
</ScreenHint2>
</view> </view>
</Container> </Container>
</template> </template>
@@ -186,4 +214,34 @@ const onSelectOption = (itemIndex, value) => {
color: #999999; color: #999999;
font-size: 14px; font-size: 14px;
} }
.tip-content {
width: 100%;
padding: 25px;
display: flex;
flex-direction: column;
color: #000;
}
.tip-content > text {
width: 100%;
text-align: center;
font-size: 14px;
margin-top: 5px;
}
.tip-content > view {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.tip-content > view > button {
width: 48%;
background: linear-gradient(180deg, #fbfbfb 0%, #f5f5f5 100%);
border-radius: 22px;
border: 1px solid #eeeeee;
padding: 12px 0;
font-size: 14px;
color: #000;
}
.tip-content > view > button:last-child {
background: #fed847;
}
</style> </style>

BIN
src/static/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B