refactor: update row density to compact in various components for improved layout
This commit is contained in:
@@ -207,7 +207,7 @@ v-model="confirmDeleteCourseVisible" confirm-color="error"
|
||||
<v-select
|
||||
v-model="addCourseForm.name" class="mb-3" density="comfortable" :items="availableCourses"
|
||||
label="課程名稱" variant="outlined" @update:model-value="handleAddCourseNameSelect" />
|
||||
<v-row dense>
|
||||
<v-row density="compact">
|
||||
<v-col cols="6">
|
||||
<v-text-field
|
||||
v-model.number="addCourseForm.credits" density="comfortable" hide-spin-buttons label="學分"
|
||||
|
||||
@@ -1,31 +1,62 @@
|
||||
<template>
|
||||
<mnt-page-cards
|
||||
:search-panel-open="searchPanelOpen" :title="`單筆資料維護示範`"
|
||||
@create="openAddDialog" @toggle-search="searchPanelOpen = !searchPanelOpen">
|
||||
:search-panel-open="searchPanelOpen"
|
||||
:title="`單筆資料維護示範`"
|
||||
@create="openAddDialog"
|
||||
@toggle-search="searchPanelOpen = !searchPanelOpen"
|
||||
>
|
||||
<template #search-fields>
|
||||
<v-col cols="12" md="2">
|
||||
<div class="text-body-2 text-medium-emphasis pl-2">學號</div>
|
||||
<v-text-field
|
||||
v-model="search.studentId" density="compact" hide-details placeholder="例如:S2024001"
|
||||
variant="outlined" />
|
||||
v-model="search.studentId"
|
||||
density="compact"
|
||||
hide-details
|
||||
placeholder="例如:S2024001"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="2">
|
||||
<div class="text-body-2 text-medium-emphasis pl-2">姓名</div>
|
||||
<v-text-field v-model="search.name" density="compact" hide-details placeholder="例如:王小明" variant="outlined" />
|
||||
<v-text-field
|
||||
v-model="search.name"
|
||||
density="compact"
|
||||
hide-details
|
||||
placeholder="例如:王小明"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="2">
|
||||
<div class="text-body-2 text-medium-emphasis pl-2">系所</div>
|
||||
<v-select v-model="search.department" density="compact" hide-details :items="departments" variant="outlined" />
|
||||
<v-select
|
||||
v-model="search.department"
|
||||
density="compact"
|
||||
hide-details
|
||||
:items="departments"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="2">
|
||||
<div class="text-body-2 text-medium-emphasis pl-2">年級</div>
|
||||
<v-select
|
||||
v-model="search.grade" density="compact" hide-details item-title="title" item-value="value"
|
||||
:items="gradeOptions" variant="outlined" />
|
||||
v-model="search.grade"
|
||||
density="compact"
|
||||
hide-details
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:items="gradeOptions"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="2">
|
||||
<div class="text-body-2 text-medium-emphasis pl-2">狀態</div>
|
||||
<v-select v-model="search.status" density="compact" hide-details :items="statuses" variant="outlined" />
|
||||
<v-select
|
||||
v-model="search.status"
|
||||
density="compact"
|
||||
hide-details
|
||||
:items="statuses"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col class="d-flex justify-end align-end flex-grow-1 ga-2" cols="12" md="auto">
|
||||
<v-btn :prepend-icon="mdiBroom" variant="text" @click="resetSearch">清除</v-btn>
|
||||
@@ -34,9 +65,17 @@ v-model="search.grade" density="compact" hide-details item-title="title" item-va
|
||||
</template>
|
||||
<template #table>
|
||||
<v-data-table
|
||||
class="student-table" density="compact" fixed-header :headers="tableHeaders"
|
||||
height="100%" :items="students" :items-per-page="10" items-per-page-text="每頁筆數" page-text="第 {0}-{1} 筆 / 共 {2} 筆"
|
||||
:row-props="rowProps">
|
||||
class="student-table"
|
||||
density="compact"
|
||||
fixed-header
|
||||
:headers="tableHeaders"
|
||||
height="100%"
|
||||
:items="students"
|
||||
:items-per-page="10"
|
||||
items-per-page-text="每頁筆數"
|
||||
page-text="第 {0}-{1} 筆 / 共 {2} 筆"
|
||||
:row-props="rowProps"
|
||||
>
|
||||
<template #[`item.grade`]="{ item }">
|
||||
{{ gradeLabel(item.grade) }}
|
||||
</template>
|
||||
@@ -47,15 +86,31 @@ class="student-table" density="compact" fixed-header :headers="tableHeaders"
|
||||
</template>
|
||||
<template #[`item.actions`]="{ item }">
|
||||
<div class="d-flex ga-2">
|
||||
<v-btn color="info" :prepend-icon="mdiEye" size="small" variant="text" @click="openViewDialog(item)">
|
||||
<v-btn
|
||||
color="info"
|
||||
:prepend-icon="mdiEye"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="openViewDialog(item)"
|
||||
>
|
||||
檢視
|
||||
</v-btn>
|
||||
<v-btn color="primary" :prepend-icon="mdiPencil" size="small" variant="text" @click="openEditDialog(item)">
|
||||
<v-btn
|
||||
color="primary"
|
||||
:prepend-icon="mdiPencil"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="openEditDialog(item)"
|
||||
>
|
||||
修改
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error" :prepend-icon="mdiDelete" size="small" variant="text"
|
||||
@click="requestDeleteConfirmation(item)">
|
||||
color="error"
|
||||
:prepend-icon="mdiDelete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="requestDeleteConfirmation(item)"
|
||||
>
|
||||
刪除
|
||||
</v-btn>
|
||||
</div>
|
||||
@@ -68,106 +123,220 @@ color="error" :prepend-icon="mdiDelete" size="small" variant="text"
|
||||
<teleport to="body">
|
||||
<!-- 包成元件需要傳高度寬度給dialog-panel -->
|
||||
<v-overlay
|
||||
class="dialog-overlay" :close-on-content-click="false" :model-value="dialogVisible" scrim="rgba(0, 0, 0, 0.45)"
|
||||
scroll-strategy="block" @update:model-value="handleDialogVisibility">
|
||||
class="dialog-overlay"
|
||||
:close-on-content-click="false"
|
||||
:model-value="dialogVisible"
|
||||
scrim="rgba(0, 0, 0, 0.45)"
|
||||
scroll-strategy="block"
|
||||
@update:model-value="handleDialogVisibility"
|
||||
>
|
||||
<div class="dialog-panel">
|
||||
<mnt-dialog-card
|
||||
content-class="pa-2 flex-grow-1 overflow-y-auto" :dialog-subtitle="dialogSubtitle" :dialog-title="dialogTitle"
|
||||
:is-edit-mode="isEditMode" :is-view-mode="isViewMode" width="100%">
|
||||
content-class="pa-2 flex-grow-1 overflow-y-auto"
|
||||
:dialog-subtitle="dialogSubtitle"
|
||||
:dialog-title="dialogTitle"
|
||||
:is-edit-mode="isEditMode"
|
||||
:is-view-mode="isViewMode"
|
||||
width="100%"
|
||||
>
|
||||
<template #toolbar>
|
||||
<mnt-record-nav-toolbar
|
||||
edit-label="進入編輯" first-label="第一筆"
|
||||
:has-next-record="hasNextRecord" :has-prev-record="hasPrevRecord" :is-edit-mode="isEditMode" :is-view-mode="isViewMode"
|
||||
last-label="最後一筆" view-label="回到檢視" @first="openEdgeRecord('first')" @last="openEdgeRecord('last')"
|
||||
@next="openAdjacentRecord('next')" @prev="openAdjacentRecord('prev')" @switch-to-edit="switchToEditMode"
|
||||
@switch-to-view="switchToViewMode" />
|
||||
edit-label="進入編輯"
|
||||
first-label="第一筆"
|
||||
:has-next-record="hasNextRecord"
|
||||
:has-prev-record="hasPrevRecord"
|
||||
:is-edit-mode="isEditMode"
|
||||
:is-view-mode="isViewMode"
|
||||
last-label="最後一筆"
|
||||
view-label="回到檢視"
|
||||
@first="openEdgeRecord('first')"
|
||||
@last="openEdgeRecord('last')"
|
||||
@next="openAdjacentRecord('next')"
|
||||
@prev="openAdjacentRecord('prev')"
|
||||
@switch-to-edit="switchToEditMode"
|
||||
@switch-to-view="switchToViewMode"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<!-- 儲存前驗證錯誤摘要 -->
|
||||
<v-alert v-if="errorSummary.length > 0 && !isLoading" class="mb-4" type="error" variant="tonal">
|
||||
<v-alert
|
||||
v-if="errorSummary.length > 0 && !isLoading"
|
||||
class="mb-4"
|
||||
type="error"
|
||||
variant="tonal"
|
||||
>
|
||||
<div class="text-subtitle-2 mb-2">請先修正以下問題</div>
|
||||
<div class="d-flex flex-column ga-1">
|
||||
<v-btn
|
||||
v-for="error in errorSummary" :key="error.field" color="error" size="small" variant="text"
|
||||
@click="scrollToField(error.field)">
|
||||
v-for="error in errorSummary"
|
||||
:key="error.field"
|
||||
color="error"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="scrollToField(error.field)"
|
||||
>
|
||||
{{ error.message }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-alert>
|
||||
|
||||
<!-- 編輯/檢視載入中骨架 -->
|
||||
<v-skeleton-loader v-if="isLoading" class="mt-4" type="subtitle,paragraph" width="100%" />
|
||||
<v-skeleton-loader
|
||||
v-if="isLoading"
|
||||
class="mt-4"
|
||||
type="subtitle,paragraph"
|
||||
width="100%"
|
||||
/>
|
||||
|
||||
<!-- 表單:檢視模式使用 readonly,避免 focus 狀態 -->
|
||||
<v-form v-else :class="{ 'form-readonly': isFormReadonly }" @submit.prevent="requestSaveConfirmation">
|
||||
<v-row dense>
|
||||
<v-form
|
||||
v-else
|
||||
:class="{ 'form-readonly': isFormReadonly }"
|
||||
@submit.prevent="requestSaveConfirmation"
|
||||
>
|
||||
<v-row density="compact">
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
id="field-studentId" v-model="form.studentId" density="comfortable" :disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.studentId" label="學號" placeholder="例如:S2024008"
|
||||
:readonly="isFormReadonly" variant="outlined"
|
||||
@update:model-value="clearFieldError('studentId')" />
|
||||
id="field-studentId"
|
||||
v-model="form.studentId"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.studentId"
|
||||
label="學號"
|
||||
placeholder="例如:S2024008"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('studentId')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
id="field-name" v-model="form.name" density="comfortable" :disabled="isFormLocked" :error-messages="fieldErrors.name"
|
||||
label="姓名" placeholder="例如:陳怡君" :readonly="isFormReadonly"
|
||||
variant="outlined" @update:model-value="clearFieldError('name')" />
|
||||
id="field-name"
|
||||
v-model="form.name"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.name"
|
||||
label="姓名"
|
||||
placeholder="例如:陳怡君"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('name')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
id="field-department" v-model="form.department" density="comfortable" :disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.department" :items="departments" label="系所"
|
||||
:readonly="isFormReadonly" variant="outlined"
|
||||
@update:model-value="clearFieldError('department')" />
|
||||
id="field-department"
|
||||
v-model="form.department"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.department"
|
||||
:items="departments"
|
||||
label="系所"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('department')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
id="field-grade" v-model="form.grade" density="comfortable" :disabled="isFormLocked" :error-messages="fieldErrors.grade"
|
||||
item-title="title" item-value="value" :items="gradeOptions" label="年級"
|
||||
:readonly="isFormReadonly" variant="outlined"
|
||||
@update:model-value="clearFieldError('grade')" />
|
||||
id="field-grade"
|
||||
v-model="form.grade"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.grade"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:items="gradeOptions"
|
||||
label="年級"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('grade')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
id="field-enrollYear" v-model="form.enrollYear" density="comfortable" :disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.enrollYear" :items="enrollYears" label="入學年度"
|
||||
:readonly="isFormReadonly" variant="outlined"
|
||||
@update:model-value="clearFieldError('enrollYear')" />
|
||||
id="field-enrollYear"
|
||||
v-model="form.enrollYear"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.enrollYear"
|
||||
:items="enrollYears"
|
||||
label="入學年度"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('enrollYear')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
id="field-credits" v-model.number="form.credits" density="comfortable" :disabled="isFormLocked" :error-messages="fieldErrors.credits"
|
||||
label="已修學分" min="0" :readonly="isFormReadonly"
|
||||
type="number" variant="outlined"
|
||||
@update:model-value="clearFieldError('credits')" />
|
||||
id="field-credits"
|
||||
v-model.number="form.credits"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.credits"
|
||||
label="已修學分"
|
||||
min="0"
|
||||
:readonly="isFormReadonly"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('credits')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
id="field-advisor" v-model="form.advisor" density="comfortable" :disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.advisor" label="指導老師" placeholder="例如:林教授"
|
||||
:readonly="isFormReadonly" variant="outlined"
|
||||
@update:model-value="clearFieldError('advisor')" />
|
||||
id="field-advisor"
|
||||
v-model="form.advisor"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.advisor"
|
||||
label="指導老師"
|
||||
placeholder="例如:林教授"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('advisor')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
id="field-email" v-model="form.email" density="comfortable" :disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.email" label="Email" placeholder="name@school.edu"
|
||||
:readonly="isFormReadonly" variant="outlined"
|
||||
@update:model-value="clearFieldError('email')" />
|
||||
id="field-email"
|
||||
v-model="form.email"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.email"
|
||||
label="Email"
|
||||
placeholder="name@school.edu"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('email')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-text-field
|
||||
id="field-phone" v-model="form.phone" density="comfortable" :disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.phone" label="電話" placeholder="例如:02-2345-6789"
|
||||
:readonly="isFormReadonly" variant="outlined"
|
||||
@update:model-value="clearFieldError('phone')" />
|
||||
id="field-phone"
|
||||
v-model="form.phone"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.phone"
|
||||
label="電話"
|
||||
placeholder="例如:02-2345-6789"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('phone')"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-select
|
||||
id="field-status" v-model="form.status" density="comfortable" :disabled="isFormLocked" :error-messages="fieldErrors.status"
|
||||
:items="statuses" label="狀態" :readonly="isFormReadonly"
|
||||
variant="outlined" @update:model-value="clearFieldError('status')" />
|
||||
id="field-status"
|
||||
v-model="form.status"
|
||||
density="comfortable"
|
||||
:disabled="isFormLocked"
|
||||
:error-messages="fieldErrors.status"
|
||||
:items="statuses"
|
||||
label="狀態"
|
||||
:readonly="isFormReadonly"
|
||||
variant="outlined"
|
||||
@update:model-value="clearFieldError('status')"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-form>
|
||||
@@ -175,12 +344,23 @@ id="field-status" v-model="form.status" density="comfortable" :disabled="isFormL
|
||||
<template #actions>
|
||||
<v-spacer />
|
||||
<v-btn :disabled="isSaving" variant="text" @click="requestCloseDialog">取消</v-btn>
|
||||
<v-btn v-if="isEditMode" color="error" :disabled="isSaving" variant="tonal" @click="requestDeleteCurrent">
|
||||
<v-btn
|
||||
v-if="isEditMode"
|
||||
color="error"
|
||||
:disabled="isSaving"
|
||||
variant="tonal"
|
||||
@click="requestDeleteCurrent"
|
||||
>
|
||||
刪除
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="!isViewMode" color="primary" :disabled="!isDirty || isLoading" :loading="isSaving"
|
||||
variant="flat" @click="requestSaveConfirmation">
|
||||
v-if="!isViewMode"
|
||||
color="primary"
|
||||
:disabled="!isDirty || isLoading"
|
||||
:loading="isSaving"
|
||||
variant="flat"
|
||||
@click="requestSaveConfirmation"
|
||||
>
|
||||
儲存
|
||||
</v-btn>
|
||||
<v-btn v-else color="primary" variant="flat" @click="requestCloseDialog">關閉</v-btn>
|
||||
@@ -190,8 +370,6 @@ v-if="!isViewMode" color="primary" :disabled="!isDirty || isLoading" :loading="i
|
||||
</v-overlay>
|
||||
</teleport>
|
||||
|
||||
|
||||
|
||||
<maintenance-crud-dialogs
|
||||
:close-visible="confirmCloseVisible"
|
||||
:delete-visible="confirmDeleteVisible"
|
||||
@@ -247,8 +425,20 @@ const { smAndUp } = useDisplay()
|
||||
|
||||
// 表格欄位設定(含固定欄與排序)
|
||||
const tableHeaders = computed(() => [
|
||||
{ title: '學號', key: 'studentId', sortable: true, fixed: smAndUp.value && 'start' as const, width: 120 },
|
||||
{ title: '姓名', key: 'name', sortable: true, fixed: smAndUp.value && 'start' as const, width: 100 },
|
||||
{
|
||||
title: '學號',
|
||||
key: 'studentId',
|
||||
sortable: true,
|
||||
fixed: smAndUp.value && ('start' as const),
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'name',
|
||||
sortable: true,
|
||||
fixed: smAndUp.value && ('start' as const),
|
||||
width: 100,
|
||||
},
|
||||
{ title: '系所', key: 'department', sortable: true, width: 140 },
|
||||
{ title: '年級', key: 'grade', sortable: true, width: 90 },
|
||||
{ title: '入學年度', key: 'enrollYear', sortable: true, width: 110 },
|
||||
@@ -257,7 +447,14 @@ const tableHeaders = computed(() => [
|
||||
{ title: '電話', key: 'phone', sortable: true, width: 140 },
|
||||
{ title: '指導老師', key: 'advisor', sortable: true, width: 110 },
|
||||
{ title: '狀態', key: 'status', sortable: true, width: 90 },
|
||||
{ title: '操作', key: 'actions', sortable: false, fixed: smAndUp.value && 'end' as const, width: 'auto', cellProps: { class: 'px-0 bg-background' } },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'actions',
|
||||
sortable: false,
|
||||
fixed: smAndUp.value && ('end' as const),
|
||||
width: 'auto',
|
||||
cellProps: { class: 'px-0 bg-background' },
|
||||
},
|
||||
])
|
||||
|
||||
// 查詢條件(示意用,未接 API)
|
||||
@@ -372,7 +569,7 @@ const {
|
||||
const isFormReadonly = computed(() => isViewMode.value)
|
||||
|
||||
// 重設查詢條件
|
||||
function resetSearch () {
|
||||
function resetSearch() {
|
||||
search.value = {
|
||||
studentId: '',
|
||||
name: '',
|
||||
@@ -383,7 +580,7 @@ function resetSearch () {
|
||||
}
|
||||
|
||||
// 新增:開啟彈窗,使用預設值
|
||||
function openAddDialog () {
|
||||
function openAddDialog() {
|
||||
loadSequence.value += 1
|
||||
dialogMode.value = 'create'
|
||||
editingId.value = null
|
||||
@@ -393,7 +590,7 @@ function openAddDialog () {
|
||||
}
|
||||
|
||||
// 編輯:先開彈窗,資料載入後填入
|
||||
function openEditDialog (student: StudentRecord) {
|
||||
function openEditDialog(student: StudentRecord) {
|
||||
loadSequence.value += 1
|
||||
const sequence = loadSequence.value
|
||||
dialogMode.value = 'edit'
|
||||
@@ -421,7 +618,7 @@ function openEditDialog (student: StudentRecord) {
|
||||
}
|
||||
|
||||
// 檢視:只讀模式並預設展開所有分組
|
||||
function openViewDialog (student: StudentRecord) {
|
||||
function openViewDialog(student: StudentRecord) {
|
||||
loadSequence.value += 1
|
||||
const sequence = loadSequence.value
|
||||
dialogMode.value = 'view'
|
||||
@@ -449,7 +646,7 @@ function openViewDialog (student: StudentRecord) {
|
||||
}
|
||||
|
||||
// 先檢核再提示儲存確認
|
||||
async function requestSaveConfirmation () {
|
||||
async function requestSaveConfirmation() {
|
||||
if (isSaving.value || isLoading.value || !isDirty.value || isViewMode.value) return
|
||||
clearAllErrors()
|
||||
|
||||
@@ -468,13 +665,13 @@ async function requestSaveConfirmation () {
|
||||
}
|
||||
|
||||
// 儲存確認後才真正送出
|
||||
function confirmSave () {
|
||||
function confirmSave() {
|
||||
confirmSaveVisible.value = false
|
||||
saveStudent()
|
||||
}
|
||||
|
||||
// 寫入資料(Demo:直接更新列表)
|
||||
async function saveStudent () {
|
||||
async function saveStudent() {
|
||||
if (isSaving.value || isLoading.value) return
|
||||
isSaving.value = true
|
||||
await new Promise((resolve) => setTimeout(resolve, 450))
|
||||
@@ -508,12 +705,11 @@ async function saveStudent () {
|
||||
}, 1600)
|
||||
}
|
||||
|
||||
function scrollToField (field: string) {
|
||||
function scrollToField(field: string) {
|
||||
const target = document.getElementById(`field-${field}`)
|
||||
if (!target) return
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
Reference in New Issue
Block a user