Compare commits
2 Commits
8de70bf597
...
50d4fcdb8b
Author | SHA1 | Date | |
---|---|---|---|
|
50d4fcdb8b | ||
|
c402939b3a |
@ -1 +1 @@
|
||||
Subproject commit 9218ddcf90a543ca84c7240480a12dd08ceb2b1d
|
||||
Subproject commit 5cb82e750f4f4e6d9523ab9a8a24a4148d12950a
|
93
src/components/SysMenu.vue
Normal file
93
src/components/SysMenu.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<q-list bordered separator>
|
||||
<div v-for="(menu, ii) in list" :key="ii">
|
||||
<div v-if="menu.children">
|
||||
<q-expansion-item :icon="menu.icon" :label="menu.label">
|
||||
<q-card>
|
||||
<q-list bordered separator>
|
||||
<div v-for="(item, index) in menu.children" :key="index">
|
||||
<q-item
|
||||
clickable
|
||||
:to="menu.path + '/' + item.path"
|
||||
exact
|
||||
:inset-level="1"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="item.icon"></q-icon>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ item.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</q-list>
|
||||
</q-card>
|
||||
</q-expansion-item>
|
||||
</div>
|
||||
<div v-else>
|
||||
<q-item clickable :to="menu.path" exact>
|
||||
<q-item-section avatar>
|
||||
<q-icon :name="menu.icon"></q-icon>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ menu.label }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
</div>
|
||||
</q-list>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { RouteRecordRaw } from 'vue-router';
|
||||
import routes from 'src/router/routes';
|
||||
|
||||
interface IMenu {
|
||||
path: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
children?: IMenu[];
|
||||
}
|
||||
|
||||
const list = ref<IMenu[]>([]);
|
||||
|
||||
onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
|
||||
function getList() {
|
||||
const arr: IMenu[] = [];
|
||||
function getPathItem(item: RouteRecordRaw): IMenu | boolean {
|
||||
if (item.meta?.hidden) {
|
||||
return false;
|
||||
}
|
||||
const obj: IMenu = {
|
||||
path: item.path,
|
||||
label: (item.meta?.label as string) || '',
|
||||
icon: (item.meta?.icon as string) || '',
|
||||
};
|
||||
if (item.children) {
|
||||
const child: IMenu[] = [];
|
||||
item.children.forEach((ii) => {
|
||||
const childItem = getPathItem(ii);
|
||||
if (childItem) {
|
||||
child.push(childItem as IMenu);
|
||||
}
|
||||
});
|
||||
if (child.length) {
|
||||
Object.assign(obj, { children: child });
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
routes.forEach((item) => {
|
||||
const pItem = getPathItem(item);
|
||||
if (pItem) {
|
||||
arr.push(pItem as IMenu);
|
||||
}
|
||||
});
|
||||
|
||||
list.value = arr;
|
||||
}
|
||||
</script>
|
21
src/configs/TokenManage.ts
Normal file
21
src/configs/TokenManage.ts
Normal file
@ -0,0 +1,21 @@
|
||||
const JwtTokenKey = 'jwttoken';
|
||||
|
||||
export function saveJwtToken(token: string) {
|
||||
sessionStorage.setItem(JwtTokenKey, `Bearer ${token}`);
|
||||
}
|
||||
|
||||
export function getJwtToken(): string | null {
|
||||
return sessionStorage.getItem(JwtTokenKey);
|
||||
}
|
||||
|
||||
export function clearJwtToken(): void {
|
||||
sessionStorage.removeItem(JwtTokenKey);
|
||||
}
|
||||
|
||||
export function getOnlyToken(): string | null {
|
||||
// 去除token前的Bearer
|
||||
let t = sessionStorage.getItem(JwtTokenKey);
|
||||
const Rxg = /^Bearer /;
|
||||
t = t ? t.replace(Rxg, '') : '';
|
||||
return t;
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<q-layout view="lHh Lpr lFf">
|
||||
<q-layout view="hHh Lpr lFf">
|
||||
<q-header elevated>
|
||||
<q-resize-observer @resize="onHeaderResize" />
|
||||
<q-toolbar>
|
||||
<q-btn
|
||||
flat
|
||||
@ -11,87 +12,173 @@
|
||||
@click="toggleLeftDrawer"
|
||||
/>
|
||||
|
||||
<q-toolbar-title> Quasar App </q-toolbar-title>
|
||||
<q-toolbar-title> 北京玖琏 </q-toolbar-title>
|
||||
|
||||
<div>Quasar v{{ $q.version }}</div>
|
||||
<div class="q-gutter-sm no-wrap">
|
||||
<q-btn
|
||||
round
|
||||
dense
|
||||
flat
|
||||
color="white"
|
||||
:icon="$q.fullscreen.isActive ? 'fullscreen_exit' : 'fullscreen'"
|
||||
@click="$q.fullscreen.toggle()"
|
||||
v-if="$q.screen.gt.sm"
|
||||
>
|
||||
</q-btn>
|
||||
<q-btn-dropdown flat stretch icon="person">
|
||||
<q-list>
|
||||
<q-item clickable v-close-popup @click="showUserInfo">
|
||||
<q-item-section>
|
||||
<q-item-label>用户信息</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="logOut">
|
||||
<q-item-section>
|
||||
<q-item-label>登出</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
</div>
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
|
||||
<q-drawer v-model="leftDrawerOpen" show-if-above bordered>
|
||||
<q-list>
|
||||
<q-item-label header> Essential Links </q-item-label>
|
||||
|
||||
<EssentialLink
|
||||
v-for="link in linksList"
|
||||
:key="link.title"
|
||||
v-bind="link"
|
||||
/>
|
||||
</q-list>
|
||||
<q-resize-observer @resize="onLeftResize" />
|
||||
<sys-menu></sys-menu>
|
||||
</q-drawer>
|
||||
|
||||
<q-page-container>
|
||||
<router-view />
|
||||
<q-resize-observer @resize="onResize" />
|
||||
<q-scroll-area :style="{ height: scrollHeight + 'px' }">
|
||||
<router-view :sizeHeight="scrollHeight" :sizeWidth="scrollWidth" />
|
||||
</q-scroll-area>
|
||||
</q-page-container>
|
||||
<q-dialog v-model="showInfo">
|
||||
<q-card style="width: 400px; max-width: 80vw">
|
||||
<q-card-section>
|
||||
<div class="text-h6">用户信息</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="q-pt-none">
|
||||
<q-list>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label caption>ID:</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-item-label>{{ userInfo?.id }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label caption>用户名:</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-item-label>{{ userInfo?.name }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label caption>角色:</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label avatar style="text-align: right">
|
||||
{{ getRoleName(userInfo?.roles) }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label caption>电话:</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-item-label>{{ userInfo?.mobile }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label caption>注册时间:</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section avatar>
|
||||
<q-item-label>{{ userInfo?.register_time }}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="确定" color="primary" @click="closeShowInfo" />
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</q-layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import EssentialLink, {
|
||||
EssentialLinkProps,
|
||||
} from 'components/EssentialLink.vue';
|
||||
import { ref, reactive } from 'vue';
|
||||
import SysMenu from 'src/components/SysMenu.vue';
|
||||
// import { useRouter } from 'vue-router';
|
||||
import { clearJwtToken } from 'src/configs/TokenManage';
|
||||
import { Dialog } from 'quasar';
|
||||
|
||||
defineOptions({
|
||||
name: 'MainLayout',
|
||||
});
|
||||
const linksList: EssentialLinkProps[] = [
|
||||
{
|
||||
title: 'Docs',
|
||||
caption: 'quasar.dev',
|
||||
icon: 'school',
|
||||
link: 'https://quasar.dev',
|
||||
},
|
||||
{
|
||||
title: 'Github',
|
||||
caption: 'github.com/quasarframework',
|
||||
icon: 'code',
|
||||
link: 'https://github.com/quasarframework',
|
||||
},
|
||||
{
|
||||
title: 'Discord Chat Channel',
|
||||
caption: 'chat.quasar.dev',
|
||||
icon: 'chat',
|
||||
link: 'https://chat.quasar.dev',
|
||||
},
|
||||
{
|
||||
title: 'Forum',
|
||||
caption: 'forum.quasar.dev',
|
||||
icon: 'record_voice_over',
|
||||
link: 'https://forum.quasar.dev',
|
||||
},
|
||||
{
|
||||
title: 'Twitter',
|
||||
caption: '@quasarframework',
|
||||
icon: 'rss_feed',
|
||||
link: 'https://twitter.quasar.dev',
|
||||
},
|
||||
{
|
||||
title: 'Facebook',
|
||||
caption: '@QuasarFramework',
|
||||
icon: 'public',
|
||||
link: 'https://facebook.quasar.dev',
|
||||
},
|
||||
{
|
||||
title: 'Quasar Awesome',
|
||||
caption: 'Community Quasar projects',
|
||||
icon: 'favorite',
|
||||
link: 'https://awesome.quasar.dev',
|
||||
},
|
||||
];
|
||||
// const router = useRouter();
|
||||
|
||||
const leftDrawerOpen = ref(false);
|
||||
|
||||
function toggleLeftDrawer() {
|
||||
leftDrawerOpen.value = !leftDrawerOpen.value;
|
||||
onResize();
|
||||
}
|
||||
const scrollHeight = ref(100);
|
||||
const scrollWidth = ref(100);
|
||||
function onResize() {
|
||||
scrollHeight.value = window.innerHeight - headerSize.height;
|
||||
scrollWidth.value =
|
||||
window.innerWidth - (leftDrawerOpen.value ? leftDrawerSize.width : 0);
|
||||
}
|
||||
const headerSize = reactive({} as { width: number; height: number });
|
||||
function onHeaderResize(size: { width: number; height: number }) {
|
||||
headerSize.width = size.width;
|
||||
headerSize.height = size.height;
|
||||
}
|
||||
|
||||
const leftDrawerSize = reactive({} as { width: number; height: number });
|
||||
function onLeftResize(size: { width: number; height: number }) {
|
||||
leftDrawerSize.width = size.width;
|
||||
leftDrawerSize.height = size.height;
|
||||
}
|
||||
|
||||
const showInfo = ref(false);
|
||||
const userInfo = null;
|
||||
function showUserInfo() {
|
||||
showInfo.value = true;
|
||||
}
|
||||
function closeShowInfo() {
|
||||
showInfo.value = false;
|
||||
}
|
||||
|
||||
function logOut() {
|
||||
Dialog.create({
|
||||
title: '登出确认',
|
||||
message: '确认是否登出?',
|
||||
cancel: true,
|
||||
persistent: true,
|
||||
}).onOk(() => {
|
||||
clearJwtToken();
|
||||
// router.push({ name: 'login' });
|
||||
});
|
||||
}
|
||||
|
||||
function getRoleName(list: { id: number; name: string }[] | undefined) {
|
||||
let name = '';
|
||||
if (list && list.length > 0) {
|
||||
const arr = list.map((item) => {
|
||||
return item.name;
|
||||
});
|
||||
name = arr.join(',');
|
||||
}
|
||||
return name;
|
||||
}
|
||||
</script>
|
||||
|
@ -3,7 +3,17 @@ import { RouteRecordRaw } from 'vue-router';
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
path: '/',
|
||||
component: () => import('layouts/DrawLayout.vue'),
|
||||
redirect: '/home',
|
||||
meta: {
|
||||
hidden: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/home',
|
||||
component: () => import('layouts/MainLayout.vue'),
|
||||
meta: {
|
||||
hidden: true,
|
||||
},
|
||||
// children: [{ path: '', component: () => import('pages/IndexPage.vue') }],
|
||||
},
|
||||
|
||||
@ -11,11 +21,17 @@ const routes: RouteRecordRaw[] = [
|
||||
// but you can also remove it
|
||||
{
|
||||
path: '/:catchAll(.*)*',
|
||||
meta: {
|
||||
hidden: true,
|
||||
},
|
||||
component: () => import('pages/ErrorNotFound.vue'),
|
||||
},
|
||||
{
|
||||
path: '/cctvPainting',
|
||||
name: 'cctvPainting',
|
||||
meta: {
|
||||
label: 'CCTV绘制',
|
||||
},
|
||||
component: () => import('layouts/CCTVDrawLayout.vue'),
|
||||
},
|
||||
];
|
||||
|
Loading…
Reference in New Issue
Block a user