feat: 建議課程前需要分組
This commit is contained in:
@@ -38,6 +38,9 @@
|
||||
<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>
|
||||
</v-col>
|
||||
@@ -227,12 +230,55 @@
|
||||
to="/introduction"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-dialog v-model="missingGroupDialog" max-width="400">
|
||||
<v-card class="rounded-xl overflow-hidden text-center">
|
||||
<v-card-title class="bg-primary text-white font-weight-bold py-3">
|
||||
尚未取得體適能分組
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text class="pa-6">
|
||||
<v-avatar class="mb-4" color="primary" size="64">
|
||||
<v-icon color="white" icon="mdi-calendar-check" size="34" />
|
||||
</v-avatar>
|
||||
|
||||
<p class="text-body-1 font-weight-bold text-grey-darken-4 mb-2">
|
||||
預約普測,建立您的體適能分組
|
||||
</p>
|
||||
<p class="text-body-2 text-grey-darken-2 mb-0">
|
||||
完成預約並到現場參加量測後,系統才能建立您的體適能分組與課程建議。
|
||||
</p>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<v-card-actions class="pa-4 justify-end">
|
||||
<v-btn
|
||||
class="rounded-lg"
|
||||
color="primary"
|
||||
variant="text"
|
||||
@click="missingGroupDialog = false"
|
||||
>
|
||||
稍後再說
|
||||
</v-btn>
|
||||
<v-btn
|
||||
class="rounded-lg font-weight-bold"
|
||||
color="primary"
|
||||
variant="flat"
|
||||
@click="goToAppointment"
|
||||
>
|
||||
前往預約
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from "vue";
|
||||
import { computed, ref, watch } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import BrandAvatar from "@/components/BrandAvatar.vue";
|
||||
import HealthRadarChart from "@/components/HealthRadarChart.vue";
|
||||
import Layout from "@/components/layout/DefaultLayout.vue";
|
||||
@@ -242,17 +288,65 @@ import { useCourseStore } from "@/stores/course";
|
||||
|
||||
const store = useAppStore();
|
||||
const courseStore = useCourseStore();
|
||||
const router = useRouter();
|
||||
const missingGroupDialog = ref(false);
|
||||
|
||||
const MISSING_GROUP_DIALOG_KEY = "missing-fitness-group-dialog-shown";
|
||||
|
||||
function hasShownMissingGroupDialog() {
|
||||
try {
|
||||
return sessionStorage.getItem(MISSING_GROUP_DIALOG_KEY) === "true";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function markMissingGroupDialogShown() {
|
||||
try {
|
||||
sessionStorage.setItem(MISSING_GROUP_DIALOG_KEY, "true");
|
||||
} catch {
|
||||
// 部分瀏覽器可能封鎖 sessionStorage,仍允許本次彈窗正常使用。
|
||||
}
|
||||
}
|
||||
|
||||
function clearMissingGroupDialogMarker() {
|
||||
try {
|
||||
sessionStorage.removeItem(MISSING_GROUP_DIALOG_KEY);
|
||||
} catch {
|
||||
// 不影響主要流程。
|
||||
}
|
||||
}
|
||||
|
||||
function openMissingGroupDialog() {
|
||||
if (
|
||||
store.isLoggedIn &&
|
||||
courseStore.groupMissing &&
|
||||
!hasShownMissingGroupDialog()
|
||||
) {
|
||||
markMissingGroupDialogShown();
|
||||
missingGroupDialog.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
async function goToAppointment() {
|
||||
missingGroupDialog.value = false;
|
||||
await router.push({ name: "appointment" });
|
||||
}
|
||||
|
||||
async function loadFitnessGroup() {
|
||||
if (!store.isLoggedIn) {
|
||||
missingGroupDialog.value = false;
|
||||
clearMissingGroupDialogMarker();
|
||||
courseStore.resetGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await courseStore.loadGroup();
|
||||
clearMissingGroupDialogMarker();
|
||||
} catch {
|
||||
// 錯誤狀態由 course store 提供給畫面顯示與重試。
|
||||
openMissingGroupDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user