chore: 容器框架升级,修复项目命令行异常问题
This commit is contained in:
93
apps/y-code-v1/src/layout/components/Header.vue
Normal file
93
apps/y-code-v1/src/layout/components/Header.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<script setup lang="ts">
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { logout } from '@/api/common';
|
||||
import avatar from '@/assets/avatar.png';
|
||||
import { useUserInfoStore } from '@/stores/useUserInfoStore';
|
||||
import { YCODE_BASEURL } from '@/utils/request';
|
||||
import { FullscreenOutlined, HomeOutlined } from '@ant-design/icons-vue';
|
||||
|
||||
const emits = defineEmits(['requestFullscreen']);
|
||||
|
||||
const route = useRoute();
|
||||
const userInfoStore = useUserInfoStore();
|
||||
|
||||
const handleLogout = () => {
|
||||
logout().then(() => {
|
||||
window.location.href = `${YCODE_BASEURL}/login?redirect=${encodeURIComponent(
|
||||
window.location.href,
|
||||
)}`;
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="root">
|
||||
<a-breadcrumb>
|
||||
<a-breadcrumb-item v-for="item in route.matched" :key="item.path">
|
||||
<HomeOutlined v-if="item.path === '/' && item.name === 'layout'" />
|
||||
<span v-else>{{ item.meta.title || item.path }}</span>
|
||||
</a-breadcrumb-item>
|
||||
</a-breadcrumb>
|
||||
|
||||
<div class="user-area">
|
||||
<div class="fullscreen-icon-area" @click="emits('requestFullscreen')">
|
||||
<FullscreenOutlined class="fullscreen-icon" />
|
||||
</div>
|
||||
<a-dropdown placement="bottom">
|
||||
<div style="display: flex; align-items: center; cursor: pointer">
|
||||
<img :src="userInfoStore.userInfo?.avatar || avatar" class="avatar" />
|
||||
<div>{{ userInfoStore.userInfo?.alias || '-' }}</div>
|
||||
</div>
|
||||
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item @click="handleLogout">
|
||||
<span>退出登录</span>
|
||||
</a-menu-item>
|
||||
<a-menu-item>
|
||||
<a class="back-oa" :href="`${OA_BASEURL}/front/`"> 返回OA </a>
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.root {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 30px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.08);
|
||||
.user-area {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: rgb(51, 51, 51);
|
||||
.fullscreen-icon-area {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #ecf4fe;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
.fullscreen-icon {
|
||||
font-size: 20px;
|
||||
color: #1890ff;
|
||||
}
|
||||
}
|
||||
.avatar {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
border-radius: 50%;
|
||||
margin-left: 16px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
70
apps/y-code-v1/src/layout/components/Sider.vue
Normal file
70
apps/y-code-v1/src/layout/components/Sider.vue
Normal file
@@ -0,0 +1,70 @@
|
||||
<script lang="ts"></script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { RouteType } from '@/router/routes';
|
||||
import type { ItemType } from 'ant-design-vue';
|
||||
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import routeList from '@/router/routes';
|
||||
|
||||
function formatMemu(list: RouteType[], path: string = ''): ItemType[] {
|
||||
return list
|
||||
.filter((i) => i.isMenu)
|
||||
.map((item) => {
|
||||
const key = item.path.startsWith('/')
|
||||
? item.path
|
||||
: `${path}/${item.path}`;
|
||||
return {
|
||||
key,
|
||||
icon: item.icon,
|
||||
children:
|
||||
item.children.length > 0 ? formatMemu(item.children, key) : void 0,
|
||||
label: item.meta.title || '-',
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const selectedKeys = ref<string[]>(['1']);
|
||||
const openKeys = ref<string[]>(['sub1']);
|
||||
const menuList = computed(() => formatMemu(routeList[0].children));
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
(val) => {
|
||||
if (!selectedKeys.value.includes(val)) {
|
||||
selectedKeys.value = [val];
|
||||
openKeys.value = route.matched.slice(1).map((i) => i.path);
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const handleClick = (config: { key: string }) => {
|
||||
router.push(config.key);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-menu
|
||||
v-model:open-keys="openKeys"
|
||||
v-model:selected-keys="selectedKeys"
|
||||
mode="inline"
|
||||
:items="menuList"
|
||||
class="sider-root"
|
||||
@click="handleClick"
|
||||
v-bind="$attrs"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sider-root {
|
||||
flex-grow: 1;
|
||||
overflow-y: auto;
|
||||
border-inline-end: none !important;
|
||||
}
|
||||
</style>
|
||||
136
apps/y-code-v1/src/layout/index.vue
Normal file
136
apps/y-code-v1/src/layout/index.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import Header from "./components/Header.vue";
|
||||
import Sider from "./components/Sider.vue";
|
||||
import {
|
||||
MenuFoldOutlined,
|
||||
MenuUnfoldOutlined,
|
||||
FullscreenExitOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { useEventListener } from "@vueuse/core";
|
||||
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
|
||||
|
||||
const __POWERED_BY_QIANKUN__ = computed(() => {
|
||||
return qiankunWindow.__POWERED_BY_QIANKUN__ || window?.proxy?.__POWERED_BY_QIANKUN__
|
||||
})
|
||||
|
||||
// const userInfoStore = useUserInfoStore();
|
||||
const isCollapsed = ref(false);
|
||||
const isFullscreen = ref(false);
|
||||
const container = ref<HTMLDivElement>();
|
||||
|
||||
onMounted(() => {
|
||||
// userInfoStore.fetchUserInfo();
|
||||
});
|
||||
|
||||
useEventListener(window, "fullscreenchange", () => {
|
||||
isFullscreen.value = !!document.fullscreenElement;
|
||||
});
|
||||
|
||||
const handleFullscreen = () => {
|
||||
if (container.value) {
|
||||
container.value.requestFullscreen();
|
||||
}
|
||||
};
|
||||
const handleExitFullscreen = () => {
|
||||
document.exitFullscreen?.();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section v-if="!__POWERED_BY_QIANKUN__" class="root">
|
||||
<section
|
||||
class="left-aside"
|
||||
:class="{ 'left-aside-collapsed': isCollapsed }"
|
||||
>
|
||||
<Sider :inlineCollapsed="isCollapsed" />
|
||||
<div class="collapsed-icon">
|
||||
<component
|
||||
:is="isCollapsed ? MenuUnfoldOutlined : MenuFoldOutlined"
|
||||
@click="isCollapsed = !isCollapsed"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section
|
||||
class="container"
|
||||
:class="{
|
||||
'container-fullscreen': isFullscreen,
|
||||
'container-collapsed': isCollapsed,
|
||||
}"
|
||||
ref="container"
|
||||
>
|
||||
<header class="header">
|
||||
<Header @requestFullscreen="handleFullscreen" />
|
||||
</header>
|
||||
<div class="i-container">
|
||||
<router-view />
|
||||
</div>
|
||||
<a-float-button @click="handleExitFullscreen" v-if="isFullscreen">
|
||||
<template #icon>
|
||||
<FullscreenExitOutlined />
|
||||
</template>
|
||||
</a-float-button>
|
||||
</section>
|
||||
</section>
|
||||
<router-view v-else />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@header-height: 60px;
|
||||
@aside-width: 220px;
|
||||
@aside-width-collapsed: 60px;
|
||||
@header-margin: 12px;
|
||||
|
||||
.root {
|
||||
height: 100%;
|
||||
.header {
|
||||
height: @header-height;
|
||||
position: fixed;
|
||||
width: calc(100% - 220px);
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
}
|
||||
.left-aside {
|
||||
width: @aside-width;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
height: 100vh;
|
||||
overflow-y: hidden;
|
||||
box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
transition: width 0.3s cubic-bezier(0.2, 0, 0, 1) 0s;
|
||||
.collapsed-icon {
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 8px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
padding-left: @aside-width;
|
||||
padding-top: @header-height + @header-margin;
|
||||
height: calc(100% - @header-height - @header-margin);
|
||||
position: relative;
|
||||
background-color: #f8f8f8;
|
||||
transition: padding 0.3s cubic-bezier(0.2, 0, 0, 1) 0s;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.container-collapsed {
|
||||
padding-left: @aside-width-collapsed + 8px;
|
||||
}
|
||||
.container-fullscreen {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
:deep(
|
||||
:where(.css-dev-only-do-not-override-1hsjdkk).ant-menu-inline-collapsed
|
||||
),
|
||||
.left-aside-collapsed {
|
||||
width: @aside-width-collapsed;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user