Files
sports-empower-hub/app/citizen-frontend/src/components/body-composition/BmiAnalysisCard.vue
T
skytek_xinliang 0f3e7b8a56 feat: bmi
2026-10-05 10:11:04 +08:00

207 lines
4.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { computed } from "vue";
import { WHO_BMI_STANDARDS } from "@/data/whoBmiStandards";
import {
BODY_COMPOSITION_COLORS,
getBmiTone,
} from "@/utils/body-composition-status";
const props = defineProps<{
weightKg: number;
bmi: number;
bmiStatus: string;
}>();
const statusColor = computed(
() => BODY_COMPOSITION_COLORS[getBmiTone(props.bmi)],
);
const recommendation = computed(() => {
if (props.bmi < 18.5) {
return "體重低於正常範圍,建議留意營養攝取與健康狀況。";
}
if (props.bmi < 25) {
return "體重位於正常範圍,請持續維持均衡飲食與規律運動。";
}
if (props.bmi < 30) {
return "體重已超過正常範圍,建議適度調整體重。";
}
return "您的 BMI 已進入肥胖範圍,建議諮詢專業人員並逐步調整生活習慣。";
});
function formatMeasurement(value: number): string {
return Number.isFinite(value) ? value.toFixed(1) : "--";
}
</script>
<template>
<v-card class="analysis-card rounded-xl" elevation="1">
<v-card-title class="text-h5 font-weight-black text-center pt-6">
體重與 BMI 分析
</v-card-title>
<v-card-text class="pa-4 pa-sm-6">
<div class="metrics-grid mb-5">
<div class="metric-cell text-center">
<div class="text-body-large text-grey-darken-2 mb-2">體重</div>
<div class="metric-value text-grey-darken-4">
{{ formatMeasurement(weightKg) }}
<span class="metric-unit">公斤</span>
</div>
</div>
<div class="metric-cell text-center">
<div class="text-body-large text-grey-darken-2 mb-2">BMI</div>
<div class="metric-value" :style="{ color: statusColor }">
{{ formatMeasurement(bmi) }}
</div>
</div>
</div>
<div class="d-flex flex-wrap justify-center align-center ga-2 mb-5">
<span class="text-title-medium">您的 BMI 屬於</span>
<v-chip
class="semantic-chip font-weight-black"
:color="statusColor"
label
size="large"
variant="flat"
>
{{ bmiStatus }}
</v-chip>
</div>
<v-alert
class="recommendation-alert mb-6"
:color="statusColor"
icon="mdi-bullhorn-outline"
variant="tonal"
>
{{ recommendation }}
</v-alert>
<v-sheet class="who-panel rounded-xl pa-4" color="grey-lighten-4">
<div class="who-title text-center mb-1">世界衛生組織 WHO 定義</div>
<div class="who-formula text-grey-darken-2 text-center mb-5">
(BMI = 體重 ÷ 身高²)
</div>
<div class="who-standards">
<div
v-for="standard in WHO_BMI_STANDARDS"
:key="standard.label"
class="who-standard rounded-lg text-center"
:style="{
backgroundColor: BODY_COMPOSITION_COLORS[standard.tone],
}"
>
<div class="who-standard-label">{{ standard.label }}</div>
<div class="who-standard-range">{{ standard.range }}</div>
</div>
</div>
<p class="who-note text-grey-darken-2 text-center mb-0 mt-5">
BMI 只是初步判斷,需搭配體脂率<br
class="d-none d-sm-inline"
/>與肌肉量進一步分析。
</p>
</v-sheet>
</v-card-text>
</v-card>
</template>
<style scoped>
.analysis-card {
border: 1px solid rgba(var(--v-theme-primary), 0.24);
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.metric-cell {
min-width: 0;
padding: 8px 12px;
}
.metric-cell + .metric-cell {
border-left: 1px solid rgba(0, 0, 0, 0.14);
}
.metric-value {
font-size: clamp(2.25rem, 10vw, 3.125rem);
font-weight: 900;
line-height: 1.1;
white-space: nowrap;
}
.metric-unit {
font-size: clamp(0.875rem, 3.5vw, 1.25rem);
font-weight: 500;
}
.recommendation-alert {
font-size: 1rem;
line-height: 1.6;
}
.semantic-chip {
color: #252525 !important;
}
.who-title {
font-size: clamp(1.25rem, 5vw, 1.65rem);
font-weight: 700;
line-height: 1.35;
}
.who-formula,
.who-note {
font-size: clamp(1rem, 4vw, 1.25rem);
line-height: 1.55;
}
.who-standards {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
}
.who-standard {
min-width: 0;
padding: 18px 6px 16px;
color: #2b2b2b;
}
.who-standard-label {
margin-bottom: 4px;
font-size: clamp(1.2rem, 5vw, 1.55rem);
font-weight: 500;
}
.who-standard-range {
font-size: clamp(0.92rem, 3.8vw, 1.12rem);
font-weight: 800;
line-height: 1.25;
white-space: nowrap;
}
@media (max-width: 420px) {
.metric-cell {
padding-inline: 6px;
}
.who-panel {
padding-inline: 12px !important;
}
.who-standards {
gap: 6px;
}
}
</style>