2024-04-09 12:11:46 +08:00

198 lines
5.8 KiB
Vue

<script setup lang="ts">
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { NLayout, NLayoutContent, NLayoutSider, NSpace } from 'naive-ui'
import { useAuthStore } from '@/store'
import { AppLoader, RoundCardModal, SvgIcon } from '@/components/common'
import { t } from '@/locales'
interface App {
name: string
componentName: string
icon: string
auth?: number
}
const props = defineProps<{
visible: boolean
}>()
const emit = defineEmits<{
(e: 'update:visible', visible: boolean): void
}>()
const componentName = ref('UserInfo')
const collapsed = ref(false)
const screenWidth = ref(0)
const isSmallScreen = ref(false)
const defaultTitle = t('appLauncher.title')
const title = ref('')
const height = ref('500px')
const authStore = useAuthStore()
const balcklist = [t('apps.exportImport.appName'),t('apps.baseSettings.appName'), t('apps.itemGroupManage.appName'), t('apps.uploadsFileManager.appName'),t('adminSettingUsers.appName')]
const apps = ref<App[]>([
{
name: t('apps.userInfo.appName'),
componentName: 'UserInfo',
icon: 'material-symbols-person-edit-outline-rounded',
auth: authStore.userInfo?.role
},
{
name: t('apps.baseSettings.appName'),
componentName: 'Style',
icon: 'ion-color-palette-outline',
auth: authStore.userInfo?.role
},
{
name: t('apps.itemGroupManage.appName'),
componentName: 'ItemGroupManage',
icon: 'material-symbols-ad-group-outline-rounded',
auth: authStore.userInfo?.role
},
{
name: t('apps.uploadsFileManager.appName'),
componentName: 'UploadFileManager',
icon: 'tabler:file-upload',
auth: authStore.userInfo?.role
},
{
name: t('apps.exportImport.appName'),
componentName: 'ImportExport',
icon: 'icon-park-outline-import-and-export',
auth: authStore.userInfo?.role
},
{
name: t('adminSettingUsers.appName'),
componentName: 'Users',
icon: 'lucide-users',
auth: 1,
},
{
name: t('apps.about.appName'),
componentName: 'About',
icon: 'lucide-info',
auth: authStore.userInfo?.role
},
].filter(e => {
if (authStore.userInfo?.role == 1) {
return true
} else {
return !balcklist.includes(e.name)
}
}))
const show = computed({
get: () => props.visible,
set: (visible: boolean) => {
emit('update:visible', visible)
},
})
function handleClickApp(item: App) {
componentName.value = item.componentName
if (isSmallScreen.value)
collapsed.value = true
}
function getScreenWidth() {
return window.innerWidth
}
function handleResize() {
screenWidth.value = getScreenWidth()
if (screenWidth.value < 640) {
collapsed.value = true
isSmallScreen.value = true
}
else {
collapsed.value = false
isSmallScreen.value = false
}
}
onMounted(() => {
window.addEventListener('resize', handleResize)
handleResize()
})
onUnmounted(() => {
window.removeEventListener('resize', handleResize)
})
</script>
<template>
<div>
<RoundCardModal v-model:show="show" style="max-width: 900px;" size="small">
<template #header>
<div class="flex items-center select-none" @click="collapsed = !collapsed">
<div class="text-3xl cursor-pointer" style="color:var(--n-color-target)">
<SvgIcon class=" transition-all duration-500"
:icon="collapsed ? 'tabler-layout-sidebar-right-collapse-filled' : 'tabler-layout-sidebar-left-collapse-filled'" />
</div>
<div class="ml-1">
{{ title === '' ? defaultTitle : title }}
</div>
</div>
</template>
<div class="w-full h-full app-starter-modal-content">
<NSpace vertical size="large" style="height: 100%;width: 100%;">
<NLayout has-sider style="border-radius:0.75rem;">
<NLayoutSider v-model:collapsed="collapsed" collapse-mode="width" :collapsed-width="0"
:width="isSmallScreen ? '100%' : 240" style="height: 100%;" content-style="overflow: hidden">
<div class="w-full h-full dark:bg-[#2c2c32]">
<div class="p-[5px] bg-slate-200 dark:bg-zinc-900 rounded-xl overflow-auto" :style="{
width: isSmallScreen ? '100%' : '220px',
minWidth: '200px',
height,
}">
<div v-for=" (item, index) in apps" :key="index"
:style="{ color: componentName === item.componentName ? 'var(--n-color-target)' : '' }"
@click="handleClickApp(item)">
<div
class="bg-white dark:bg-zinc-800 p-[10px] rounded-lg mb-[5px] font-bold cursor-pointer flex items-center hover:bg-slate-50 focus:bg-slate-50">
<div class="flex items-center justify-center">
<div class="text-lg">
<SvgIcon :icon="item.icon" />
</div>
<span class="ml-2">{{ item.name }}</span>
</div>
<!-- 更多按钮 -->
<!-- <div class="ml-auto">
<SvgIcon icon="mingcute-more-1-fill" />
</div> -->
</div>
</div>
</div>
</div>
</NLayoutSider>
<NLayoutContent :content-style="{ height }">
<div class="rounded-2xl h-full overflow-auto transition-all duration-500 min-w-[300px] h-full"
:class="(isSmallScreen && !collapsed) ? 'opacity-0' : 'opacity-100'">
<AppLoader :component-name="componentName" class="h-full" />
</div>
</NLayoutContent>
</NLayout>
</NSpace>
</div>
</RoundCardModal>
</div>
</template>
<style scoped>
.text-shadow {
text-shadow: 0px 0px 5px gray;
}
</style>
<style>
.dark .app-starter-modal-content .n-layout {
background-color: #2c2c32;
}
</style>