feat: bmi
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { GroupMeta } from "@/stores/course";
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
groupMeta: GroupMeta;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<v-card-item class="pa-4" :class="`bg-${groupMeta.color}`">
|
||||||
|
<template #prepend>
|
||||||
|
<v-avatar class="group-avatar" size="60">
|
||||||
|
<v-icon color="white" :icon="groupMeta.icon" size="34" />
|
||||||
|
</v-avatar>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #subtitle>
|
||||||
|
<span class="text-title-small group-caption">你的體適能組別</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #title>
|
||||||
|
<span class="text-h5 font-weight-black text-white">
|
||||||
|
{{ groupMeta.label }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</v-card-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.group-avatar {
|
||||||
|
background-color: rgba(255, 255, 255, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.group-caption {
|
||||||
|
color: rgba(255, 255, 255, 0.85);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -6,9 +6,7 @@
|
|||||||
<v-app-bar-nav-icon variant="text" @click="drawer = !drawer" />
|
<v-app-bar-nav-icon variant="text" @click="drawer = !drawer" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-app-bar-title class="font-weight-bold flex-grow-1">
|
<v-app-bar-title class="font-weight-bold flex-grow-1"> 運動玩轉健康力 </v-app-bar-title>
|
||||||
運動玩轉健康力
|
|
||||||
</v-app-bar-title>
|
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
@@ -21,10 +19,7 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
@click="isLargeText = !isLargeText"
|
@click="isLargeText = !isLargeText"
|
||||||
>
|
>
|
||||||
<v-icon
|
<v-icon :color="isLargeText ? 'accent' : 'white'" icon="mdi-format-size" />
|
||||||
:color="isLargeText ? 'accent' : 'white'"
|
|
||||||
icon="mdi-format-size"
|
|
||||||
/>
|
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -42,7 +37,7 @@
|
|||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-avatar color="accent" size="48">
|
<v-avatar color="accent" size="48">
|
||||||
<span class="text-white font-weight-bold text-h6">
|
<span class="text-white font-weight-bold text-h6">
|
||||||
{{ (store.userProfile.name || "姓名").substring(0, 1) }}
|
{{ (store.userProfile.name || '姓名').substring(0, 1) }}
|
||||||
</span>
|
</span>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
</template>
|
</template>
|
||||||
@@ -63,9 +58,7 @@
|
|||||||
</v-avatar>
|
</v-avatar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-list-item-subtitle class="text-white-50"
|
<v-list-item-subtitle class="text-white-50">未登入訪客</v-list-item-subtitle>
|
||||||
>未登入訪客</v-list-item-subtitle
|
|
||||||
>
|
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-divider />
|
<v-divider />
|
||||||
@@ -78,12 +71,7 @@
|
|||||||
<v-list-item-title>大字體模式</v-list-item-title>
|
<v-list-item-title>大字體模式</v-list-item-title>
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-switch
|
<v-switch v-model="isLargeText" color="secondary" density="compact" hide-details />
|
||||||
v-model="isLargeText"
|
|
||||||
color="secondary"
|
|
||||||
density="compact"
|
|
||||||
hide-details
|
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
@@ -100,6 +88,13 @@
|
|||||||
@click="drawer = false"
|
@click="drawer = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<v-list-item
|
||||||
|
v-if="SELF_ASSESSMENT_ENABLED"
|
||||||
|
color="primary"
|
||||||
|
prepend-icon="mdi-clipboard-text-search"
|
||||||
|
title="自評"
|
||||||
|
to="/self-assessment"
|
||||||
|
/>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-if="BODY_COMPOSITION_ENABLED && store.isLoggedIn"
|
v-if="BODY_COMPOSITION_ENABLED && store.isLoggedIn"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -109,14 +104,6 @@
|
|||||||
@click="drawer = false"
|
@click="drawer = false"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<v-list-item
|
|
||||||
v-if="SELF_ASSESSMENT_ENABLED"
|
|
||||||
color="primary"
|
|
||||||
prepend-icon="mdi-clipboard-text-search"
|
|
||||||
title="自評"
|
|
||||||
to="/self-assessment"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-if="store.isLoggedIn"
|
v-if="store.isLoggedIn"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -184,10 +171,7 @@
|
|||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
|
|
||||||
<!-- 主要內容區 -->
|
<!-- 主要內容區 -->
|
||||||
<v-main
|
<v-main class="bg-white min-vh-100" :class="{ 'pb-16': BOTTOM_NAVIGATION_ENABLED }">
|
||||||
class="bg-white min-vh-100"
|
|
||||||
:class="{ 'pb-16': BOTTOM_NAVIGATION_ENABLED }"
|
|
||||||
>
|
|
||||||
<v-container class="px-4 py-2">
|
<v-container class="px-4 py-2">
|
||||||
<slot name="main" />
|
<slot name="main" />
|
||||||
</v-container>
|
</v-container>
|
||||||
@@ -204,17 +188,11 @@
|
|||||||
tag="div"
|
tag="div"
|
||||||
>
|
>
|
||||||
<v-btn to="/" value="home">
|
<v-btn to="/" value="home">
|
||||||
<v-icon :color="getBottomNavIconColor('home')"
|
<v-icon :color="getBottomNavIconColor('home')">mdi-view-dashboard</v-icon>
|
||||||
>mdi-view-dashboard</v-icon
|
|
||||||
>
|
|
||||||
<span class="bottom-nav-text">首頁</span>
|
<span class="bottom-nav-text">首頁</span>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
<v-btn
|
<v-btn v-if="SELF_ASSESSMENT_ENABLED" to="/self-assessment" value="self-assessment">
|
||||||
v-if="SELF_ASSESSMENT_ENABLED"
|
|
||||||
to="/self-assessment"
|
|
||||||
value="self-assessment"
|
|
||||||
>
|
|
||||||
<v-icon :color="getBottomNavIconColor('self-assessment')">
|
<v-icon :color="getBottomNavIconColor('self-assessment')">
|
||||||
mdi-clipboard-text-search
|
mdi-clipboard-text-search
|
||||||
</v-icon>
|
</v-icon>
|
||||||
@@ -222,25 +200,13 @@
|
|||||||
<span class="bottom-nav-text">自評</span>
|
<span class="bottom-nav-text">自評</span>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
<v-btn
|
<v-btn v-if="CHECKIN_ENABLED && store.isLoggedIn" to="/checkin" value="checkin">
|
||||||
v-if="CHECKIN_ENABLED && store.isLoggedIn"
|
<v-icon :color="getBottomNavIconColor('checkin')">mdi-qrcode-scan</v-icon>
|
||||||
to="/checkin"
|
|
||||||
value="checkin"
|
|
||||||
>
|
|
||||||
<v-icon :color="getBottomNavIconColor('checkin')"
|
|
||||||
>mdi-qrcode-scan</v-icon
|
|
||||||
>
|
|
||||||
<span class="bottom-nav-text">量測</span>
|
<span class="bottom-nav-text">量測</span>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
<v-btn
|
<v-btn v-if="APPOINTMENT_ENABLED && store.isLoggedIn" to="/appointment" value="appointment">
|
||||||
v-if="APPOINTMENT_ENABLED && store.isLoggedIn"
|
<v-icon :color="getBottomNavIconColor('appointment')">mdi-calendar-check</v-icon>
|
||||||
to="/appointment"
|
|
||||||
value="appointment"
|
|
||||||
>
|
|
||||||
<v-icon :color="getBottomNavIconColor('appointment')"
|
|
||||||
>mdi-calendar-check</v-icon
|
|
||||||
>
|
|
||||||
<span class="bottom-nav-text">預約</span>
|
<span class="bottom-nav-text">預約</span>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-bottom-navigation>
|
</v-bottom-navigation>
|
||||||
@@ -248,9 +214,7 @@
|
|||||||
<!-- 隱私授權對話框 -->
|
<!-- 隱私授權對話框 -->
|
||||||
<v-dialog v-model="showPrivacy" max-width="500">
|
<v-dialog v-model="showPrivacy" max-width="500">
|
||||||
<v-card class="rounded-xl">
|
<v-card class="rounded-xl">
|
||||||
<v-card-title
|
<v-card-title class="bg-primary text-white font-weight-bold d-flex align-center">
|
||||||
class="bg-primary text-white font-weight-bold d-flex align-center"
|
|
||||||
>
|
|
||||||
<v-icon class="mr-2" icon="mdi-shield-check" />
|
<v-icon class="mr-2" icon="mdi-shield-check" />
|
||||||
個資同意與資料授權
|
個資同意與資料授權
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
@@ -267,7 +231,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p class="text-caption text-grey">
|
<p class="text-caption text-grey">
|
||||||
授權狀態:{{ store.userProfile.consent ? "已同意授權" : "未授權" }}
|
授權狀態:{{ store.userProfile.consent ? '已同意授權' : '未授權' }}
|
||||||
</p>
|
</p>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
@@ -287,58 +251,57 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch } from 'vue'
|
||||||
import { useRoute, useRouter } from "vue-router";
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { useDisplayUserName } from "@/composables/useDisplayUserName";
|
import { useDisplayUserName } from '@/composables/useDisplayUserName'
|
||||||
import {
|
import {
|
||||||
APPOINTMENT_ENABLED,
|
APPOINTMENT_ENABLED,
|
||||||
BODY_COMPOSITION_ENABLED,
|
BODY_COMPOSITION_ENABLED,
|
||||||
BOTTOM_NAVIGATION_ENABLED,
|
BOTTOM_NAVIGATION_ENABLED,
|
||||||
CHECKIN_ENABLED,
|
CHECKIN_ENABLED,
|
||||||
SELF_ASSESSMENT_ENABLED,
|
SELF_ASSESSMENT_ENABLED,
|
||||||
} from "@/config/features";
|
} from '@/config/features'
|
||||||
import { useAppStore } from "@/stores/app";
|
import { useAppStore } from '@/stores/app'
|
||||||
import { useCourseStore } from "@/stores/course";
|
import { useCourseStore } from '@/stores/course'
|
||||||
|
|
||||||
const store = useAppStore();
|
const store = useAppStore()
|
||||||
const courseStore = useCourseStore();
|
const courseStore = useCourseStore()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
const displayUserName = useDisplayUserName(store.userProfile);
|
const displayUserName = useDisplayUserName(store.userProfile)
|
||||||
|
|
||||||
const drawer = ref(false);
|
const drawer = ref(false)
|
||||||
const activeTab = ref("home");
|
const activeTab = ref('home')
|
||||||
const showPrivacy = ref(false);
|
const showPrivacy = ref(false)
|
||||||
|
|
||||||
// 無障礙狀態 (可持久化儲存於 localStorage)
|
// 無障礙狀態 (可持久化儲存於 localStorage)
|
||||||
const isLargeText = ref(localStorage.getItem("mode-large-text") === "true");
|
const isLargeText = ref(localStorage.getItem('mode-large-text') === 'true')
|
||||||
|
|
||||||
watch(isLargeText, (newVal) => {
|
watch(isLargeText, (newVal) => {
|
||||||
localStorage.setItem("mode-large-text", String(newVal));
|
localStorage.setItem('mode-large-text', String(newVal))
|
||||||
});
|
})
|
||||||
|
|
||||||
// 同步底部導航狀態與當前路由
|
// 同步底部導航狀態與當前路由
|
||||||
watch(
|
watch(
|
||||||
() => route.path,
|
() => route.path,
|
||||||
(path) => {
|
(path) => {
|
||||||
if (path === "/") activeTab.value = "home";
|
if (path === '/') activeTab.value = 'home'
|
||||||
else if (path.startsWith("/self-assessment"))
|
else if (path.startsWith('/self-assessment')) activeTab.value = 'self-assessment'
|
||||||
activeTab.value = "self-assessment";
|
else if (path.startsWith('/appointment')) activeTab.value = 'appointment'
|
||||||
else if (path.startsWith("/appointment")) activeTab.value = "appointment";
|
else if (path.startsWith('/checkin')) activeTab.value = 'checkin'
|
||||||
else if (path.startsWith("/checkin")) activeTab.value = "checkin";
|
|
||||||
},
|
},
|
||||||
{ immediate: true },
|
{ immediate: true }
|
||||||
);
|
)
|
||||||
|
|
||||||
function getBottomNavIconColor(value: string) {
|
function getBottomNavIconColor(value: string) {
|
||||||
return activeTab.value === value ? "secondary" : "secondary-darken-1";
|
return activeTab.value === value ? 'secondary' : 'secondary-darken-1'
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleLogout() {
|
async function handleLogout() {
|
||||||
await store.logout();
|
await store.logout()
|
||||||
courseStore.resetGroup();
|
courseStore.resetGroup()
|
||||||
await router.push("/login");
|
await router.push('/login')
|
||||||
drawer.value = false;
|
drawer.value = false
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export const APPOINTMENT_ENABLED = false;
|
export const APPOINTMENT_ENABLED = false
|
||||||
export const BODY_COMPOSITION_ENABLED = false;
|
export const BODY_COMPOSITION_ENABLED = true
|
||||||
export const BOTTOM_NAVIGATION_ENABLED = false;
|
export const BOTTOM_NAVIGATION_ENABLED = false
|
||||||
export const CHECKIN_ENABLED = false;
|
export const CHECKIN_ENABLED = false
|
||||||
export const EXERCISE_DURATION_RECOMMENDATION_ENABLED = false;
|
export const EXERCISE_DURATION_RECOMMENDATION_ENABLED = false
|
||||||
export const RADAR_ENABLED = true;
|
export const RADAR_ENABLED = true
|
||||||
export const SELF_ASSESSMENT_ENABLED = true;
|
export const SELF_ASSESSMENT_ENABLED = true
|
||||||
|
|||||||
@@ -10,23 +10,7 @@
|
|||||||
elevation="1"
|
elevation="1"
|
||||||
variant="flat"
|
variant="flat"
|
||||||
>
|
>
|
||||||
<v-card-item class="pa-4" :class="`bg-${store.groupMeta.color}`">
|
<FitnessGroupCardItem :group-meta="store.groupMeta" />
|
||||||
<template #prepend>
|
|
||||||
<v-avatar class="group-avatar" size="60">
|
|
||||||
<v-icon color="white" :icon="store.groupMeta.icon" size="34" />
|
|
||||||
</v-avatar>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #subtitle>
|
|
||||||
<span class="text-title-small group-caption">你的體適能組別</span>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #title>
|
|
||||||
<span class="text-h5 font-weight-black text-white">{{
|
|
||||||
store.groupMeta.label
|
|
||||||
}}</span>
|
|
||||||
</template>
|
|
||||||
</v-card-item>
|
|
||||||
|
|
||||||
<v-card-text class="text-body-medium text-grey-darken-2 pa-4">
|
<v-card-text class="text-body-medium text-grey-darken-2 pa-4">
|
||||||
{{ store.groupMeta.description }}
|
{{ store.groupMeta.description }}
|
||||||
@@ -388,6 +372,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TimeSlot, YesNo } from "@/api/types";
|
import type { TimeSlot, YesNo } from "@/api/types";
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
import FitnessGroupCardItem from "@/components/FitnessGroupCardItem.vue";
|
||||||
import Layout from "@/components/layout/DefaultLayout.vue";
|
import Layout from "@/components/layout/DefaultLayout.vue";
|
||||||
import PageHeading from "@/components/layout/PageHeading.vue";
|
import PageHeading from "@/components/layout/PageHeading.vue";
|
||||||
import { EXERCISE_DURATION_RECOMMENDATION_ENABLED } from "@/config/features";
|
import { EXERCISE_DURATION_RECOMMENDATION_ENABLED } from "@/config/features";
|
||||||
@@ -528,15 +513,6 @@ onMounted(() => {
|
|||||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 組別卡片:半透明白底圓形與次級白字,Vuetify 沒有對應的 utility class */
|
|
||||||
.group-avatar {
|
|
||||||
background-color: rgba(255, 255, 255, 0.22);
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-caption {
|
|
||||||
color: rgba(255, 255, 255, 0.85);
|
|
||||||
}
|
|
||||||
|
|
||||||
.pa-0 :deep(.v-expansion-panel-text__wrapper) {
|
.pa-0 :deep(.v-expansion-panel-text__wrapper) {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,39 +7,17 @@
|
|||||||
<!-- 頂部:我的健康力護照卡片 (Taipei Masters Hub) -->
|
<!-- 頂部:我的健康力護照卡片 (Taipei Masters Hub) -->
|
||||||
<v-card class="border-primary border-xl rounded-xl" variant="flat">
|
<v-card class="border-primary border-xl rounded-xl" variant="flat">
|
||||||
<v-row class="mt-4 pa-2" no-gutters>
|
<v-row class="mt-4 pa-2" no-gutters>
|
||||||
<v-col cols="8">
|
<v-col :cols="courseStore.groupMissing ? 8 : 12">
|
||||||
<v-card-title>
|
<v-card-title>
|
||||||
{{ displayUserName }}
|
{{ displayUserName }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-subtitle> 資料更新於 {{ todayTimeString }} </v-card-subtitle>
|
<v-card-subtitle> 資料更新於 {{ todayTimeString }} </v-card-subtitle>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col class="d-flex justify-center" cols="4">
|
<v-col v-if="courseStore.groupMissing" class="d-flex justify-center" cols="4">
|
||||||
<!-- 體適能分組徽章 -->
|
<!-- 體適能分組徽章 -->
|
||||||
<div
|
<div class="score-disk d-flex flex-column justify-center align-center text-primary">
|
||||||
:class="[
|
<span class="group-label">未完成體適能測試</span>
|
||||||
'score-disk',
|
|
||||||
'd-flex',
|
|
||||||
'flex-column',
|
|
||||||
'justify-center',
|
|
||||||
'align-center',
|
|
||||||
courseStore.groupLoaded ? `text-${courseStore.groupMeta.color}` : 'text-primary',
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<v-progress-circular
|
|
||||||
v-if="courseStore.groupLoading"
|
|
||||||
color="primary"
|
|
||||||
indeterminate
|
|
||||||
size="28"
|
|
||||||
width="3"
|
|
||||||
/>
|
|
||||||
<span v-else-if="courseStore.groupLoaded" class="group-label">
|
|
||||||
{{ courseStore.groupMeta.label }}
|
|
||||||
</span>
|
|
||||||
<span v-else-if="courseStore.groupMissing" class="group-label">
|
|
||||||
未完成體適能測試
|
|
||||||
</span>
|
|
||||||
<span v-else class="group-label">無資料</span>
|
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@@ -73,7 +51,7 @@
|
|||||||
<div class="px-2">
|
<div class="px-2">
|
||||||
<ModuleRouterCard
|
<ModuleRouterCard
|
||||||
clickable
|
clickable
|
||||||
description="依 11 項測驗成績重新計算體適能分組。"
|
description="依 11 項測驗成績重新計算"
|
||||||
icon="mdi-refresh-circle"
|
icon="mdi-refresh-circle"
|
||||||
icon-color="secondary"
|
icon-color="secondary"
|
||||||
:disabled="generatePhysicalFitnessLoading"
|
:disabled="generatePhysicalFitnessLoading"
|
||||||
@@ -85,7 +63,13 @@
|
|||||||
|
|
||||||
<!-- 課程建議入口 -->
|
<!-- 課程建議入口 -->
|
||||||
|
|
||||||
<v-list-item append-icon="mdi-chevron-right" class="bg-primary py-4 mt-4" to="/course">
|
<FitnessGroupCardItem
|
||||||
|
v-if="courseStore.groupLoaded"
|
||||||
|
class="mt-4"
|
||||||
|
:group-meta="courseStore.groupMeta"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-list-item append-icon="mdi-chevron-right" class="bg-primary py-4" to="/course">
|
||||||
<v-list-item-title class="font-weight-bold">
|
<v-list-item-title class="font-weight-bold">
|
||||||
<v-icon icon="mdi-notebook-check-outline" size="16" />
|
<v-icon icon="mdi-notebook-check-outline" size="16" />
|
||||||
課程建議
|
課程建議
|
||||||
@@ -349,6 +333,7 @@ import { useRouter } from 'vue-router'
|
|||||||
import type { PhysicalFitnessItem } from '@/api/types'
|
import type { PhysicalFitnessItem } from '@/api/types'
|
||||||
import { fetchPhysicalFitness, generatePhysicalFitness } from '@/api/physical-fitness'
|
import { fetchPhysicalFitness, generatePhysicalFitness } from '@/api/physical-fitness'
|
||||||
import BrandAvatar from '@/components/BrandAvatar.vue'
|
import BrandAvatar from '@/components/BrandAvatar.vue'
|
||||||
|
import FitnessGroupCardItem from '@/components/FitnessGroupCardItem.vue'
|
||||||
import HealthRadarChart from '@/components/HealthRadarChart.vue'
|
import HealthRadarChart from '@/components/HealthRadarChart.vue'
|
||||||
import IntroductionCarousel from '@/components/IntroductionCarousel.vue'
|
import IntroductionCarousel from '@/components/IntroductionCarousel.vue'
|
||||||
import Layout from '@/components/layout/DefaultLayout.vue'
|
import Layout from '@/components/layout/DefaultLayout.vue'
|
||||||
|
|||||||
Reference in New Issue
Block a user