update:新增稳定训练
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user