Files
gym-manage/gym-manage-uniapp/pages/memberInfo/bodyTestMeasuring.vue
T
2026-06-11 08:33:19 +08:00

170 lines
6.1 KiB
Vue

<template>
<view class="scroll-container theme-light">
<view class="bt-page">
<MemberInfoSubNav title="测量中" @back="onCancel" />
<view class="bt-page__body">
<view class="bt-card">
<view class="bt-measure">
<view class="bt-measure__ring-wrap">
<view class="bt-measure__ring-bg"></view>
<view
class="bt-measure__ring-fill"
:style="{ transform: `rotate(${ringRotation}deg)` }"
></view>
<view class="bt-measure__center">
<text class="bt-measure__percent">{{ progress }}%</text>
<text class="bt-measure__hint">{{ phaseHint }}</text>
</view>
</view>
<text class="bt-card__desc">{{ statusText }}</text>
</view>
</view>
<view class="bt-card">
<text class="bt-card__title">实时数据</text>
<view class="bt-measure__live">
<view
v-for="item in liveDisplay"
:key="item.key"
class="bt-measure__live-item"
>
<text class="bt-measure__live-value">{{ item.value }}</text>
<text class="bt-measure__live-label">{{ item.label }}</text>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import MemberInfoSubNav from '@/components/memberInfo/MemberInfoSubNav.vue'
import { PAGE, navigateToPage, goBackOrTab } from '@/common/constants/routes.js'
import {
loadMemberStore,
persistMemberStore
} from '@/common/memberInfo/store.js'
import {
interpolateMeasuringMetrics,
saveSimulatedBodyTestRecord
} from '@/common/memberInfo/bodyTestStore.js'
const PHASES = [
{ until: 20, hint: '校准中', text: '请保持站立姿势,双手自然下垂' },
{ until: 50, hint: '阻抗测量', text: '请勿移动,正在进行生物电阻抗分析' },
{ until: 80, hint: '数据分析', text: '正在计算体脂与肌肉分布' },
{ until: 100, hint: '即将完成', text: '生成健康报告中…' }
]
export default {
components: { MemberInfoSubNav },
data() {
return {
progress: 0,
liveMetrics: {},
timer: null,
finished: false
}
},
computed: {
ringRotation() {
return -90 + (this.progress / 100) * 360
},
phaseHint() {
const phase = PHASES.find((p) => this.progress <= p.until)
return phase?.hint || '完成'
},
statusText() {
const phase = PHASES.find((p) => this.progress <= p.until)
return phase?.text || '测量完成'
},
liveDisplay() {
const m = this.liveMetrics
return [
{ key: 'weight', label: '体重(kg)', value: m.weight ?? '--' },
{ key: 'bodyFat', label: '体脂率(%)', value: m.bodyFat ?? '--' },
{ key: 'muscleMass', label: '肌肉量(kg)', value: m.muscleMass ?? '--' },
{ key: 'bmr', label: '基础代谢', value: m.bmr ?? '--' }
]
}
},
onLoad() {
const store = loadMemberStore()
if (!store.bodyTest.device.connected) {
uni.showToast({ title: '请先连接设备', icon: 'none' })
setTimeout(() => {
navigateToPage(PAGE.BODY_TEST_CONNECT)
}, 800)
return
}
this.startMeasurement()
},
onUnload() {
this.clearTimer()
},
methods: {
clearTimer() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
startMeasurement() {
const store = loadMemberStore()
this.liveMetrics = interpolateMeasuringMetrics(0, store.profile)
this.timer = setInterval(() => {
if (this.progress >= 100) {
this.completeMeasurement()
return
}
this.progress = Math.min(100, this.progress + 2)
const s = loadMemberStore()
this.liveMetrics = interpolateMeasuringMetrics(this.progress, s.profile)
}, 120)
},
completeMeasurement() {
if (this.finished) return
this.finished = true
this.clearTimer()
const store = loadMemberStore()
const record = saveSimulatedBodyTestRecord(store, {
...this.liveMetrics,
visceralFat: 6,
boneMass: 2.42,
bodyWater: this.liveMetrics.bodyWater || 52.8,
protein: 16.4
})
persistMemberStore(store)
uni.showToast({ title: '测量完成', icon: 'success' })
setTimeout(() => {
navigateToPage(`${PAGE.BODY_TEST_REPORT}?id=${record.id}&new=1`)
}, 600)
},
onCancel() {
if (this.finished) return
uni.showModal({
title: '取消测量',
content: '确定要中断当前体测吗?',
success: (res) => {
if (res.confirm) {
this.clearTimer()
goBackOrTab(PAGE.BODY_TEST_HOME)
}
}
})
}
}
}
</script>
<style>
@import '@/common/style/base.css';
@import '@/common/style/memberInfo/pages/page-reset.css';
@import '@/common/style/memberInfo/pages/sub-page-base.css';
@import '@/common/style/memberInfo/member-info-component-reset.css';
@import '@/common/style/memberInfo/member-info-sub-nav.css';
@import '@/common/style/memberInfo/member-info-tap.css';
@import '@/common/style/memberInfo/pages/body-test-common.css';
</style>