Files
skt-vuetify-templates/src/components/maintenance/master-detail-c/MasterDetailCCourseMobilePanel.vue
T

174 lines
6.2 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.
<template>
<v-card border class="d-flex flex-column h-100 rounded-0" flat width="100%">
<v-toolbar color="transparent" density="compact" flat>
<v-btn :icon="mdiArrowLeft" size="small" variant="text" @click="$emit('close')" />
<v-toolbar-title class="text-subtitle-1 font-weight-bold">
{{ semester?.semesterName || '課程明細' }}
</v-toolbar-title>
</v-toolbar>
<v-divider />
<v-card-text class="pa-0 flex-grow-1 overflow-y-auto bg-grey-lighten-5">
<div v-if="semester" class="pa-4 d-flex flex-column ga-4">
<div class="d-flex flex-column ga-3">
<v-card class="py-2 px-3" variant="outlined">
<div class="text-caption text-medium-emphasis">學期平均</div>
<div class="text-h6 font-weight-bold text-primary">{{ semester.average }}</div>
</v-card>
<v-card class="py-2 px-3" variant="outlined">
<div class="text-caption text-medium-emphasis">班級排名</div>
<div class="text-h6 font-weight-bold">{{ semester.rank }}</div>
</v-card>
<v-card class="py-2 px-3" variant="outlined">
<div class="text-caption text-medium-emphasis">總學分</div>
<div class="text-h6 font-weight-bold">{{ totalCredits }}</div>
</v-card>
</div>
<div class="d-flex align-center">
<div>
<div class="text-subtitle-2 font-weight-bold">課程列表</div>
<div class="text-caption text-medium-emphasis">
手機版改用卡片式維護不使用扁平表格
</div>
</div>
<v-spacer />
<v-btn
v-if="!isViewMode"
color="primary"
:disabled="isFormLocked"
:prepend-icon="mdiPlus"
size="small"
variant="text"
@click="$emit('add-course', semester.id)"
>
加入課程
</v-btn>
</div>
<template v-if="semester.courses.length > 0">
<v-card
v-for="(course, idx) in semester.courses"
:key="`${course.code}-${idx}`"
class="pa-3"
variant="outlined"
>
<template v-if="isViewMode">
<div class="d-flex align-start justify-space-between ga-3">
<div>
<div class="text-body-1 font-weight-medium">{{ course.name }}</div>
<div class="text-caption text-medium-emphasis">{{ course.code }}</div>
</div>
<v-chip
:color="course.score < 60 ? 'error' : 'success'"
size="small"
variant="tonal"
>
{{ course.score }}
</v-chip>
</div>
<div class="d-flex ga-4 mt-3 text-body-2">
<div>學分 {{ course.credits }}</div>
</div>
</template>
<template v-else>
<div class="d-flex align-center mb-3">
<div class="text-subtitle-2 font-weight-bold">課程 {{ idx + 1 }}</div>
<v-spacer />
<v-btn
color="error"
:disabled="isFormLocked"
:icon="mdiDelete"
size="small"
variant="text"
@click="$emit('delete-course', semester.id, idx)"
/>
</div>
<div class="d-flex flex-column ga-3">
<v-text-field
density="comfortable"
:disabled="isFormLocked"
hide-details
label="課程名稱"
:model-value="course.name"
variant="outlined"
@update:model-value="(value) => updateCourse(idx, { name: String(value) })"
/>
<v-text-field
density="comfortable"
:disabled="isFormLocked"
hide-details
label="代碼"
:model-value="course.code"
variant="outlined"
@update:model-value="(value) => updateCourse(idx, { code: String(value) })"
/>
<v-text-field
density="comfortable"
:disabled="isFormLocked"
hide-details
label="學分"
:model-value="course.credits"
type="number"
variant="outlined"
@update:model-value="(value) => updateCourse(idx, { credits: Number(value) || 0 })"
/>
<v-text-field
density="comfortable"
:disabled="isFormLocked"
hide-details
label="分數"
:model-value="course.score"
type="number"
variant="outlined"
@update:model-value="(value) => updateCourse(idx, { score: Number(value) || 0 })"
/>
</div>
</template>
</v-card>
</template>
<div v-else class="text-center text-medium-emphasis py-6 border border-dashed rounded">
尚無課程資料
</div>
</div>
</v-card-text>
</v-card>
</template>
<script setup lang="ts">
import type { CourseRecord, SemesterRecord } from '@/stores/semesters'
import { mdiArrowLeft, mdiDelete, mdiPlus } from '@mdi/js'
import { computed } from 'vue'
const props = defineProps<{
semester: SemesterRecord | null
isViewMode: boolean
isFormLocked: boolean
}>()
const emit = defineEmits<{
(event: 'close'): void
(event: 'add-course', semesterId: number): void
(
event: 'update-course',
semesterId: number,
courseIndex: number,
payload: Partial<CourseRecord>
): void
(event: 'delete-course', semesterId: number, courseIndex: number): void
}>()
const totalCredits = computed(
() => props.semester?.courses.reduce((sum, course) => sum + course.credits, 0) ?? 0
)
function updateCourse (courseIndex: number, payload: Partial<CourseRecord>) {
if (!props.semester) return
emit('update-course', props.semester.id, courseIndex, payload)
}
</script>