chore: OXC Formatter

This commit is contained in:
skytek_xinliang
2026-08-13 15:41:12 +08:00
parent 5377b872d8
commit 8f5fa15d3a
40 changed files with 2392 additions and 3009 deletions
+184 -79
View File
@@ -3,13 +3,24 @@
<template #main>
<!-- 頁面標題:刻意縮小,把版面讓給下方的組別 -->
<div class="d-flex align-center mb-3">
<v-icon class="mr-2" color="primary" icon="mdi-calendar-week" size="18" />
<v-icon
class="mr-2"
color="primary"
icon="mdi-calendar-week"
size="18"
/>
<span class="text-title-small font-weight-bold text-grey-darken-1">課程建議</span>
<span class="text-title-small font-weight-bold text-grey-darken-1"
>課程建議</span
>
</div>
<!-- 體適能組別:本頁所有內容都依它而定,因此獨立成一張顯眼的卡片 -->
<v-card class="rounded-xl mb-6 overflow-hidden" elevation="1" variant="flat">
<v-card
class="rounded-xl mb-6 overflow-hidden"
elevation="1"
variant="flat"
>
<v-card-item class="pa-4" :class="`bg-${store.groupMeta.color}`">
<template #prepend>
<v-avatar class="group-avatar" size="60">
@@ -22,7 +33,9 @@
</template>
<template #title>
<span class="text-h5 font-weight-black text-white">{{ store.groupMeta.label }}</span>
<span class="text-h5 font-weight-black text-white">{{
store.groupMeta.label
}}</span>
</template>
</v-card-item>
@@ -61,7 +74,12 @@
<!-- 載入中 -->
<template v-if="store.loading">
<v-skeleton-loader v-for="n in 3" :key="n" class="rounded-xl mb-4" type="article" />
<v-skeleton-loader
v-for="n in 3"
:key="n"
class="rounded-xl mb-4"
type="article"
/>
</template>
<!-- 載入失敗 -->
@@ -75,7 +93,9 @@
{{ store.error }}
<template #append>
<v-btn size="small" variant="text" @click="store.loadAll()">重試</v-btn>
<v-btn size="small" variant="text" @click="store.loadAll()"
>重試</v-btn
>
</template>
</v-alert>
@@ -94,8 +114,15 @@
<template v-else>
<!-- 課程說明:對應 doc/課程說明.md -->
<v-card class="rounded-lg elevation-1 mt-4 overflow-hidden">
<v-card-title class="text-title-medium font-weight-bold text-primary d-flex align-center">
<v-icon class="mr-2" color="primary" icon="mdi-book-open-variant" size="20" />
<v-card-title
class="text-title-medium font-weight-bold text-primary d-flex align-center"
>
<v-icon
class="mr-2"
color="primary"
icon="mdi-book-open-variant"
size="20"
/>
課程說明
</v-card-title>
@@ -103,7 +130,9 @@
<v-expansion-panels v-model="openPanels" multiple variant="accordion">
<v-expansion-panel>
<v-expansion-panel-title class="font-weight-bold">族群特徵</v-expansion-panel-title>
<v-expansion-panel-title class="font-weight-bold"
>族群特徵</v-expansion-panel-title
>
<v-expansion-panel-text>
<p class="text-body-medium text-grey-darken-2 mb-3">
@@ -115,7 +144,11 @@
:key="index"
class="d-flex align-start ga-3 mb-2"
>
<v-icon color="secondary" :icon="`mdi-numeric-${index + 1}-circle`" size="20" />
<v-icon
color="secondary"
:icon="`mdi-numeric-${index + 1}-circle`"
size="20"
/>
<div class="text-body-medium">{{ item }}</div>
</div>
</v-expansion-panel-text>
@@ -132,12 +165,18 @@
:key="index"
class="d-flex align-start ga-3 mb-4"
>
<v-icon color="secondary" :icon="`mdi-numeric-${index + 1}-circle`" size="20" />
<v-icon
color="secondary"
:icon="`mdi-numeric-${index + 1}-circle`"
size="20"
/>
<div>
<div class="font-weight-bold">{{ item.title }}</div>
<div class="text-body-medium text-grey-darken-2 mt-1">{{ item.detail }}</div>
<div class="text-body-medium text-grey-darken-2 mt-1">
{{ item.detail }}
</div>
</div>
</div>
</v-expansion-panel-text>
@@ -154,7 +193,11 @@
:key="index"
class="d-flex align-start ga-3 mb-2"
>
<v-icon color="secondary" :icon="`mdi-numeric-${index + 1}-circle`" size="20" />
<v-icon
color="secondary"
:icon="`mdi-numeric-${index + 1}-circle`"
size="20"
/>
<div class="text-body-medium">{{ item }}</div>
</div>
</v-expansion-panel-text>
@@ -164,12 +207,21 @@
<!-- 運動時間建議:對應 doc/運動時間建議.png -->
<v-card class="rounded-lg elevation-1 mt-4 overflow-hidden">
<v-expansion-panels v-model="durationTablePanel" flat variant="accordion">
<v-expansion-panels
v-model="durationTablePanel"
flat
variant="accordion"
>
<v-expansion-panel value="duration">
<v-expansion-panel-title
class="course-table-panel-title text-title-medium font-weight-bold text-primary"
>
<v-icon class="mr-2" color="primary" icon="mdi-timer-outline" size="20" />
<v-icon
class="mr-2"
color="primary"
icon="mdi-timer-outline"
size="20"
/>
運動時間建議
</v-expansion-panel-title>
@@ -179,9 +231,15 @@
<v-table class="course-table" density="comfortable">
<thead>
<tr>
<th class="day-col bg-primary text-white text-center">星期</th>
<th class="bg-primary text-white text-center">運動內容</th>
<th class="time-col bg-primary text-white text-center">時間</th>
<th class="day-col bg-primary text-white text-center">
星期
</th>
<th class="bg-primary text-white text-center">
運動內容
</th>
<th class="time-col bg-primary text-white text-center">
時間
</th>
</tr>
</thead>
@@ -191,14 +249,18 @@
:key="row.day"
:class="{ 'bg-teal-lighten-5': row.day === todayDay }"
>
<td class="day-col text-center font-weight-bold text-primary">
<td
class="day-col text-center font-weight-bold text-primary"
>
{{ DAY_NAMES[row.day - 1] }}
</td>
<td class="text-body-medium text-wrap">{{ row.content }}</td>
<td class="text-body-medium text-wrap">
{{ row.content }}
</td>
<td class="time-col text-center text-body-medium">
{{ row.minutes === null ? '—' : `${row.minutes} 分` }}
{{ row.minutes === null ? "—" : `${row.minutes} 分` }}
</td>
</tr>
</tbody>
@@ -209,12 +271,21 @@
</v-card>
<v-card class="rounded-lg elevation-1 mt-4 overflow-hidden">
<v-expansion-panels v-model="scheduleTablePanel" flat variant="accordion">
<v-expansion-panels
v-model="scheduleTablePanel"
flat
variant="accordion"
>
<v-expansion-panel value="schedule">
<v-expansion-panel-title
class="course-table-panel-title text-title-medium font-weight-bold text-primary"
>
<v-icon class="mr-2" color="primary" icon="mdi-timer-outline" size="20" />
<v-icon
class="mr-2"
color="primary"
icon="mdi-timer-outline"
size="20"
/>
運動課表
</v-expansion-panel-title>
@@ -224,7 +295,9 @@
<v-table class="course-table" density="comfortable">
<thead>
<tr>
<th class="day-col bg-primary text-white text-center">星期</th>
<th class="day-col bg-primary text-white text-center">
星期
</th>
<th
v-for="slot in visibleSlots"
@@ -244,7 +317,9 @@
:key="row.day"
:class="{ 'bg-teal-lighten-5': row.day === todayDay }"
>
<td class="day-col text-center font-weight-bold text-primary">
<td
class="day-col text-center font-weight-bold text-primary"
>
{{ DAY_NAMES[row.day - 1] }}
</td>
@@ -253,8 +328,13 @@
:key="slot.key"
class="slot-cell text-body-medium text-wrap"
>
<div class="d-flex flex-column flex-md-row align-center ga-1 ga-md-3">
<v-avatar class="slot-avatar flex-shrink-0" rounded="lg">
<div
class="d-flex flex-column flex-md-row align-center ga-1 ga-md-3"
>
<v-avatar
class="slot-avatar flex-shrink-0"
rounded="lg"
>
<v-img
:alt="`${DAY_NAMES[row.day - 1]}${slot.label}課表插圖`"
:src="scheduleCardImage(row.day, slot.key)"
@@ -273,7 +353,10 @@
</v-card>
<v-card class="rounded-lg elevation-1 mt-4 overflow-hidden">
<v-img :alt="`${store.groupMeta.label}課表示意圖`" :src="groupIllustration" />
<v-img
:alt="`${store.groupMeta.label}課表示意圖`"
:src="groupIllustration"
/>
</v-card>
</template>
</template>
@@ -281,102 +364,124 @@
</template>
<script setup lang="ts">
import type { FitnessGroup, TimeSlot, YesNo } from '@/api/types'
import { computed, onMounted, ref } from 'vue'
import highIllustration from '@/assets/course/high.png'
import lowIllustration from '@/assets/course/low.png'
import mediumIllustration from '@/assets/course/medium.png'
import Layout from '@/components/layout/DefaultLayout.vue'
import { COURSE_DETAIL } from '@/data/courseDetail'
import { useCourseStore } from '@/stores/course'
import type { FitnessGroup, TimeSlot, YesNo } from "@/api/types";
import { computed, onMounted, ref } from "vue";
import highIllustration from "@/assets/course/high.png";
import lowIllustration from "@/assets/course/low.png";
import mediumIllustration from "@/assets/course/medium.png";
import Layout from "@/components/layout/DefaultLayout.vue";
import { COURSE_DETAIL } from "@/data/courseDetail";
import { useCourseStore } from "@/stores/course";
const store = useCourseStore()
const store = useCourseStore();
// 運動時間建議與課程說明的靜態內容,依組別對應
const detail = computed(() => COURSE_DETAIL[store.group])
const detail = computed(() => COURSE_DETAIL[store.group]);
// 課程說明預設只展開第一個面板(族群特徵)
const openPanels = ref([0])
const openPanels = ref([0]);
// 兩張表格預設展開,使用者可分別收合以減少頁面長度。
const durationTablePanel = ref<string | null>('duration')
const scheduleTablePanel = ref<string | null>('schedule')
const durationTablePanel = ref<string | null>("duration");
const scheduleTablePanel = ref<string | null>("schedule");
const GROUP_ILLUSTRATIONS: Record<FitnessGroup, string> = {
low: lowIllustration,
medium: mediumIllustration,
high: highIllustration,
}
};
const groupIllustration = computed(() => GROUP_ILLUSTRATIONS[store.group])
const groupIllustration = computed(() => GROUP_ILLUSTRATIONS[store.group]);
// 時段篩選功能尚未開放,UI 先隱藏;之後要開放時把這個常數改回 true 即可
const SHOW_SLOT_FILTER = false
const SHOW_SLOT_FILTER = false;
const DAY_NAMES = ['一', '二', '三', '四', '五', '六', '日']
const DAY_NAMES = ["一", "二", "三", "四", "五", "六", "日"];
// 課表小卡:檔名為「星期-時段」,逐一匯入 21 張圖並依 day/slot 查表取用
const scheduleCardModules = import.meta.glob<{ default: string }>(
'../assets/course/schedule/*.png',
"../assets/course/schedule/*.png",
{ eager: true },
)
);
const SCHEDULE_CARD_DAY_KEYS = [
'monday',
'tuesday',
'wednesday',
'thursday',
'friday',
'saturday',
'sunday',
]
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday",
];
const SCHEDULE_CARD_SLOT_KEYS: Record<TimeSlot, string> = {
morning: 'morning',
noon: 'noon',
night: 'evening',
}
morning: "morning",
noon: "noon",
night: "evening",
};
const SCHEDULE_CARDS: Record<string, string> = Object.fromEntries(
Object.entries(scheduleCardModules).map(([path, module]) => [
path.replace(/^.*\/|\.png$/g, ''),
path.replace(/^.*\/|\.png$/g, ""),
module.default,
]),
)
);
function scheduleCardImage (day: number, slot: TimeSlot): string {
const key = `${SCHEDULE_CARD_DAY_KEYS[day - 1]}-${SCHEDULE_CARD_SLOT_KEYS[slot]}`
return SCHEDULE_CARDS[key]
function scheduleCardImage(day: number, slot: TimeSlot): string {
const key = `${SCHEDULE_CARD_DAY_KEYS[day - 1]}-${SCHEDULE_CARD_SLOT_KEYS[slot]}`;
return SCHEDULE_CARDS[key];
}
const SLOTS: { key: TimeSlot, label: string, icon: string, headerClass: string }[] = [
{ key: 'morning', label: '早上', icon: 'mdi-weather-sunset-up', headerClass: 'bg-deep-orange' },
{ key: 'noon', label: '中午', icon: 'mdi-white-balance-sunny', headerClass: 'bg-amber-darken-2' },
{ key: 'night', label: '晚上', icon: 'mdi-weather-night', headerClass: 'bg-deep-purple' },
]
const SLOTS: {
key: TimeSlot;
label: string;
icon: string;
headerClass: string;
}[] = [
{
key: "morning",
label: "早上",
icon: "mdi-weather-sunset-up",
headerClass: "bg-deep-orange",
},
{
key: "noon",
label: "中午",
icon: "mdi-white-balance-sunny",
headerClass: "bg-amber-darken-2",
},
{
key: "night",
label: "晚上",
icon: "mdi-weather-night",
headerClass: "bg-deep-purple",
},
];
// 依目前選取的時段決定表格要顯示哪幾欄,順序固定為早上/中午/晚上
const visibleSlots = computed(() => SLOTS.filter(slot => store.selectedSlots.includes(slot.key)))
const visibleSlots = computed(() =>
SLOTS.filter((slot) => store.selectedSlots.includes(slot.key)),
);
// 今天對應的星期幾,換算成與 CourseRow.day 相同的規則(1 = 週一 … 7 = 週日)
const todayDay = computed(() => {
const jsDay = new Date().getDay()
return jsDay === 0 ? 7 : jsDay
})
const jsDay = new Date().getDay();
return jsDay === 0 ? 7 : jsDay;
});
// v-btn-toggle 以陣列表達勾選狀態,store 則以 Y/N 保存,兩者在此橋接
const selectedSlots = computed<TimeSlot[]>({
get: () => store.selectedSlots,
set: value => {
set: (value) => {
for (const slot of SLOTS) {
const next: YesNo = value.includes(slot.key) ? 'Y' : 'N'
store.setSlot(slot.key, next)
const next: YesNo = value.includes(slot.key) ? "Y" : "N";
store.setSlot(slot.key, next);
}
},
})
});
onMounted(() => {
store.loadAll()
})
store.loadAll();
});
</script>
<style scoped>