first commit
This commit is contained in:
commit
db15eb3ee0
42 files changed
+4620
No files matched your search
@@ -0,0 +1,94 @@
|
||||
<script setup>
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { House, VideoCamera, Film, Lock, Setting, SwitchButton, ArrowDown, FullScreen, Close, Moon, Sunny, Document, DataAnalysis, Picture, User } from '@element-plus/icons-vue'
|
||||
import { useAuth } from '../stores/auth'
|
||||
import { useRbac } from '../stores/rbac'
|
||||
import { roleData } from '../data/roles'
|
||||
import { useTheme } from '../stores/theme'
|
||||
import { customMenus } from '../data/customMenus'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const { currentRole, logout, setRole } = useAuth()
|
||||
const { can } = useRbac()
|
||||
const customIconMap = { Document, DataAnalysis, Picture, User, Setting, VideoCamera }
|
||||
const { isDark, toggleTheme } = useTheme()
|
||||
const tabs = ref([{ name: 'dashboard', title: '工作台' }])
|
||||
const isFullscreen = ref(Boolean(document.fullscreenElement))
|
||||
const activeTab = computed({
|
||||
get: () => String(route.name || 'dashboard'),
|
||||
set: name => router.push({ name }),
|
||||
})
|
||||
|
||||
watch(() => route.name, name => {
|
||||
if (!name || name === 'login') return
|
||||
const title = String(route.meta.title || '工作台')
|
||||
if (!tabs.value.some(tab => tab.name === name)) tabs.value.push({ name, title })
|
||||
})
|
||||
|
||||
function syncFullscreen() { isFullscreen.value = Boolean(document.fullscreenElement) }
|
||||
async function toggleFullscreen() {
|
||||
try {
|
||||
if (document.fullscreenElement) await document.exitFullscreen()
|
||||
else await document.documentElement.requestFullscreen()
|
||||
} catch {
|
||||
// Fullscreen may be unavailable in embedded previews or restricted browsers.
|
||||
}
|
||||
}
|
||||
onMounted(() => document.addEventListener('fullscreenchange', syncFullscreen))
|
||||
onUnmounted(() => document.removeEventListener('fullscreenchange', syncFullscreen))
|
||||
|
||||
function closeTab(name) {
|
||||
if (name === 'dashboard') return
|
||||
const index = tabs.value.findIndex(tab => tab.name === name)
|
||||
tabs.value = tabs.value.filter(tab => tab.name !== name)
|
||||
if (String(route.name) === name) router.push({ name: tabs.value[Math.max(0, index - 1)]?.name || 'dashboard' })
|
||||
}
|
||||
|
||||
function chooseRole(role) {
|
||||
setRole(role)
|
||||
router.replace({ name: 'dashboard' })
|
||||
}
|
||||
|
||||
function handleLogout() {
|
||||
logout()
|
||||
tabs.value = [{ name: 'dashboard', title: '工作台' }]
|
||||
router.replace({ name: 'login' })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="app-shell">
|
||||
<aside class="sidebar">
|
||||
<div class="brand"><div class="brand-mark"><span></span><span></span><span></span></div><div><b>reelshort</b><small>STUDIO CONSOLE</small></div></div>
|
||||
<el-menu :default-active="String(route.name)" :default-openeds="['content','system']" class="side-menu" router>
|
||||
<el-menu-item index="dashboard" :route="{name:'dashboard'}"><el-icon><House /></el-icon><span>工作台</span></el-menu-item>
|
||||
<el-sub-menu index="content">
|
||||
<template #title><el-icon><VideoCamera /></el-icon><span>内容管理</span></template>
|
||||
<el-menu-item v-if="can('查看短剧列表')" index="dramas" :route="{name:'dramas'}">短剧管理</el-menu-item>
|
||||
<el-menu-item v-if="can('查看剧集列表')" index="episodes" :route="{name:'episodes'}">剧集管理</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-sub-menu v-if="can('角色与权限配置') || can('管理员用户列表') || can('菜单管理') || can('角色分类管理')" index="system">
|
||||
<template #title><el-icon><Setting /></el-icon><span>后台管理</span></template>
|
||||
<el-menu-item v-if="can('角色与权限配置')" index="access" :route="{name:'access'}">角色权限配置</el-menu-item>
|
||||
<el-menu-item v-if="can('管理员用户列表')" index="admin-users" :route="{name:'admin-users'}">管理员用户列表</el-menu-item>
|
||||
<el-menu-item v-if="can('菜单管理')" index="menus" :route="{name:'menus'}">菜单管理</el-menu-item>
|
||||
<el-menu-item v-if="can('角色分类管理')" index="role-categories" :route="{name:'role-categories'}">角色分类</el-menu-item>
|
||||
<el-menu-item v-if="can('角色与权限配置')" index="settings" :route="{name:'settings'}">系统设置</el-menu-item>
|
||||
</el-sub-menu>
|
||||
<el-sub-menu v-if="customMenus.some(menu => can(menu.permission))" index="custom-menus">
|
||||
<template #title><el-icon><Document /></el-icon><span>自定义菜单</span></template>
|
||||
<el-menu-item v-for="menu in customMenus.filter(item => item.type !== '按钮' && can(item.permission))" :key="menu.key" :index="`custom-menu-${menu.key}`" :route="{name:`custom-menu-${menu.key}`}"><el-icon><component :is="customIconMap[menu.icon] || Document" /></el-icon>{{menu.title}}</el-menu-item>
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
</aside>
|
||||
<main class="main-area">
|
||||
<header class="topbar"><div class="breadcrumb"><span>ReelShort Studio</span><span class="slash">/</span><b>{{route.meta.title || '工作台'}}</b></div><div class="top-actions"><span class="current-user">林小满 · {{currentRole}}</span><el-dropdown v-if="currentRole==='超级管理员'" trigger="click" @command="chooseRole"><el-button text class="role-switch">切换角色<el-icon><ArrowDown /></el-icon></el-button><template #dropdown><el-dropdown-menu><el-dropdown-item v-for="role in roleData" :key="role.name" :command="role.name">{{role.name}}</el-dropdown-item></el-dropdown-menu></template></el-dropdown><el-tooltip :content="isDark?'切换浅色主题':'切换深色主题'"><el-button text class="theme-button" :aria-label="isDark?'切换浅色主题':'切换深色主题'" @click="toggleTheme"><el-icon><component :is="isDark ? Sunny : Moon" /></el-icon></el-button></el-tooltip><el-tooltip :content="isFullscreen?'退出全屏':'全屏显示'"><el-button text class="fullscreen-button" :aria-label="isFullscreen?'退出全屏':'全屏显示'" @click="toggleFullscreen"><el-icon><component :is="isFullscreen ? Close : FullScreen" /></el-icon></el-button></el-tooltip><el-button text class="logout-button" @click="handleLogout"><el-icon><SwitchButton /></el-icon>退出登录</el-button></div></header>
|
||||
<el-tabs v-model="activeTab" type="card" class="page-tabs" @tab-remove="closeTab">
|
||||
<el-tab-pane v-for="tab in tabs" :key="tab.name" :name="tab.name" :label="tab.title" :closable="tab.name!=='dashboard'" />
|
||||
</el-tabs>
|
||||
<section class="page-content"><RouterView /></section>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
Reference in new issue
Block a user