feat: add SingleRecordMnt component for student record maintenance with search, add, edit, view, and delete functionalities
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<v-row align="center" class="pa-4" no-gutters v-bind="$attrs">
|
||||
<span v-if="title">{{ title }}</span>
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<v-btn
|
||||
v-if="showCreate"
|
||||
class="mr-4"
|
||||
color="primary"
|
||||
prepend-icon="mdi-plus"
|
||||
@click="$emit('create')"
|
||||
>
|
||||
{{ createBtnText }}
|
||||
</v-btn>
|
||||
|
||||
<v-tooltip :disabled="!searchToggleTooltipText" location="top" :text="searchToggleTooltipText">
|
||||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
v-if="showSearchToggle"
|
||||
v-bind="props"
|
||||
density="comfortable"
|
||||
icon
|
||||
variant="text"
|
||||
@click="$emit('toggle-search')"
|
||||
>
|
||||
<v-icon :color="searchVisible ? 'primary-variant' : undefined"> mdi-magnify </v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<v-tooltip :disabled="!refreshTooltipText" location="top" :text="refreshTooltipText">
|
||||
<template #activator="{ props }">
|
||||
<v-btn v-bind="props" density="comfortable" icon variant="text" @click="$emit('refresh')">
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
|
||||
<v-menu v-if="settingsItems && settingsItems.length > 0">
|
||||
<template #activator="{ props: menuProps }">
|
||||
<v-tooltip :disabled="!settingsTooltipText" location="top" :text="settingsTooltipText">
|
||||
<template #activator="{ props: tooltipProps }">
|
||||
<v-btn
|
||||
v-bind="{ ...menuProps, ...tooltipProps }"
|
||||
density="comfortable"
|
||||
icon
|
||||
variant="text"
|
||||
@click="$emit('settings')"
|
||||
>
|
||||
<v-icon>mdi-cog</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-tooltip>
|
||||
</template>
|
||||
|
||||
<v-list density="compact">
|
||||
<v-list-item class="py-0">
|
||||
<v-checkbox
|
||||
color="primary"
|
||||
density="compact"
|
||||
:disabled="selectAllChecked"
|
||||
hide-details
|
||||
:indeterminate="selectAllIndeterminate"
|
||||
label="全選"
|
||||
:model-value="selectAllChecked"
|
||||
@update:model-value="toggleSelectAll"
|
||||
/>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item v-for="item in settingsItems" :key="item.key" class="py-0">
|
||||
<v-checkbox
|
||||
color="primary"
|
||||
density="compact"
|
||||
hide-details
|
||||
:label="item.label"
|
||||
:model-value="settingsSelectedKeys"
|
||||
:value="item.key"
|
||||
@update:model-value="updateSettingsSelectedKeys"
|
||||
/>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</v-row>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, toRefs } from 'vue'
|
||||
|
||||
interface SettingsItem {
|
||||
key: string
|
||||
label: string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
createBtnText?: string
|
||||
showCreate?: boolean
|
||||
showSearchToggle?: boolean
|
||||
searchVisible?: boolean
|
||||
searchToggleTooltipText?: string
|
||||
refreshTooltipText?: string
|
||||
settingsTooltipText?: string
|
||||
settingsItems?: SettingsItem[]
|
||||
settingsSelectedKeys?: string[]
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
createBtnText: '新增',
|
||||
showCreate: true,
|
||||
showSearchToggle: false,
|
||||
searchVisible: true,
|
||||
searchToggleTooltipText: '顯示/隱藏搜尋條件',
|
||||
refreshTooltipText: '更新',
|
||||
settingsTooltipText: '欄位設定',
|
||||
settingsItems: () => [],
|
||||
settingsSelectedKeys: () => [],
|
||||
})
|
||||
|
||||
const { settingsItems, settingsSelectedKeys } = toRefs(props)
|
||||
|
||||
const emit = defineEmits([
|
||||
'create',
|
||||
'refresh',
|
||||
'settings',
|
||||
'toggle-search',
|
||||
'update:settingsSelectedKeys',
|
||||
])
|
||||
|
||||
const allSettingsKeys = computed(() => settingsItems.value.map((i) => i.key))
|
||||
|
||||
const selectAllChecked = computed(() => {
|
||||
if (allSettingsKeys.value.length === 0) {
|
||||
return false
|
||||
}
|
||||
return allSettingsKeys.value.every((k) => settingsSelectedKeys.value.includes(k))
|
||||
})
|
||||
|
||||
const selectAllIndeterminate = computed(() => {
|
||||
if (allSettingsKeys.value.length === 0) {
|
||||
return false
|
||||
}
|
||||
const selectedCount = allSettingsKeys.value.filter((k) =>
|
||||
settingsSelectedKeys.value.includes(k)
|
||||
).length
|
||||
return selectedCount > 0 && selectedCount < allSettingsKeys.value.length
|
||||
})
|
||||
|
||||
function toggleSelectAll (checked: unknown) {
|
||||
const current = Array.isArray(settingsSelectedKeys.value) ? settingsSelectedKeys.value : []
|
||||
const nonSettingsKeys = current.filter((k) => !allSettingsKeys.value.includes(k))
|
||||
|
||||
emit(
|
||||
'update:settingsSelectedKeys',
|
||||
checked ? [...nonSettingsKeys, ...allSettingsKeys.value] : nonSettingsKeys
|
||||
)
|
||||
}
|
||||
|
||||
function updateSettingsSelectedKeys (value: unknown) {
|
||||
emit('update:settingsSelectedKeys', Array.isArray(value) ? value : [])
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user