update:新增稳定训练

This commit is contained in:
2026-08-26 15:23:02 +08:00
parent 45bc324f70
commit 96b64e4187
15 changed files with 645 additions and 25 deletions
+3 -1
View File
@@ -39,7 +39,9 @@ const getDisplayText = (arrow) => {
const isLowScore = (arrow) => {
if (!arrow) return false;
if (props.trainingType === "rhythm") return arrow.ok !== true;
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;
+32 -2
View File
@@ -255,6 +255,32 @@ const metricConfigs = {
deltaUnit: "次",
},
],
stability: [
{
label: "能量最高值",
valueKeys: ["maxEnergyPercent", "max_energy_percent"],
unit: "%",
deltaKeys: [
"deltaMaxEnergyPercent",
"delta_max_energy_percent",
],
deltaUnit: "%",
},
{
label: "达标箭数",
valueKeys: ["qualifiedArrows", "qualified_arrows"],
unit: "箭",
deltaKeys: ["deltaQualifiedArrows", "delta_qualified_arrows"],
deltaUnit: "箭",
},
{
label: "达标率",
valueKeys: ["qualifiedRate", "qualified_rate"],
unit: "%",
deltaKeys: ["deltaQualifiedRate", "delta_qualified_rate"],
deltaUnit: "%",
},
],
endurance: [
{
label: "完成箭数",
@@ -304,7 +330,8 @@ const metricConfigs = {
};
const resultRows = computed(() => {
const configs = metricConfigs[resultTrainingType.value] || metricConfigs.precision;
const configs =
metricConfigs[resultTrainingType.value] || metricConfigs.precision;
return configs.map((config) => {
const fallback = config.fallback ? config.fallback() : 0;
const value = readMetricNumber(config.valueKeys, fallback);
@@ -371,7 +398,10 @@ const calories = computed(
<view v-else class="stat-value">--</view>
</view>
</view>
<view v-if="resultTrainingType !== 'rhythm'" class="stat-row">
<view
v-if="!['rhythm', 'stability'].includes(resultTrainingType)"
class="stat-row"
>
<image class="stat-bg" src="https://static.shelingxingqiu.com/shootmini/static/training-difficulty-design/result-c-bg.png" mode="scaleToFill" />
<view class="stat-cell">
<text class="stat-label">消耗卡路里</text>
+112 -2
View File
@@ -73,6 +73,14 @@ const props = defineProps({
type: Number,
default: 0,
},
energyPercent: {
type: Number,
default: 0,
},
energyReqPercent: {
type: Number,
default: 0,
},
isVip: {
type: Boolean,
default: false,
@@ -137,6 +145,9 @@ let rhythmServerClockOffsetMs = 0;
let rhythmSyncGeneration = 0;
const isRhythmTraining = computed(() => props.trainingType === "rhythm");
const isStabilityTraining = computed(
() => props.trainingType === "stability"
);
const normalizePositiveInteger = (value) => {
const numberValue = Number(value);
@@ -176,6 +187,18 @@ const progressPercent = computed(() => {
return Math.max(0, Math.min(100, (remain.value / props.total) * 100));
});
const stabilityEnergyPercent = computed(() =>
Math.max(0, Math.min(100, Number(props.energyPercent) || 0))
);
const stabilityEnergyReqPercent = computed(() =>
Math.max(0, Math.min(100, Number(props.energyReqPercent) || 0))
);
const stabilityEnergyReached = computed(
() =>
stabilityEnergyReqPercent.value > 0 &&
stabilityEnergyPercent.value >= stabilityEnergyReqPercent.value
);
const rhythmMarkerPercent = computed(() => {
if (!validRhythmRoundTime.value) return 0;
return Math.max(
@@ -536,9 +559,34 @@ onBeforeUnmount(() => {
<template>
<view
v-if="show"
:class="isRhythmTraining ? 'rhythm-progress' : 'progress-card'"
:class="
isRhythmTraining
? 'rhythm-progress'
: isStabilityTraining
? 'stability-progress'
: 'progress-card'
"
>
<template v-if="isRhythmTraining">
<template v-if="isStabilityTraining">
<text class="stability-progress__time">{{ remain }}</text>
<view class="stability-progress__track">
<view
class="stability-progress__fill"
:class="{
'stability-progress__fill--reached': stabilityEnergyReached,
}"
:style="{ width: `${stabilityEnergyPercent}%` }"
/>
<view
class="stability-progress__marker"
:style="{ left: `${stabilityEnergyReqPercent}%` }"
/>
<text class="stability-progress__value">
{{ Math.round(stabilityEnergyPercent) }}%
</text>
</view>
</template>
<template v-else-if="isRhythmTraining">
<text class="rhythm-progress__title">{{ rhythmTitle }}</text>
<view class="rhythm-progress__track">
<view
@@ -758,6 +806,68 @@ onBeforeUnmount(() => {
text-align: center;
}
.stability-progress {
box-sizing: border-box;
margin: 32rpx 84rpx 0;
}
.stability-progress__time {
display: block;
margin-bottom: 20rpx;
color: #ffffff;
font-size: 34rpx;
font-weight: 500;
line-height: 48rpx;
text-align: center;
}
.stability-progress__track {
position: relative;
width: 100%;
height: 24rpx;
overflow: hidden;
border-radius: 18rpx;
background: #444444;
}
.stability-progress__fill {
position: absolute;
top: 0;
bottom: 0;
left: 0;
border-radius: 18rpx;
background: linear-gradient(90deg, #87f1df 0%, #5ba8e8 100%);
transition: width 240ms linear, background 240ms ease;
}
.stability-progress__fill--reached {
background: linear-gradient(90deg, #a5df62 0%, #61c787 100%);
}
.stability-progress__marker {
position: absolute;
top: 0;
bottom: 0;
z-index: 2;
width: 4rpx;
transform: translateX(-2rpx);
background: rgba(26, 24, 22, 0.92);
}
.stability-progress__value {
position: absolute;
inset: 0;
z-index: 3;
display: flex;
align-items: center;
justify-content: center;
color: #eefaff;
font-size: 18rpx;
line-height: 24rpx;
text-align: center;
pointer-events: none;
}
.rhythm-progress {
box-sizing: border-box;
margin: 32rpx 84rpx 0;
@@ -13,7 +13,20 @@ const props = defineProps({
});
const previewLines = computed(() => {
return props.lines.map((line) => String(line || "").trim()).filter(Boolean);
return props.lines
.map((line) => {
const rawParts = Array.isArray(line?.parts)
? line.parts
: [{ text: line }];
const parts = rawParts
.map((part) => ({
text: String(part?.text ?? part ?? "").trim(),
}))
.filter((part) => part.text);
return { parts };
})
.filter((line) => line.parts.length > 0);
});
</script>
@@ -27,13 +40,16 @@ const previewLines = computed(() => {
<view class="difficulty-preview__content">
<text class="difficulty-preview__title">{{ title }}</text>
<view class="difficulty-preview__copy">
<text
<view
v-for="(line, index) in previewLines"
:key="`${line}-${index}`"
:key="index"
class="difficulty-preview__line"
>
{{ line }}
</text>
<text
v-for="(part, partIndex) in line.parts"
:key="partIndex"
>{{ part.text }}</text>
</view>
</view>
</view>
</view>
@@ -86,6 +102,4 @@ const previewLines = computed(() => {
.difficulty-preview__line {
display: block;
}
</style>