162 lines
4.5 KiB
Vue
162 lines
4.5 KiB
Vue
<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>
|