refactor: replace common confirm dialogs with maintenance CRUD dialogs and streamline form handling in MasterDetailMntC.vue and SingleRecordMnt.vue
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch, type Ref } from 'vue'
|
||||
import type { AdminLayoutMenuItem } from '@/components/layouts/sk-admin-layout/types'
|
||||
|
||||
type ToggleSidebarPayload = {
|
||||
drawer: boolean
|
||||
rail: boolean
|
||||
}
|
||||
|
||||
type UseAdminLayoutStateOptions = {
|
||||
appBarRef: Ref<unknown>
|
||||
breadcrumbBarVisible: boolean | null
|
||||
emitUpdateBreadcrumbBarVisible: (value: boolean) => void
|
||||
emitUpdateFavoritesBarVisible: (value: boolean) => void
|
||||
emitUpdateIsRail: (value: boolean) => void
|
||||
favoritesBarVisible: boolean | null
|
||||
isMobile: Ref<boolean>
|
||||
isRail: boolean | null
|
||||
menuItems: AdminLayoutMenuItem[]
|
||||
onToggleSidebar: (payload: ToggleSidebarPayload) => void
|
||||
}
|
||||
|
||||
export function useAdminLayoutState (options: UseAdminLayoutStateOptions) {
|
||||
const drawer = ref(true)
|
||||
const mobileFavoritesPanel = ref(false)
|
||||
const mobileMenuPath = ref<AdminLayoutMenuItem[]>([])
|
||||
const localBreadcrumbBarVisible = ref(true)
|
||||
const localFavoritesBarVisible = ref(true)
|
||||
const localIsRail = ref(false)
|
||||
const opened = ref<string[]>([])
|
||||
const appBarHeight = ref(0)
|
||||
|
||||
const isRail = computed({
|
||||
get: () => (options.isRail ?? localIsRail.value),
|
||||
set: (value: boolean) => {
|
||||
if (options.isRail === null) {
|
||||
localIsRail.value = value
|
||||
return
|
||||
}
|
||||
|
||||
options.emitUpdateIsRail(value)
|
||||
},
|
||||
})
|
||||
|
||||
const showFavoritesBar = computed({
|
||||
get: () => (options.favoritesBarVisible ?? localFavoritesBarVisible.value),
|
||||
set: (value: boolean) => {
|
||||
if (options.favoritesBarVisible === null) {
|
||||
localFavoritesBarVisible.value = value
|
||||
return
|
||||
}
|
||||
|
||||
options.emitUpdateFavoritesBarVisible(value)
|
||||
},
|
||||
})
|
||||
|
||||
const showBreadcrumbBar = computed({
|
||||
get: () => (options.breadcrumbBarVisible ?? localBreadcrumbBarVisible.value),
|
||||
set: (value: boolean) => {
|
||||
if (options.breadcrumbBarVisible === null) {
|
||||
localBreadcrumbBarVisible.value = value
|
||||
return
|
||||
}
|
||||
|
||||
options.emitUpdateBreadcrumbBarVisible(value)
|
||||
},
|
||||
})
|
||||
|
||||
const mobileCurrentItems = computed(() =>
|
||||
mobileMenuPath.value.reduce(
|
||||
(items, currentItem) => currentItem?.subItems ?? [],
|
||||
options.menuItems || []
|
||||
)
|
||||
)
|
||||
|
||||
const mobileCurrentLevel = computed(() => mobileMenuPath.value.length + 1)
|
||||
|
||||
const mobileMenuLevels = computed(() =>
|
||||
Array.from({ length: mobileCurrentLevel.value }, (_, index) => ({
|
||||
level: index + 1,
|
||||
title: index === 0 ? '主選單' : (mobileMenuPath.value[index - 1]?.title ?? `第${index + 1}層`),
|
||||
}))
|
||||
)
|
||||
|
||||
function resetMobilePanels () {
|
||||
mobileFavoritesPanel.value = false
|
||||
mobileMenuPath.value = []
|
||||
}
|
||||
|
||||
function toggleSidebar () {
|
||||
if (options.isMobile.value) {
|
||||
drawer.value = !drawer.value
|
||||
} else {
|
||||
isRail.value = !isRail.value
|
||||
}
|
||||
|
||||
options.onToggleSidebar({
|
||||
drawer: drawer.value,
|
||||
rail: isRail.value,
|
||||
})
|
||||
}
|
||||
|
||||
function goToMobileLevel (level: number) {
|
||||
mobileFavoritesPanel.value = false
|
||||
mobileMenuPath.value = mobileMenuPath.value.slice(0, Math.max(0, level - 1))
|
||||
}
|
||||
|
||||
function openMobileFavoritesPanel () {
|
||||
mobileMenuPath.value = []
|
||||
mobileFavoritesPanel.value = true
|
||||
}
|
||||
|
||||
function handleMobileMenuClick (
|
||||
item: AdminLayoutMenuItem,
|
||||
onSelect: (selectedItem: AdminLayoutMenuItem) => void
|
||||
) {
|
||||
if (item?.subItems?.length) {
|
||||
mobileMenuPath.value = [...mobileMenuPath.value, item]
|
||||
return
|
||||
}
|
||||
|
||||
onSelect(item)
|
||||
}
|
||||
|
||||
function handleSelectFavorite (
|
||||
item: AdminLayoutMenuItem,
|
||||
onSelect: (selectedItem: AdminLayoutMenuItem) => void
|
||||
) {
|
||||
onSelect(item)
|
||||
mobileFavoritesPanel.value = false
|
||||
}
|
||||
|
||||
function toggleFavoritesBar (nextValue?: boolean) {
|
||||
showFavoritesBar.value =
|
||||
typeof nextValue === 'boolean' ? nextValue : !showFavoritesBar.value
|
||||
}
|
||||
|
||||
function handleUnshrink () {
|
||||
isRail.value = false
|
||||
}
|
||||
|
||||
let appBarObserver: ResizeObserver | null = null
|
||||
|
||||
function resolveObservedElement () {
|
||||
const target = options.appBarRef.value as HTMLElement | { $el?: HTMLElement } | null
|
||||
if (!target) return null
|
||||
if (target instanceof HTMLElement) return target
|
||||
return target.$el ?? null
|
||||
}
|
||||
|
||||
function updateAppBarHeight () {
|
||||
const el = resolveObservedElement()
|
||||
if (!el) return
|
||||
appBarHeight.value = Math.round(el.getBoundingClientRect().height || 0)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
updateAppBarHeight()
|
||||
if (typeof ResizeObserver === 'undefined') return
|
||||
|
||||
const el = resolveObservedElement()
|
||||
if (!el) return
|
||||
|
||||
appBarObserver = new ResizeObserver(() => updateAppBarHeight())
|
||||
appBarObserver.observe(el)
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (!appBarObserver) return
|
||||
appBarObserver.disconnect()
|
||||
appBarObserver = null
|
||||
})
|
||||
|
||||
watch(options.isMobile, (value) => {
|
||||
if (!value) {
|
||||
resetMobilePanels()
|
||||
}
|
||||
})
|
||||
|
||||
watch(drawer, (value) => {
|
||||
if (!value) {
|
||||
resetMobilePanels()
|
||||
}
|
||||
})
|
||||
|
||||
const mainStyle = computed(() => ({
|
||||
paddingTop: appBarHeight.value ? `${appBarHeight.value}px` : undefined,
|
||||
height: '100vh',
|
||||
minHeight: 0,
|
||||
flex: '1 1 0',
|
||||
}))
|
||||
|
||||
return {
|
||||
drawer,
|
||||
goToMobileLevel,
|
||||
handleMobileMenuClick,
|
||||
handleSelectFavorite,
|
||||
handleUnshrink,
|
||||
isRail,
|
||||
mainStyle,
|
||||
mobileCurrentItems,
|
||||
mobileCurrentLevel,
|
||||
mobileFavoritesPanel,
|
||||
mobileMenuLevels,
|
||||
openMobileFavoritesPanel,
|
||||
opened,
|
||||
showBreadcrumbBar,
|
||||
showFavoritesBar,
|
||||
toggleFavoritesBar,
|
||||
toggleSidebar,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user