整合api请求、添加购买会员卡页面、登陆页面

This commit is contained in:
future
2026-06-23 22:17:53 +08:00
parent 1c547a717e
commit 8d8c823616
70 changed files with 7666 additions and 2656 deletions
@@ -169,7 +169,8 @@
</view>
</template>
<script>
<script setup>
import { ref, computed } from 'vue'
import MemberInfoSubNav from '@/components/memberInfo/MemberInfoSubNav.vue'
import BodyTestRadarChart from '@/components/memberInfo/BodyTestRadarChart.vue'
import BodyTestTrendChart from '@/components/memberInfo/BodyTestTrendChart.vue'
@@ -180,127 +181,139 @@ import {
getBodyTestTrendData,
getRecommendedCourses,
computeChanges,
formatChangeValue,
bodyTestMock
formatChangeValue
} from '@/common/memberInfo/bodyTestStore.js'
export default {
components: { MemberInfoSubNav, BodyTestRadarChart, BodyTestTrendChart },
data() {
const recordId = ref(null)
const record = ref(null)
const previous = ref(null)
const chartWidth = ref(300)
const radarLabels = computed(() => {
return ['体重', 'BMI', '体脂率', '肌肉量', '内脏脂肪', '基础代谢']
})
const radarKeys = ['weight', 'bmi', 'bodyFat', 'muscleMass', 'visceralFat', 'bmr']
const radarValues = computed(() => {
if (!record.value?.radar) return []
return radarKeys.map((k) => record.value.radar[k] || 0)
})
const metricDefs = [
{ key: 'weight', label: '体重', unit: 'kg' },
{ key: 'bmi', label: 'BMI' },
{ key: 'bodyFat', label: '体脂率', unit: '%' },
{ key: 'muscleMass', label: '肌肉量', unit: 'kg' },
{ key: 'visceralFat', label: '内脏脂肪', unit: '级' },
{ key: 'bmr', label: '基础代谢', unit: 'kcal' },
{ key: 'bodyWater', label: '体水分', unit: '%' },
{ key: 'boneMass', label: '骨量', unit: 'kg' }
]
const metricCards = computed(() => {
if (!record.value?.metrics) return []
const changesVal = changes.value
const defs = metricDefs.slice(0, 8)
return defs.map((def) => {
const val = record.value.metrics[def.key]
const diff = changesVal[def.key]
let changeText = ''
let changeClass = ''
if (diff !== undefined && diff !== null) {
changeText = formatChangeValue(def.key, diff)
const lowerBetter = ['weight', 'bodyFat', 'visceralFat'].includes(def.key)
const isGood = lowerBetter ? diff < 0 : diff > 0
changeClass = isGood ? 'bt-metric__change--down' : 'bt-metric__change--up'
}
const display = def.unit ? `${val}${def.unit === '%' ? '%' : def.unit === 'kg' ? '' : ` ${def.unit}`}` : val
return {
recordId: null,
record: null,
previous: null,
chartWidth: 300
}
},
computed: {
radarLabels() {
return bodyTestMock.radarLabels.map((l) => l.label)
},
radarValues() {
if (!this.record?.radar) return []
const keys = bodyTestMock.radarLabels.map((l) => l.key)
return keys.map((k) => this.record.radar[k] || 0)
},
metricCards() {
if (!this.record?.metrics) return []
const changes = this.changes
const defs = bodyTestMock.metricDefs.slice(0, 8)
return defs.map((def) => {
const val = this.record.metrics[def.key]
const diff = changes[def.key]
let changeText = ''
let changeClass = ''
if (diff !== undefined && diff !== null) {
changeText = formatChangeValue(def.key, diff)
const lowerBetter = ['weight', 'bodyFat', 'visceralFat'].includes(def.key)
const isGood = lowerBetter ? diff < 0 : diff > 0
changeClass = isGood ? 'bt-metric__change--down' : 'bt-metric__change--up'
}
const display = def.unit ? `${val}${def.unit === '%' ? '%' : def.unit === 'kg' ? '' : ` ${def.unit}`}` : val
return {
key: def.key,
label: def.label + (def.unit && def.unit !== '%' && def.unit !== 'kg' ? `(${def.unit})` : def.unit === 'kg' ? '(kg)' : def.unit === '%' ? '(%)' : ''),
display: def.key === 'bodyFat' ? `${val}%` : def.key === 'bodyWater' ? `${val}%` : def.unit === 'kg' ? val : def.unit ? `${val}` : val,
changeText,
changeClass
}
})
},
changes() {
if (this.record?.changes) return this.record.changes
if (this.previous) return computeChanges(this.record, this.previous)
return {}
},
trendPreview() {
const store = loadMemberStore()
return getBodyTestTrendData(store, 'weight', 4)
},
courses() {
return getRecommendedCourses(this.record)
}
},
onLoad(options) {
this.recordId = options?.id ? Number(options.id) : null
this.chartWidth = uni.getSystemInfoSync().windowWidth - 64
this.loadRecord()
},
methods: {
loadRecord() {
const store = loadMemberStore()
const records = store.bodyTest.records
if (this.recordId) {
this.record = getBodyTestRecordById(store, this.recordId)
} else {
this.record = records.length ? { ...records[0] } : null
}
if (this.record) {
const idx = records.findIndex((r) => r.id === this.record.id)
this.previous = idx >= 0 && records[idx + 1] ? records[idx + 1] : null
}
},
onBack() {
goBackOrTab(PAGE.BODY_TEST_HOME)
},
goTrend() {
navigateToPage(`${PAGE.BODY_TEST_TREND}?metric=weight`)
},
exportReport() {
uni.showLoading({ title: '生成中…' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '报告已保存到相册', icon: 'success' })
}, 1200)
},
shareReport() {
uni.showActionSheet({
itemList: ['分享给微信好友', '生成分享海报', '复制报告链接'],
success: (res) => {
const msgs = ['已唤起微信分享', '海报已生成', '链接已复制']
uni.showToast({ title: msgs[res.tapIndex] || '分享成功', icon: 'none' })
}
})
},
onCourseTap(course) {
uni.showModal({
title: course.title,
content: `${course.coach}\n${course.schedule}\n\n是否前往预约?`,
success: (res) => {
if (res.confirm) {
navigateToPage(PAGE.COURSE_LIST)
}
}
})
},
retest() {
navigateToPage(PAGE.BODY_TEST_HOME)
key: def.key,
label: def.label + (def.unit && def.unit !== '%' && def.unit !== 'kg' ? `(${def.unit})` : def.unit === 'kg' ? '(kg)' : def.unit === '%' ? '(%)' : ''),
display: def.key === 'bodyFat' ? `${val}%` : def.key === 'bodyWater' ? `${val}%` : def.unit === 'kg' ? val : def.unit ? `${val}` : val,
changeText,
changeClass
}
})
})
const changes = computed(() => {
if (record.value?.changes) return record.value.changes
if (previous.value) return computeChanges(record.value, previous.value)
return {}
})
const trendPreview = computed(() => {
const store = loadMemberStore()
return getBodyTestTrendData(store, 'weight', 4)
})
const courses = computed(() => {
return getRecommendedCourses(record.value)
})
function loadRecord() {
const store = loadMemberStore()
const records = store.bodyTest.records
if (recordId.value) {
record.value = getBodyTestRecordById(store, recordId.value)
} else {
record.value = records.length ? { ...records[0] } : null
}
if (record.value) {
const idx = records.findIndex((r) => r.id === record.value.id)
previous.value = idx >= 0 && records[idx + 1] ? records[idx + 1] : null
}
}
function onBack() {
goBackOrTab(PAGE.BODY_TEST_HOME)
}
function goTrend() {
navigateToPage(`${PAGE.BODY_TEST_TREND}?metric=weight`)
}
function exportReport() {
uni.showLoading({ title: '生成中…' })
setTimeout(() => {
uni.hideLoading()
uni.showToast({ title: '报告已保存到相册', icon: 'success' })
}, 1200)
}
function shareReport() {
uni.showActionSheet({
itemList: ['分享给微信好友', '生成分享海报', '复制报告链接'],
success: (res) => {
const msgs = ['已唤起微信分享', '海报已生成', '链接已复制']
uni.showToast({ title: msgs[res.tapIndex] || '分享成功', icon: 'none' })
}
})
}
function onCourseTap(course) {
uni.showModal({
title: course.title,
content: `${course.coach}\n${course.schedule}\n\n是否前往预约?`,
success: (res) => {
if (res.confirm) {
navigateToPage(PAGE.COURSE_LIST)
}
}
})
}
function retest() {
navigateToPage(PAGE.BODY_TEST_HOME)
}
// Initialize
chartWidth.value = uni.getSystemInfoSync().windowWidth - 64
loadRecord()
</script>
<style>
<style lang="scss">
@import '@/common/style/base.css';
@import '@/common/style/memberInfo/pages/page-reset.css';
@import '@/common/style/memberInfo/pages/sub-page-base.css';