mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
refactor: 样式优化
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
"clipboard": "^2.0.11",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"echarts": "^5.6.0",
|
||||
"echarts": "^6.0.0",
|
||||
"element-plus": "^2.10.5",
|
||||
"js-base64": "^3.7.7",
|
||||
"jsencrypt": "^3.3.2",
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 9.4 KiB |
@@ -1,35 +1,34 @@
|
||||
<template>
|
||||
<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
|
||||
<div class="h-full">
|
||||
<el-watermark
|
||||
:zIndex="100000"
|
||||
:width="210"
|
||||
v-if="themeConfig.isWatermark"
|
||||
:font="{ color: 'rgba(180, 180, 180, 0.3)' }"
|
||||
:content="themeConfig.watermarkText"
|
||||
class="!h-full"
|
||||
>
|
||||
<router-view />
|
||||
</el-watermark>
|
||||
<router-view v-if="!themeConfig.isWatermark" />
|
||||
<el-watermark
|
||||
:zIndex="100000"
|
||||
:width="210"
|
||||
v-if="themeConfig.isWatermark"
|
||||
:font="{ color: 'rgba(180, 180, 180, 0.3)' }"
|
||||
:content="themeConfig.watermarkText"
|
||||
class="!h-full"
|
||||
>
|
||||
<router-view />
|
||||
</el-watermark>
|
||||
<router-view v-if="!themeConfig.isWatermark" />
|
||||
|
||||
<Setings />
|
||||
</div>
|
||||
<Setings />
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="app">
|
||||
import { onMounted, nextTick, watch, computed } from 'vue';
|
||||
import { onMounted, nextTick, watch, computed, defineAsyncComponent } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import Setings from '@/layout/navBars/breadcrumb/setings.vue';
|
||||
import { useIntervalFn } from '@vueuse/core';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import EnumValue from './common/Enum';
|
||||
import { I18nEnum } from './common/commonEnum';
|
||||
import { saveThemeConfig } from './common/utils/storage';
|
||||
|
||||
const Setings = defineAsyncComponent(() => import('@/layout/navBars/breadcrumb/setings.vue'));
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const themeConfigStores = useThemeConfig();
|
||||
|
||||
@@ -1 +1,9 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1621859009605" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9709" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M820.203922 812.172549H684.67451v-45.176471h112.439215V279.090196H633.47451l-85.333334 277.082353c-3.011765 10.039216-12.047059 16.062745-22.086274 16.062745-10.039216 0-19.07451-7.027451-21.082353-17.066667l-71.278431-280.094117h-180.705883V762.980392h120.470589v45.176471H229.898039c-12.047059 0-22.086275-10.039216-22.086274-22.086275V252.988235c0-12.047059 10.039216-22.086275 22.086274-22.086274H451.764706c10.039216 0 19.07451 7.027451 22.086274 17.066666l55.215687 218.854902L595.32549 250.980392c3.011765-9.035294 12.047059-16.062745 21.082353-16.062745h202.792157c12.047059 0 22.086275 10.039216 22.086275 22.086275v533.082353c1.003922 12.047059-9.035294 22.086275-21.082353 22.086274z m0 0" fill="#e25813" p-id="9710"></path><path d="M731.858824 425.662745c4.015686-12.047059-2.007843-25.098039-14.054902-29.113725-12.047059-4.015686-25.098039 2.007843-29.113726 14.054902L563.2 766.996078h-73.286275L371.45098 410.603922c-4.015686-12.047059-17.066667-18.070588-28.109804-14.054902-12.047059 4.015686-18.070588 17.066667-14.054901 28.109804l123.482352 371.45098c3.011765 9.035294 12.047059 15.058824 21.082353 15.058823h72.282353l-53.207843 160.627451 46.180392 2.007844 192.752942-548.141177z" fill="#2c2c2c" p-id="9711"></path></svg>
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg t="1621859009605" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="9709" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="200" height="200">
|
||||
<defs><style type="text/css"></style></defs>
|
||||
<path d="M820.203922 812.172549H684.67451v-45.176471h112.439215V279.090196H633.47451l-85.333334 277.082353c-3.011765 10.039216-12.047059 16.062745-22.086274 16.062745-10.039216 0-19.07451-7.027451-21.082353-17.066667l-71.278431-280.094117h-180.705883V762.980392h120.470589v45.176471H229.898039c-12.047059 0-22.086275-10.039216-22.086274-22.086275V252.988235c0-12.047059 10.039216-22.086275 22.086274-22.086274H451.764706c10.039216 0 19.07451 7.027451 22.086274 17.066666l55.215687 218.854902L595.32549 250.980392c3.011765-9.035294 12.047059-16.062745 21.082353-16.062745h202.792157c12.047059 0 22.086275 10.039216 22.086275 22.086275v533.082353c1.003922 12.047059-9.035294 22.086275-21.082353 22.086274z m0 0" fill="#e25813" p-id="9710" stroke-width="30" stroke="#e25813"></path>
|
||||
<path d="M731.858824 425.662745c4.015686-12.047059-2.007843-25.098039-14.054902-29.113725-12.047059-4.015686-25.098039 2.007843-29.113726 14.054902L563.2 766.996078h-73.286275L371.45098 410.603922c-4.015686-12.047059-17.066667-18.070588-28.109804-14.054902-12.047059 4.015686-18.070588 17.066667-14.054901 28.109804l123.482352 371.45098c3.011765 9.035294 12.047059 15.058824 21.082353 15.058823h72.282353l-53.207843 160.627451 46.180392 2.007844 192.752942-548.141177z" fill="#2c2c2c" p-id="9711" stroke-width="30" stroke="#2c2c2c"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
@@ -16,15 +16,16 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="layoutAside">
|
||||
import { reactive, computed, watch, getCurrentInstance, onBeforeMount, onUnmounted, inject } from 'vue';
|
||||
import { reactive, computed, watch, getCurrentInstance, onBeforeMount, inject, defineAsyncComponent } from 'vue';
|
||||
import pinia from '@/store/index';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import { useRoutesList } from '@/store/routesList';
|
||||
import Logo from '@/layout/logo/index.vue';
|
||||
import Vertical from '@/layout/navMenu/vertical.vue';
|
||||
import { useWindowSize } from '@vueuse/core';
|
||||
|
||||
const Logo = defineAsyncComponent(() => import('@/layout/logo/index.vue'));
|
||||
const Vertical = defineAsyncComponent(() => import('@/layout/navMenu/vertical.vue'));
|
||||
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
|
||||
const { themeConfig } = storeToRefs(useThemeConfig());
|
||||
|
||||
@@ -103,9 +103,14 @@ const setFilterRoutes = () => {
|
||||
state.columnsAsideList = filterRoutesFun(useRoutesList().routesList);
|
||||
const resData: any = setSendChildren(route.path);
|
||||
onColumnsAsideDown(resData.item[0].k);
|
||||
if (columnsMenuData) {
|
||||
columnsMenuData.value = resData;
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
if (columnsMenuData) {
|
||||
columnsMenuData.value = resData;
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
};
|
||||
// 传送当前子级数据到菜单中
|
||||
const setSendChildren = (path: string) => {
|
||||
|
||||
@@ -1,26 +1,11 @@
|
||||
<template>
|
||||
<el-header class="layout-header" :height="setHeaderHeight">
|
||||
<el-header class="layout-header">
|
||||
<NavBarsIndex />
|
||||
</el-header>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import NavBarsIndex from '@/layout/navBars/index.vue';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
export default {
|
||||
name: 'layoutHeader',
|
||||
components: { NavBarsIndex },
|
||||
setup() {
|
||||
// 设置 header 的高度
|
||||
const setHeaderHeight = computed(() => {
|
||||
let { isTagsview, layout } = useThemeConfig().themeConfig;
|
||||
if (isTagsview && layout !== 'classic') return '84px';
|
||||
else return '50px';
|
||||
});
|
||||
return {
|
||||
setHeaderHeight,
|
||||
};
|
||||
},
|
||||
};
|
||||
<script setup lang="ts" name="layoutHeader">
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
const NavBarsIndex = defineAsyncComponent(() => import('@/layout/navBars/index.vue'));
|
||||
</script>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<el-scrollbar ref="layoutScrollbarRef" view-class="!h-full">
|
||||
<LayoutParentView />
|
||||
</el-scrollbar>
|
||||
|
||||
<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
|
||||
</el-main>
|
||||
|
||||
<el-footer v-if="themeConfig.isFooter">
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
<template>
|
||||
<Defaults v-if="themeConfig.layout === 'defaults'" />
|
||||
<Classic v-else-if="themeConfig.layout === 'classic'" />
|
||||
<Transverse v-else-if="themeConfig.layout === 'transverse'" />
|
||||
<Columns v-else-if="themeConfig.layout === 'columns'" />
|
||||
<component :is="layouts[themeConfig.layout]" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="layout">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import Defaults from '@/layout/main/defaults.vue';
|
||||
import Classic from '@/layout/main/classic.vue';
|
||||
import Transverse from '@/layout/main/transverse.vue';
|
||||
import Columns from '@/layout/main/columns.vue';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
const layouts: any = {
|
||||
defaults: defineAsyncComponent(() => import('@/layout/main/defaults.vue')),
|
||||
classic: defineAsyncComponent(() => import('@/layout/main/classic.vue')),
|
||||
transverse: defineAsyncComponent(() => import('@/layout/main/transverse.vue')),
|
||||
columns: defineAsyncComponent(() => import('@/layout/main/columns.vue')),
|
||||
};
|
||||
|
||||
const { themeConfig } = storeToRefs(useThemeConfig());
|
||||
</script>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="layout-logo" v-if="setShowLogo" @click="onThemeConfigChange">
|
||||
<img :src="themeConfig.logoIcon" class="layout-logo-medium-img" />
|
||||
<span>
|
||||
<span class="logo-title">
|
||||
{{ `${themeConfig.globalTitle}` }}
|
||||
<sub
|
||||
><span style="font-size: 10px; color: goldenrod">{{ ` ${config.version}` }}</span></sub
|
||||
@@ -53,8 +53,17 @@ const onThemeConfigChange = () => {
|
||||
}
|
||||
|
||||
&-medium-img {
|
||||
width: 20px;
|
||||
margin-right: 5px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.logo-title {
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: calc(100% - 32px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,10 +73,12 @@ const onThemeConfigChange = () => {
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
animation: logoAnimation 0.3s ease-in-out;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-img {
|
||||
width: 20px;
|
||||
margin: auto;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -8,18 +8,18 @@
|
||||
<Main />
|
||||
</div>
|
||||
</el-container>
|
||||
<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="layoutClassic">
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import Aside from '@/layout/component/aside.vue';
|
||||
import Header from '@/layout/component/header.vue';
|
||||
import Main from '@/layout/component/main.vue';
|
||||
import TagsView from '@/layout/navBars/tagsView/tagsView.vue';
|
||||
import { provide, ref } from 'vue';
|
||||
import { defineAsyncComponent, provide, ref } from 'vue';
|
||||
|
||||
const Aside = defineAsyncComponent(() => import('@/layout/component/aside.vue'));
|
||||
const Header = defineAsyncComponent(() => import('@/layout/component/header.vue'));
|
||||
const Main = defineAsyncComponent(() => import('@/layout/component/main.vue'));
|
||||
const TagsView = defineAsyncComponent(() => import('@/layout/navBars/tagsView/tagsView.vue'));
|
||||
|
||||
const { themeConfig } = storeToRefs(useThemeConfig());
|
||||
|
||||
|
||||
@@ -9,18 +9,18 @@
|
||||
<Main />
|
||||
</el-container>
|
||||
</div>
|
||||
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="layoutColumns">
|
||||
import { computed, provide, ref } from 'vue';
|
||||
import Aside from '@/layout/component/aside.vue';
|
||||
import Header from '@/layout/component/header.vue';
|
||||
import Main from '@/layout/component/main.vue';
|
||||
import ColumnsAside from '@/layout/component/columnsAside.vue';
|
||||
import { computed, defineAsyncComponent, provide, ref } from 'vue';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
|
||||
const Aside = defineAsyncComponent(() => import('@/layout/component/aside.vue'));
|
||||
const Header = defineAsyncComponent(() => import('@/layout/component/header.vue'));
|
||||
const Main = defineAsyncComponent(() => import('@/layout/component/main.vue'));
|
||||
const ColumnsAside = defineAsyncComponent(() => import('@/layout/component/columnsAside.vue'));
|
||||
|
||||
// 提供响应式数据给子组件
|
||||
const columnsMenuData = ref<any>(null);
|
||||
provide('columnsMenuData', columnsMenuData);
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
<Header v-if="!isFixedHeader" />
|
||||
<Main />
|
||||
</el-container>
|
||||
<el-backtop target=".layout-backtop .el-scrollbar__wrap"></el-backtop>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="layoutDefaults">
|
||||
import { computed, getCurrentInstance, watch } from 'vue';
|
||||
import { computed, defineAsyncComponent, getCurrentInstance, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import Aside from '@/layout/component/aside.vue';
|
||||
import Header from '@/layout/component/header.vue';
|
||||
import Main from '@/layout/component/main.vue';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
|
||||
const Aside = defineAsyncComponent(() => import('@/layout/component/aside.vue'));
|
||||
const Header = defineAsyncComponent(() => import('@/layout/component/header.vue'));
|
||||
const Main = defineAsyncComponent(() => import('@/layout/component/main.vue'));
|
||||
|
||||
const { proxy } = getCurrentInstance() as any;
|
||||
const route = useRoute();
|
||||
const isFixedHeader = computed(() => {
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
<el-container class="layout-container flex-center layout-backtop">
|
||||
<Header />
|
||||
<Main />
|
||||
<el-backtop target=".layout-backtop .el-main .el-scrollbar__wrap"></el-backtop>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="layoutTransverse">
|
||||
import Header from '@/layout/component/header.vue';
|
||||
import Main from '@/layout/component/main.vue';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
|
||||
const Main = defineAsyncComponent(() => import('@/layout/component/main.vue'));
|
||||
const Header = defineAsyncComponent(() => import('@/layout/component/header.vue'));
|
||||
</script>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
<template>
|
||||
<div class="layout-navbars-breadcrumb" v-show="themeConfig.isBreadcrumb">
|
||||
<SvgIcon class="layout-navbars-breadcrumb-icon" :name="themeConfig.isCollapse ? 'expand' : 'fold'" @click="onThemeConfigChange" />
|
||||
<div class="flex flex-1 h-inherit items-center pl-4" v-show="themeConfig.isBreadcrumb">
|
||||
<SvgIcon
|
||||
class="cursor-pointer text-18px mr-4 text-[var(--bg-topBarColor)]"
|
||||
:name="themeConfig.isCollapse ? 'expand' : 'fold'"
|
||||
@click="onThemeConfigChange"
|
||||
/>
|
||||
<el-breadcrumb class="layout-navbars-breadcrumb-hide">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(v, k) in state.breadcrumbList" :key="v.meta.title">
|
||||
<span v-if="k === state.breadcrumbList.length - 1" class="layout-navbars-breadcrumb-span">
|
||||
<SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="themeConfig.isBreadcrumbIcon" />
|
||||
<span v-if="k === state.breadcrumbList.length - 1 || (!v.redirect && !v.component)" class="opacity-70 text-[var(--bg-topBarColor)]">
|
||||
<SvgIcon :name="v.meta.icon" class="text-14px mr-1.25" v-if="themeConfig.isBreadcrumbIcon" />
|
||||
{{ $t(v.meta.title) }}
|
||||
</span>
|
||||
<a v-else @click.prevent="onBreadcrumbClick(v)">
|
||||
<SvgIcon :name="v.meta.icon" class="layout-navbars-breadcrumb-iconfont" v-if="themeConfig.isBreadcrumbIcon" />
|
||||
<a v-else @click.prevent="onBreadcrumbClick(v)" class="opacity-100 text-[var(--bg-topBarColor)] hover:opacity-100">
|
||||
<SvgIcon :name="v.meta.icon" class="text-14px mr-1.25" v-if="themeConfig.isBreadcrumbIcon" />
|
||||
{{ $t(v.meta.title) }}
|
||||
</a>
|
||||
</el-breadcrumb-item>
|
||||
@@ -29,84 +33,99 @@ const { themeConfig } = storeToRefs(useThemeConfig());
|
||||
const { routesList } = storeToRefs(useRoutesList());
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state: any = reactive({
|
||||
breadcrumbList: [],
|
||||
routeSplit: [],
|
||||
routeSplitFirst: '',
|
||||
routeSplitIndex: 1,
|
||||
const state = reactive({
|
||||
breadcrumbList: [] as any[],
|
||||
});
|
||||
|
||||
// 面包屑点击时
|
||||
const onBreadcrumbClick = (v: any) => {
|
||||
const { redirect, path } = v;
|
||||
if (redirect) router.push(redirect);
|
||||
else router.push(path);
|
||||
if (redirect) {
|
||||
router.push(redirect);
|
||||
return;
|
||||
}
|
||||
if (v.component) {
|
||||
router.push(path);
|
||||
}
|
||||
};
|
||||
// 展开/收起左侧菜单点击
|
||||
const onThemeConfigChange = () => {
|
||||
themeConfig.value.isCollapse = !themeConfig.value.isCollapse;
|
||||
};
|
||||
// 处理面包屑数据
|
||||
const getBreadcrumbList = (arr: Array<object>) => {
|
||||
arr.map((item: any) => {
|
||||
state.routeSplit.map((v: any, k: number, arrs: any) => {
|
||||
if (state.routeSplitFirst === item.path) {
|
||||
state.routeSplitFirst += `/${arrs[state.routeSplitIndex]}`;
|
||||
state.breadcrumbList.push(item);
|
||||
state.routeSplitIndex++;
|
||||
if (item.children) getBreadcrumbList(item.children);
|
||||
|
||||
// 根据当前路径生成面包屑列表
|
||||
const generateBreadcrumbList = (currentPath: string) => {
|
||||
if (!themeConfig.value.isBreadcrumb) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化面包屑列表,包含首页
|
||||
const homeRoute = routesList.value.length > 0 ? routesList.value[0] : null;
|
||||
const breadcrumbList = homeRoute ? [homeRoute] : [];
|
||||
|
||||
// 查找匹配的路由及其所有父级路由(除了首页)
|
||||
if (homeRoute && currentPath !== homeRoute.path) {
|
||||
const matchedRoutes = findMatchedRoutes(routesList.value, currentPath);
|
||||
// 如果找到匹配的路由,添加到面包屑列表中(排除首页,避免重复)
|
||||
if (matchedRoutes.length > 0) {
|
||||
// 过滤掉首页路由,避免重复添加
|
||||
const filteredRoutes = matchedRoutes.filter((r) => r !== homeRoute);
|
||||
breadcrumbList.push(...filteredRoutes);
|
||||
}
|
||||
}
|
||||
|
||||
state.breadcrumbList = breadcrumbList;
|
||||
};
|
||||
|
||||
// 在路由树中查找匹配当前路径的路由,并返回该路由及其所有父级路由
|
||||
const findMatchedRoutes = (routes: any[], currentPath: string): any[] => {
|
||||
for (const route of routes) {
|
||||
// 精确匹配
|
||||
if (route.path === currentPath) {
|
||||
return [route];
|
||||
}
|
||||
|
||||
// 前缀匹配且有子路由
|
||||
if (currentPath.startsWith(route.path + '/') && route.children) {
|
||||
const matchedChildren = findMatchedRoutes(route.children, currentPath);
|
||||
if (matchedChildren.length > 0) {
|
||||
return [route, ...matchedChildren];
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
// 当前路由字符串切割成数组,并删除第一项空内容
|
||||
const initRouteSplit = (path: string) => {
|
||||
if (!themeConfig.value.isBreadcrumb) return false;
|
||||
state.breadcrumbList = [routesList.value[0]];
|
||||
state.routeSplit = path.split('/');
|
||||
state.routeSplit.shift();
|
||||
state.routeSplitFirst = `/${state.routeSplit[0]}`;
|
||||
state.routeSplitIndex = 1;
|
||||
getBreadcrumbList(routesList.value);
|
||||
}
|
||||
|
||||
// 处理子路由匹配但当前路由是根路径的情况
|
||||
if (route.path === '/' && route.children) {
|
||||
const matchedChildren = findMatchedRoutes(route.children, currentPath);
|
||||
if (matchedChildren.length > 0) {
|
||||
return [route, ...matchedChildren];
|
||||
}
|
||||
}
|
||||
|
||||
// 递归查找子路由
|
||||
if (route.children) {
|
||||
const matchedChildren = findMatchedRoutes(route.children, currentPath);
|
||||
if (matchedChildren.length > 0) {
|
||||
return [route, ...matchedChildren];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// 页面加载时
|
||||
onMounted(() => {
|
||||
initRouteSplit(route.path);
|
||||
generateBreadcrumbList(route.path);
|
||||
});
|
||||
// 路由更新时
|
||||
onBeforeRouteUpdate((to) => {
|
||||
initRouteSplit(to.path);
|
||||
generateBreadcrumbList(to.path);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.layout-navbars-breadcrumb {
|
||||
flex: 1;
|
||||
height: inherit;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 15px;
|
||||
|
||||
.layout-navbars-breadcrumb-icon {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
margin-right: 15px;
|
||||
color: var(--bg-topBarColor);
|
||||
}
|
||||
|
||||
.layout-navbars-breadcrumb-span {
|
||||
opacity: 0.7;
|
||||
color: var(--bg-topBarColor);
|
||||
}
|
||||
|
||||
.layout-navbars-breadcrumb-iconfont {
|
||||
font-size: 14px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
::v-deep(.el-breadcrumb__separator) {
|
||||
opacity: 0.7;
|
||||
color: var(--bg-topBarColor);
|
||||
}
|
||||
<style scoped>
|
||||
::v-deep(.el-breadcrumb__separator) {
|
||||
opacity: 0.7;
|
||||
color: var(--bg-topBarColor);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,16 +8,17 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="layoutBreadcrumbIndex">
|
||||
import { computed, reactive, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { computed, reactive, onMounted, watch, defineAsyncComponent } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import pinia from '@/store/index';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import { useRoutesList } from '@/store/routesList';
|
||||
import Breadcrumb from '@/layout/navBars/breadcrumb/breadcrumb.vue';
|
||||
import User from '@/layout/navBars/breadcrumb/user.vue';
|
||||
import Logo from '@/layout/logo/index.vue';
|
||||
import Horizontal from '@/layout/navMenu/horizontal.vue';
|
||||
|
||||
const Breadcrumb = defineAsyncComponent(() => import('@/layout/navBars/breadcrumb/breadcrumb.vue'));
|
||||
const User = defineAsyncComponent(() => import('@/layout/navBars/breadcrumb/user.vue'));
|
||||
const Logo = defineAsyncComponent(() => import('@/layout/logo/index.vue'));
|
||||
const Horizontal = defineAsyncComponent(() => import('@/layout/navMenu/horizontal.vue'));
|
||||
|
||||
const { themeConfig } = storeToRefs(useThemeConfig());
|
||||
const { routesList } = storeToRefs(useRoutesList());
|
||||
|
||||
@@ -5,25 +5,17 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
<script setup lang="ts" name="layoutNavBars">
|
||||
import { computed } from 'vue';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import BreadcrumbIndex from '@/layout/navBars/breadcrumb/index.vue';
|
||||
import TagsView from '@/layout/navBars/tagsView/tagsView.vue';
|
||||
export default {
|
||||
name: 'layoutNavBars',
|
||||
components: { BreadcrumbIndex, TagsView },
|
||||
setup() {
|
||||
// 是否显示 tagsView
|
||||
const setShowTagsView = computed(() => {
|
||||
let { layout, isTagsview } = useThemeConfig().themeConfig;
|
||||
return layout !== 'classic' && isTagsview;
|
||||
});
|
||||
return {
|
||||
setShowTagsView,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
// 是否显示 tagsView
|
||||
const setShowTagsView = computed(() => {
|
||||
let { layout, isTagsview } = useThemeConfig().themeConfig;
|
||||
return layout !== 'classic' && isTagsview;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -34,12 +34,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="navMenuHorizontal">
|
||||
import { reactive, computed, onMounted, inject } from 'vue';
|
||||
import { reactive, computed, onMounted, inject, defineAsyncComponent } from 'vue';
|
||||
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
|
||||
import SubItem from '@/layout/navMenu/subItem.vue';
|
||||
import { useRoutesList } from '@/store/routesList';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
|
||||
const SubItem = defineAsyncComponent(() => import('@/layout/navMenu/subItem.vue'));
|
||||
|
||||
// 定义父组件传过来的值
|
||||
const props = defineProps({
|
||||
// 菜单列表
|
||||
|
||||
@@ -22,24 +22,20 @@
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue';
|
||||
export default defineComponent({
|
||||
name: 'navMenuSubItem',
|
||||
props: {
|
||||
chil: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
// 获取父级菜单数据
|
||||
const chils = computed(() => {
|
||||
return props.chil as any;
|
||||
});
|
||||
return {
|
||||
chils,
|
||||
};
|
||||
},
|
||||
<script setup lang="ts" name="navMenuSubItem">
|
||||
import { computed } from 'vue';
|
||||
|
||||
// 定义 props
|
||||
interface Props {
|
||||
chil?: any[];
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
chil: () => [],
|
||||
});
|
||||
|
||||
// 获取父级菜单数据
|
||||
const chils = computed(() => {
|
||||
return props.chil as any;
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -29,11 +29,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup name="navMenuVertical">
|
||||
import { reactive, computed } from 'vue';
|
||||
import { reactive, computed, defineAsyncComponent } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import { useRoute, onBeforeRouteUpdate } from 'vue-router';
|
||||
import SubItem from '@/layout/navMenu/subItem.vue';
|
||||
|
||||
const SubItem = defineAsyncComponent(() => import('@/layout/navMenu/subItem.vue'));
|
||||
|
||||
// 定义父组件传过来的值
|
||||
const props = defineProps({
|
||||
|
||||
@@ -31,9 +31,6 @@ const state = reactive({
|
||||
// 立即前往
|
||||
const onGotoFullPage = () => {
|
||||
window.open(state.link);
|
||||
// const { origin, pathname } = window.location;
|
||||
// if (verifyUrl(<string>state.isLink)) window.open(state.isLink);
|
||||
// else window.open(`${origin}${pathname}#${state.isLink}`);
|
||||
};
|
||||
|
||||
// 监听路由的变化,设置内容
|
||||
|
||||
@@ -9,6 +9,9 @@ import { RouteRecordRaw } from 'vue-router';
|
||||
import { LAYOUT_ROUTE_NAME } from './staticRouter';
|
||||
import { LinkTypeEnum } from '@/common/commonEnum';
|
||||
|
||||
const Link = () => import('@/layout/routerView/link.vue');
|
||||
const Iframe = () => import('@/layout/routerView/iframes.vue');
|
||||
|
||||
/**
|
||||
* 获取目录下的 route.ts 全部文件
|
||||
* @method import.meta.glob
|
||||
@@ -125,9 +128,9 @@ export function backEndRouterConverter(allModuleRoutes: any, routes: any, callba
|
||||
// 如果是外链类型,name的路由名都是Link 或者 Iframes会导致路由名重复,无法添加多个外链
|
||||
if (item.meta.link) {
|
||||
if (item.meta.linkType == LinkTypeEnum.Link.value) {
|
||||
item.component = () => import('@/layout/routerView/link.vue');
|
||||
item.component = Link;
|
||||
} else {
|
||||
item.component = () => import('@/layout/routerView/iframes.vue');
|
||||
item.component = Iframe;
|
||||
}
|
||||
} else {
|
||||
// routerName == 模块下route.ts 字段key == 组件名
|
||||
|
||||
@@ -6,7 +6,7 @@ import { getLocal, getThemeConfig } from '@/common/utils/storage';
|
||||
|
||||
// 系统默认logo图标,对应于@/assets/image/logo.svg
|
||||
const logoIcon =
|
||||
'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNjIxODU5MDA5NjA1IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9Ijk3MDkiIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PGRlZnM+PHN0eWxlIHR5cGU9InRleHQvY3NzIj48L3N0eWxlPjwvZGVmcz48cGF0aCBkPSJNODIwLjIwMzkyMiA4MTIuMTcyNTQ5SDY4NC42NzQ1MXYtNDUuMTc2NDcxaDExMi40MzkyMTVWMjc5LjA5MDE5Nkg2MzMuNDc0NTFsLTg1LjMzMzMzNCAyNzcuMDgyMzUzYy0zLjAxMTc2NSAxMC4wMzkyMTYtMTIuMDQ3MDU5IDE2LjA2Mjc0NS0yMi4wODYyNzQgMTYuMDYyNzQ1LTEwLjAzOTIxNiAwLTE5LjA3NDUxLTcuMDI3NDUxLTIxLjA4MjM1My0xNy4wNjY2NjdsLTcxLjI3ODQzMS0yODAuMDk0MTE3aC0xODAuNzA1ODgzVjc2Mi45ODAzOTJoMTIwLjQ3MDU4OXY0NS4xNzY0NzFIMjI5Ljg5ODAzOWMtMTIuMDQ3MDU5IDAtMjIuMDg2Mjc1LTEwLjAzOTIxNi0yMi4wODYyNzQtMjIuMDg2Mjc1VjI1Mi45ODgyMzVjMC0xMi4wNDcwNTkgMTAuMDM5MjE2LTIyLjA4NjI3NSAyMi4wODYyNzQtMjIuMDg2Mjc0SDQ1MS43NjQ3MDZjMTAuMDM5MjE2IDAgMTkuMDc0NTEgNy4wMjc0NTEgMjIuMDg2Mjc0IDE3LjA2NjY2Nmw1NS4yMTU2ODcgMjE4Ljg1NDkwMkw1OTUuMzI1NDkgMjUwLjk4MDM5MmMzLjAxMTc2NS05LjAzNTI5NCAxMi4wNDcwNTktMTYuMDYyNzQ1IDIxLjA4MjM1My0xNi4wNjI3NDVoMjAyLjc5MjE1N2MxMi4wNDcwNTkgMCAyMi4wODYyNzUgMTAuMDM5MjE2IDIyLjA4NjI3NSAyMi4wODYyNzV2NTMzLjA4MjM1M2MxLjAwMzkyMiAxMi4wNDcwNTktOS4wMzUyOTQgMjIuMDg2Mjc1LTIxLjA4MjM1MyAyMi4wODYyNzR6IG0wIDAiIGZpbGw9IiNlMjU4MTMiIHAtaWQ9Ijk3MTAiPjwvcGF0aD48cGF0aCBkPSJNNzMxLjg1ODgyNCA0MjUuNjYyNzQ1YzQuMDE1Njg2LTEyLjA0NzA1OS0yLjAwNzg0My0yNS4wOTgwMzktMTQuMDU0OTAyLTI5LjExMzcyNS0xMi4wNDcwNTktNC4wMTU2ODYtMjUuMDk4MDM5IDIuMDA3ODQzLTI5LjExMzcyNiAxNC4wNTQ5MDJMNTYzLjIgNzY2Ljk5NjA3OGgtNzMuMjg2Mjc1TDM3MS40NTA5OCA0MTAuNjAzOTIyYy00LjAxNTY4Ni0xMi4wNDcwNTktMTcuMDY2NjY3LTE4LjA3MDU4OC0yOC4xMDk4MDQtMTQuMDU0OTAyLTEyLjA0NzA1OSA0LjAxNTY4Ni0xOC4wNzA1ODggMTcuMDY2NjY3LTE0LjA1NDkwMSAyOC4xMDk4MDRsMTIzLjQ4MjM1MiAzNzEuNDUwOThjMy4wMTE3NjUgOS4wMzUyOTQgMTIuMDQ3MDU5IDE1LjA1ODgyNCAyMS4wODIzNTMgMTUuMDU4ODIzaDcyLjI4MjM1M2wtNTMuMjA3ODQzIDE2MC42Mjc0NTEgNDYuMTgwMzkyIDIuMDA3ODQ0IDE5Mi43NTI5NDItNTQ4LjE0MTE3N3oiIGZpbGw9IiMyYzJjMmMiIHAtaWQ9Ijk3MTEiPjwvcGF0aD48L3N2Zz4=';
|
||||
'data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHQ9IjE2MjE4NTkwMDk2MDUiIGNsYXNzPSJpY29uIiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIAogICAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcC1pZD0iOTcwOSIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIAogICAgIHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIj4KICAgICA8ZGVmcz48c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwvc3R5bGU+PC9kZWZzPgogICAgIDxwYXRoIGQ9Ik04MjAuMjAzOTIyIDgxMi4xNzI1NDlINjg0LjY3NDUxdi00NS4xNzY0NzFoMTEyLjQzOTIxNVYyNzkuMDkwMTk2SDYzMy40NzQ1MWwtODUuMzMzMzM0IDI3Ny4wODIzNTNjLTMuMDExNzY1IDEwLjAzOTIxNi0xMi4wNDcwNTkgMTYuMDYyNzQ1LTIyLjA4NjI3NCAxNi4wNjI3NDUtMTAuMDM5MjE2IDAtMTkuMDc0NTEtNy4wMjc0NTEtMjEuMDgyMzUzLTE3LjA2NjY2N2wtNzEuMjc4NDMxLTI4MC4wOTQxMTdoLTE4MC43MDU4ODNWNzYyLjk4MDM5MmgxMjAuNDcwNTg5djQ1LjE3NjQ3MUgyMjkuODk4MDM5Yy0xMi4wNDcwNTkgMC0yMi4wODYyNzUtMTAuMDM5MjE2LTIyLjA4NjI3NC0yMi4wODYyNzVWMjUyLjk4ODIzNWMwLTEyLjA0NzA1OSAxMC4wMzkyMTYtMjIuMDg2Mjc1IDIyLjA4NjI3NC0yMi4wODYyNzRINDUxLjc2NDcwNmMxMC4wMzkyMTYgMCAxOS4wNzQ1MSA3LjAyNzQ1MSAyMi4wODYyNzQgMTcuMDY2NjY2bDU1LjIxNTY4NyAyMTguODU0OTAyTDU5NS4zMjU0OSAyNTAuOTgwMzkyYzMuMDExNzY1LTkuMDM1Mjk0IDEyLjA0NzA1OS0xNi4wNjI3NDUgMjEuMDgyMzUzLTE2LjA2Mjc0NWgyMDIuNzkyMTU3YzEyLjA0NzA1OSAwIDIyLjA4NjI3NSAxMC4wMzkyMTYgMjIuMDg2Mjc1IDIyLjA4NjI3NXY1MzMuMDgyMzUzYzEuMDAzOTIyIDEyLjA0NzA1OS05LjAzNTI5NCAyMi4wODYyNzUtMjEuMDgyMzUzIDIyLjA4NjI3NHogbTAgMCIgZmlsbD0iI2UyNTgxMyIgcC1pZD0iOTcxMCIgc3Ryb2tlLXdpZHRoPSIzMCIgc3Ryb2tlPSIjZTI1ODEzIj48L3BhdGg+CiAgICAgPHBhdGggZD0iTTczMS44NTg4MjQgNDI1LjY2Mjc0NWM0LjAxNTY4Ni0xMi4wNDcwNTktMi4wMDc4NDMtMjUuMDk4MDM5LTE0LjA1NDkwMi0yOS4xMTM3MjUtMTIuMDQ3MDU5LTQuMDE1Njg2LTI1LjA5ODAzOSAyLjAwNzg0My0yOS4xMTM3MjYgMTQuMDU0OTAyTDU2My4yIDc2Ni45OTYwNzhoLTczLjI4NjI3NUwzNzEuNDUwOTggNDEwLjYwMzkyMmMtNC4wMTU2ODYtMTIuMDQ3MDU5LTE3LjA2NjY2Ny0xOC4wNzA1ODgtMjguMTA5ODA0LTE0LjA1NDkwMi0xMi4wNDcwNTkgNC4wMTU2ODYtMTguMDcwNTg4IDE3LjA2NjY2Ny0xNC4wNTQ5MDEgMjguMTA5ODA0bDEyMy40ODIzNTIgMzcxLjQ1MDk4YzMuMDExNzY1IDkuMDM1Mjk0IDEyLjA0NzA1OSAxNS4wNTg4MjQgMjEuMDgyMzUzIDE1LjA1ODgyM2g3Mi4yODIzNTNsLTUzLjIwNzg0MyAxNjAuNjI3NDUxIDQ2LjE4MDM5MiAyLjAwNzg0NCAxOTIuNzUyOTQyLTU0OC4xNDExNzd6IiBmaWxsPSIjMmMyYzJjIiBwLWlkPSI5NzExIiBzdHJva2Utd2lkdGg9IjMwIiBzdHJva2U9IiMyYzJjMmMiPjwvcGF0aD4KPC9zdmc+';
|
||||
|
||||
export const useThemeConfig = defineStore('themeConfig', {
|
||||
state: (): ThemeConfigState => ({
|
||||
|
||||
@@ -60,6 +60,7 @@ body,
|
||||
|
||||
.layout-header {
|
||||
padding: 0 !important;
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.layout-main {
|
||||
|
||||
@@ -1,34 +1,5 @@
|
||||
@use 'mixins/index' as mixins;
|
||||
|
||||
/* Button 按钮
|
||||
------------------------------- */
|
||||
|
||||
/* Input 输入框、InputNumber 计数器
|
||||
------------------------------- */
|
||||
// 菜单搜索
|
||||
.el-autocomplete-suggestion__wrap {
|
||||
max-height: 280px !important;
|
||||
}
|
||||
|
||||
|
||||
/* Alert 警告
|
||||
------------------------------- */
|
||||
.el-alert {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.el-alert__title {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* Message 消息提示
|
||||
------------------------------- */
|
||||
.el-message {
|
||||
min-width: unset !important;
|
||||
padding: 15px !important;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
/* NavMenu 导航菜单
|
||||
------------------------------- */
|
||||
$radius: 6px;
|
||||
@@ -306,9 +277,6 @@ html.dark {
|
||||
|
||||
/* Tabs 标签页
|
||||
------------------------------- */
|
||||
.el-tabs__nav-wrap::after {
|
||||
height: 1px !important;
|
||||
}
|
||||
|
||||
/* Dropdown 下拉菜单
|
||||
------------------------------- */
|
||||
@@ -326,8 +294,6 @@ html.dark {
|
||||
}
|
||||
}
|
||||
|
||||
/* Dialog 对话框
|
||||
------------------------------- */
|
||||
|
||||
/* Card 卡片
|
||||
------------------------------- */
|
||||
@@ -335,62 +301,6 @@ html.dark {
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
/* Table 表格 element plus 2.2.0 版本
|
||||
------------------------------- */
|
||||
.el-table {
|
||||
.el-button.is-text {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* scrollbar
|
||||
------------------------------- */
|
||||
.el-scrollbar__bar {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
/*防止页面切换时,滚动条高度不变的问题(滚动条高度非滚动条滚动高度)*/
|
||||
.el-scrollbar__wrap {
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.el-select-dropdown .el-scrollbar__wrap {
|
||||
overflow-x: scroll !important;
|
||||
}
|
||||
|
||||
/*修复Select 选择器高度问题*/
|
||||
.el-select-dropdown__wrap {
|
||||
max-height: 274px !important;
|
||||
}
|
||||
|
||||
/*修复Cascader 级联选择器高度问题*/
|
||||
.el-cascader-menu__wrap.el-scrollbar__wrap {
|
||||
height: 204px !important;
|
||||
}
|
||||
|
||||
/*用于界面高度自适应(main.vue),区分 scrollbar__view,防止其它使用 scrollbar 的地方出现滚动条消失*/
|
||||
.layout-container-view .el-scrollbar__view {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*防止分栏布局二级菜单很多时,滚动条消失问题*/
|
||||
.layout-columns-warp .layout-aside .el-scrollbar__view {
|
||||
height: unset !important;
|
||||
}
|
||||
|
||||
/* Pagination 分页
|
||||
------------------------------- */
|
||||
.el-pagination__editor {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
/*深色模式时分页高亮问题*/
|
||||
.el-pagination.is-background .btn-next.is-active,
|
||||
.el-pagination.is-background .btn-prev.is-active,
|
||||
.el-pagination.is-background .el-pager li.is-active {
|
||||
background-color: var(--el-color-primary) !important;
|
||||
color: var(--el-color-white) !important;
|
||||
}
|
||||
|
||||
/* Breadcrumb 面包屑
|
||||
------------------------------- */
|
||||
@@ -418,6 +328,8 @@ html.dark {
|
||||
}
|
||||
|
||||
|
||||
/* Dialog 对话框
|
||||
------------------------------- */
|
||||
.el-dialog {
|
||||
border-radius: 6px;
|
||||
/* 设置圆角 */
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="type" :label="$t('common.type')" required>
|
||||
<el-select @change="changeDbType" style="width: 100%" v-model="form.type">
|
||||
<el-select @change="changeDbType" v-model="form.type">
|
||||
<el-option
|
||||
v-for="(dbTypeAndDialect, key) in getDbDialectMap()"
|
||||
:key="key"
|
||||
@@ -34,11 +34,15 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.type !== DbType.sqlite" prop="host" label="Host" required>
|
||||
<el-form-item v-if="form.type !== DbType.sqlite" label="Host" required>
|
||||
<el-col :span="18">
|
||||
<el-input v-model.trim="form.host" auto-complete="off"></el-input>
|
||||
<el-form-item prop="host" required>
|
||||
<el-input v-model.trim="form.host" auto-complete="off"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col style="text-align: center" :span="1">:</el-col>
|
||||
|
||||
<el-col class="text-center" :span="1">:</el-col>
|
||||
|
||||
<el-col :span="5">
|
||||
<el-input type="number" v-model.number="form.port" :placeholder="$t('db.port')"></el-input>
|
||||
</el-col>
|
||||
|
||||
@@ -272,10 +272,7 @@ import { formatByteSize, formatDate } from '@/common/utils/format';
|
||||
import { TagResourceTypePath } from '@/common/commonEnum';
|
||||
import { SearchItem } from '@/components/pagetable/SearchForm';
|
||||
import { getTagPathSearchItem } from '../component/tag';
|
||||
import MachineFile from '@/views/ops/machine/file/MachineFile.vue';
|
||||
import ResourceAuthCert from '../component/ResourceAuthCert.vue';
|
||||
import { MachineProtocolEnum } from './enums';
|
||||
import MachineRdpDialogComp from '@/components/terminal-rdp/MachineRdpDialog.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useI18nDeleteConfirm, useI18nDeleteSuccessMsg } from '@/hooks/useI18n';
|
||||
|
||||
@@ -287,6 +284,9 @@ const FileConfList = defineAsyncComponent(() => import('./file/FileConfList.vue'
|
||||
const MachineStats = defineAsyncComponent(() => import('./MachineStats.vue'));
|
||||
const MachineRec = defineAsyncComponent(() => import('./MachineRec.vue'));
|
||||
const ProcessList = defineAsyncComponent(() => import('./ProcessList.vue'));
|
||||
const MachineFile = defineAsyncComponent(() => import('./file/MachineFile.vue'));
|
||||
const ResourceAuthCert = defineAsyncComponent(() => import('../component/ResourceAuthCert.vue'));
|
||||
const MachineRdpDialogComp = defineAsyncComponent(() => import('@/components/terminal-rdp/MachineRdpDialog.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
||||
@@ -87,12 +87,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, Ref } from 'vue';
|
||||
import { ref, toRefs, reactive, Ref, defineAsyncComponent } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import TerminalBody from '@/components/terminal/TerminalBody.vue';
|
||||
import { getMachineTerminalSocketUrl, machineApi } from './api';
|
||||
import { ScriptResultEnum, ScriptTypeEnum } from './enums';
|
||||
import ScriptEdit from './ScriptEdit.vue';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn } from '@/components/pagetable';
|
||||
import { DynamicFormDialog } from '@/components/dynamic-form';
|
||||
@@ -101,6 +99,9 @@ import { useI18n } from 'vue-i18n';
|
||||
import { useI18nCreateTitle, useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nEditTitle } from '@/hooks/useI18n';
|
||||
import { OptionsApi } from '@/components/pagetable/SearchForm/index';
|
||||
|
||||
const ScriptEdit = defineAsyncComponent(() => import('./ScriptEdit.vue'));
|
||||
const TerminalBody = defineAsyncComponent(() => import('@/components/terminal/TerminalBody.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
|
||||
@@ -64,14 +64,15 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, toRefs, watch } from 'vue';
|
||||
import { defineAsyncComponent, reactive, toRefs, watch } from 'vue';
|
||||
import { machineApi } from '../api';
|
||||
import { FileTypeEnum } from '../enums';
|
||||
import MachineFile from './MachineFile.vue';
|
||||
import MachineFileContent from './MachineFileContent.vue';
|
||||
import EnumSelect from '@/components/enumselect/EnumSelect.vue';
|
||||
import { useI18nDeleteConfirm, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||
|
||||
const MachineFile = defineAsyncComponent(() => import('./MachineFile.vue'));
|
||||
const MachineFileContent = defineAsyncComponent(() => import('./MachineFileContent.vue'));
|
||||
|
||||
const props = defineProps({
|
||||
protocol: { type: Number, default: 1 },
|
||||
machineId: { type: Number },
|
||||
|
||||
@@ -309,14 +309,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, reactive, ref, toRefs } from 'vue';
|
||||
import { computed, defineAsyncComponent, onMounted, reactive, ref, toRefs } from 'vue';
|
||||
import { ElInput, ElMessage } from 'element-plus';
|
||||
import { machineApi } from '../api';
|
||||
|
||||
import { joinClientParams } from '@/common/request';
|
||||
import config from '@/common/config';
|
||||
import { isTrue, notBlank } from '@/common/assert';
|
||||
import MachineFileContent from './MachineFileContent.vue';
|
||||
import { getToken } from '@/common/utils/storage';
|
||||
import { convertToBytes, formatByteSize } from '@/common/utils/format';
|
||||
import { getMachineConfig } from '@/common/sysconfig';
|
||||
@@ -325,6 +324,8 @@ import { fuzzyMatchField } from '@/common/utils/string';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useI18nDeleteConfirm, useI18nDeleteSuccessMsg } from '@/hooks/useI18n';
|
||||
|
||||
const MachineFileContent = defineAsyncComponent(() => import('./MachineFileContent.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps({
|
||||
@@ -556,6 +557,8 @@ const setFiles = async (path: string) => {
|
||||
}
|
||||
state.fileNameFilter = '';
|
||||
state.loading = true;
|
||||
state.files = []; // 清空旧数据,可能出现莫名其妙的文件展示错误,先这么处理
|
||||
state.nowPath = '';
|
||||
state.files = await lsFile(path);
|
||||
state.nowPath = path;
|
||||
} finally {
|
||||
|
||||
@@ -22,11 +22,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, reactive, Ref, ref, toRefs, watch } from 'vue';
|
||||
import { computed, reactive, Ref, ref, toRefs, watch, defineAsyncComponent } from 'vue';
|
||||
import { machineApi } from '../api';
|
||||
import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||
import { useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||
|
||||
const MonacoEditor = defineAsyncComponent(() => import('@/components/monaco/MonacoEditor.vue'));
|
||||
|
||||
const props = defineProps({
|
||||
protocol: { type: Number, default: 1 },
|
||||
title: { type: String, default: '' },
|
||||
|
||||
@@ -623,6 +623,13 @@ const delKey = async (key: string) => {
|
||||
padding: 0 10px;
|
||||
height: 29px;
|
||||
}
|
||||
|
||||
::v-deep(.el-tabs__nav-next) {
|
||||
line-height: 29px;
|
||||
}
|
||||
::v-deep(.el-tabs__nav-prev) {
|
||||
line-height: 29px;
|
||||
}
|
||||
}
|
||||
|
||||
.redis-data-op {
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
<script lang="ts" setup>
|
||||
import { toRefs, reactive, onMounted, ref, Ref } from 'vue';
|
||||
import { resourceAuthCertApi } from './api';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn } from '@/components/pagetable';
|
||||
import { SearchItem } from '@/components/pagetable/SearchForm';
|
||||
|
||||
@@ -61,9 +61,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import RoleAllocation from './RoleAllocation.vue';
|
||||
import AccountEdit from './AccountEdit.vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref, defineAsyncComponent } from 'vue';
|
||||
import { AccountStatusEnum } from '../enums';
|
||||
import { accountApi } from '../api';
|
||||
import { formatDate } from '@/common/utils/format';
|
||||
@@ -73,6 +71,9 @@ import { hasPerms } from '@/components/auth/auth';
|
||||
import { SearchItem } from '@/components/pagetable/SearchForm';
|
||||
import { useI18nCreateTitle, useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nEditTitle, useI18nOperateSuccessMsg } from '@/hooks/useI18n';
|
||||
|
||||
const AccountEdit = defineAsyncComponent(() => import('./AccountEdit.vue'));
|
||||
const RoleAllocation = defineAsyncComponent(() => import('./RoleAllocation.vue'));
|
||||
|
||||
const perms = {
|
||||
addAccount: 'account:add',
|
||||
delAccount: 'account:del',
|
||||
|
||||
@@ -45,13 +45,17 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<config-edit :title="$t(configEdit.title)" v-model:visible="configEdit.visible" :data="configEdit.config" @val-change="onConfigEditChange" />
|
||||
<config-edit
|
||||
:title="$t(state.configEdit.title)"
|
||||
v-model:visible="state.configEdit.visible"
|
||||
:data="state.configEdit.config"
|
||||
@val-change="onConfigEditChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import ConfigEdit from './ConfigEdit.vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref, defineAsyncComponent } from 'vue';
|
||||
import { configApi } from '../api';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn } from '@/components/pagetable';
|
||||
@@ -61,6 +65,8 @@ import { SearchItem } from '@/components/pagetable/SearchForm';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||
|
||||
const ConfigEdit = defineAsyncComponent(() => import('./ConfigEdit.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const perms = {
|
||||
@@ -103,7 +109,7 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { query, paramsDialog, configEdit } = toRefs(state);
|
||||
const { query, paramsDialog } = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
if (Object.keys(actionBtns).length > 0) {
|
||||
|
||||
@@ -141,9 +141,8 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, watch } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, watch, defineAsyncComponent } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import ResourceEdit from './ResourceEdit.vue';
|
||||
import { ResourceTypeEnum, RoleStatusEnum } from '../enums';
|
||||
import { resourceApi } from '../api';
|
||||
import { formatDate } from '@/common/utils/format';
|
||||
@@ -154,6 +153,8 @@ import { useI18n } from 'vue-i18n';
|
||||
import { useI18nDeleteConfirm, useI18nDeleteSuccessMsg } from '@/hooks/useI18n';
|
||||
import { getMenuIcon } from './index';
|
||||
|
||||
const ResourceEdit = defineAsyncComponent(() => import('./ResourceEdit.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const menuTypeValue = ResourceTypeEnum.Menu.value;
|
||||
|
||||
@@ -49,20 +49,21 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import RoleEdit from './RoleEdit.vue';
|
||||
import ResourceEdit from './ResourceEdit.vue';
|
||||
import ShowResource from './ShowResource.vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref, defineAsyncComponent } from 'vue';
|
||||
import { roleApi, resourceApi } from '../api';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn } from '@/components/pagetable';
|
||||
import { hasPerms } from '@/components/auth/auth';
|
||||
import { RoleStatusEnum } from '../enums';
|
||||
import { SearchItem } from '@/components/pagetable/SearchForm';
|
||||
import AccountAllocation from './AccountAllocation.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useI18nCreateTitle, useI18nDeleteConfirm, useI18nDeleteSuccessMsg, useI18nEditTitle, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
|
||||
|
||||
const RoleEdit = defineAsyncComponent(() => import('./RoleEdit.vue'));
|
||||
const ShowResource = defineAsyncComponent(() => import('./ShowResource.vue'));
|
||||
const ResourceEdit = defineAsyncComponent(() => import('./ResourceEdit.vue'));
|
||||
const AccountAllocation = defineAsyncComponent(() => import('./AccountAllocation.vue'));
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const perms = {
|
||||
|
||||
Reference in New Issue
Block a user