【功能优化】:新增标签页样式Naive

This commit is contained in:
lipeng 2024-11-28 16:30:17 +08:00
parent 64ebe2bfdb
commit a3a7cf63a8
8 changed files with 356 additions and 2 deletions

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="35" viewBox="0 0 120 35">
<path id="bg" data-name="bg" d="M13.444,35H1.272v0A12.461,12.461,0,0,0,13.444,22.845V8a8,8,0,0,1,8-8H70V35ZM0,34.961v0Z" fill="#e9efff"/>
</svg>

After

Width:  |  Height:  |  Size: 233 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="120" height="35" viewBox="0 0 120 35">
<path id="bg_default" data-name="bg_default" d="M13.444,35H1.272v0A12.461,12.461,0,0,0,13.444,22.845V8a8,8,0,0,1,8-8H70V35ZM0,34.961v0Z" fill="#DEE1E6"/>
</svg>

After

Width:  |  Height:  |  Size: 249 B

View File

@ -24,7 +24,7 @@ export const appDefaultConfig = {
borderRadius: 6, borderRadius: 6,
// 标签页 // 标签页
pageTagFlag: true, pageTagFlag: true,
// 标签页样式: default、 antd // 标签页样式: default、 antd、naive
pageTagStyle: 'default', pageTagStyle: 'default',
// 面包屑 // 面包屑
breadCrumbFlag: true, breadCrumbFlag: true,

View File

@ -31,4 +31,8 @@ export const PAGE_TAG_ENUM = {
value: 'antd', value: 'antd',
desc: 'Ant Design', desc: 'Ant Design',
}, },
NAIVE: {
value: 'naive',
desc: 'NAIVE',
},
}; };

View File

@ -73,7 +73,8 @@
<a-form-item :label="$t('setting.pagetag.style')"> <a-form-item :label="$t('setting.pagetag.style')">
<a-radio-group v-model:value="formState.pageTagStyle" button-style="solid" @change="changePageTagStyle"> <a-radio-group v-model:value="formState.pageTagStyle" button-style="solid" @change="changePageTagStyle">
<a-radio-button value="default">默认</a-radio-button> <a-radio-button value="default">默认</a-radio-button>
<a-radio-button value="antd">Ant Design</a-radio-button> <a-radio-button value="antd">ANTD</a-radio-button>
<a-radio-button value="naive">NAIVE</a-radio-button>
</a-radio-group> </a-radio-group>
</a-form-item> </a-form-item>
<a-form-item :label="$t('setting.pagetag')"> <a-form-item :label="$t('setting.pagetag')">

View File

@ -0,0 +1,340 @@
<!--
* 使用naiveUI <a-tabs> 组件
*
* @Author: 1024创新实验室-主任卓大
* @Date: 2024-11-27 20:29:12
* @Wechat: zhuda1024
* @Email: lab1024@163.com
* @Copyright 1024创新实验室 https://1024lab.net Since 2012
-->
<template>
<!-- 标签页共两部分1标签 2标签操作区 -->
<a-row style="border-bottom: 1px solid #eeeeee; position: relative" v-show="pageTagFlag">
<a-dropdown :trigger="['contextmenu']">
<div class="smart-page-tag">
<a-tabs style="width: 100%" :tab-position="mode" v-model:activeKey="selectedKey" size="small" @tabClick="selectTab">
<a-tab-pane v-for="item in tagNav" :key="item.menuName">
<template #tab>
<span class="smart-tag-content">
<home-outlined style="font-size: 12px" v-if="item.menuName === HOME_PAGE_NAME" class="smart-page-tag-close" />
<component v-else :is="$antIcons[item.menuIcon]" />
{{ item.menuTitle }}
<close-outlined @click.stop="closeTag(item, false)" v-if="item.menuName !== HOME_PAGE_NAME" class="smart-page-tag-close" />
</span>
</template>
</a-tab-pane>
</a-tabs>
</div>
<template #overlay>
<a-menu>
<a-menu-item @click="closeByMenu(false)">关闭其他</a-menu-item>
<a-menu-item @click="closeByMenu(true)">关闭所有</a-menu-item>
</a-menu>
</template>
</a-dropdown>
<a-dropdown>
<!--标签页操作区-->
<div class="smart-page-tag-operate">
<div class="smart-page-tag-operate-icon">
<AppstoreOutlined />
</div>
</div>
<template #overlay>
<a-menu>
<a-menu-item @click="closeByMenu(false)">关闭其他</a-menu-item>
<a-menu-item @click="closeByMenu(true)">关闭所有</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-row>
</template>
<script setup>
import { AppstoreOutlined, CloseOutlined } from '@ant-design/icons-vue';
import { computed, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { HOME_PAGE_NAME } from '/@/constants/system/home-const';
import { useAppConfigStore } from '/@/store/modules/system/app-config';
import { useUserStore } from '/@/store/modules/system/user';
import { theme } from 'ant-design-vue';
//
const pageTagFlag = computed(() => useAppConfigStore().$state.pageTagFlag);
const router = useRouter();
const route = useRoute();
const mode = ref('top');
const tagNav = computed(() => useUserStore().getTagNav || []);
const selectedKey = ref(route.name);
watch(
() => route.name,
(newValue, oldValue) => {
selectedKey.value = newValue;
},
{ immediate: true }
);
//
function selectTab(name) {
if (selectedKey.value === name) {
return;
}
// tag
let tag = tagNav.value.find((e) => e.menuName === name);
if (!tag) {
router.push({ name: HOME_PAGE_NAME });
return;
}
// router.push({ name, query: Object.assign({ _keepAlive: 1 }, tag.menuQuery) });
router.push({ name, query: tag.menuQuery });
}
//
function closeByMenu(closeAll) {
let find = tagNav.value.find((e) => e.menuName === selectedKey.value);
if (!find || closeAll) {
closeTag(null, true);
} else {
closeTag(find, true);
}
}
//
function closeTag(item, closeAll) {
// tag
if (item && !closeAll) {
let goName = HOME_PAGE_NAME;
let goQuery = undefined;
if (item.fromMenuName && item.fromMenuName !== item.menuName && tagNav.value.some((e) => e.menuName === item.fromMenuName)) {
goName = item.fromMenuName;
goQuery = item.fromMenuQuery;
} else {
// tag
let index = tagNav.value.findIndex((e) => e.menuName === item.menuName);
if (index > 0) {
// tag
let leftTagNav = tagNav.value[index - 1];
goName = leftTagNav.menuName;
goQuery = leftTagNav.menuQuery;
}
}
// router.push({ name: goName, query: Object.assign({ _keepAlive: 1 }, goQuery) });
router.push({ name: goName, query: goQuery });
} else if (!item && closeAll) {
// tag
router.push({ name: HOME_PAGE_NAME });
}
// tag closeTagNav
useUserStore().closeTagNav(item ? item.menuName : null, closeAll);
}
const { useToken } = theme;
const { token } = useToken();
const borderRadius = 8 + 'px';
</script>
<style scoped lang="less">
@smart-page-tag-operate-width: 40px;
@color-primary: v-bind('token.colorPrimary');
.smart-page-tag-operate {
width: @smart-page-tag-operate-width;
height: @smart-page-tag-operate-width;
background-color: #ffffff;
font-size: 17px;
text-align: center;
vertical-align: middle;
line-height: @smart-page-tag-operate-width;
padding-right: 10px;
cursor: pointer;
color: #606266;
.smart-page-tag-operate-icon {
width: 20px;
height: 20px;
transition: all 1s;
transform-origin: 10px 20px;
}
.smart-page-tag-operate-icon:hover {
width: 20px;
height: 20px;
transform: rotate(360deg);
}
}
.smart-page-tag-operate:hover {
color: @color-primary;
}
.smart-page-tag {
position: relative;
box-sizing: border-box;
display: flex;
align-content: center;
align-items: flex-end;
justify-content: space-between;
min-height: @page-tag-height;
padding-right: 20px;
padding-left: 20px;
user-select: none;
background: #fff;
width: calc(100% - @smart-page-tag-operate-width);
.smart-page-tag-close {
margin-left: 5px;
font-size: 12px;
color: #666666;
}
/** 覆盖 ant design vue的 tabs 样式,变小一点 **/
:deep(.ant-tabs-nav) {
margin: 0;
// padding: 0 0 2px 0;
min-height: 35px;
min-width: 120px;
box-sizing: border-box;
}
:deep(.ant-tabs-nav::before) {
border-bottom: 1px solid #ffffff;
}
:deep(.ant-tabs-small > .ant-tabs-nav .ant-tabs-tab) {
padding: 5px 18px 3px 24px;
border-radius: v-bind(borderRadius) v-bind(borderRadius) 0 0;
margin: 0 -10px;
&:nth-child(1) {
margin-left: 0 !important;
}
&:nth-last-child(2) {
margin-right: 0 !important;
}
}
.smart-tag-content {
display: inline-block;
min-width: 100px;
&::after {
content: '';
position: absolute;
width: 1px;
height: 16px;
position: absolute;
right: 9px;
z-index: -2;
top: 10px;
background: #666;
}
}
:deep(.ant-tabs-tab-active) {
position: relative;
background-size: 60% 100%;
& + .ant-tabs-tab {
margin-left: -50px;
}
&::before {
content: '';
background: url(/@/assets/images/nav/active_bg2.svg) no-repeat left;
width: 50%;
height: 35px;
// background-size: 130%;
z-index: -1;
position: absolute;
left: -4px;
bottom: 0;
}
&::after {
content: '';
background: url(/@/assets/images/nav/active_bg2.svg) no-repeat left;
width: 50%;
height: 35px;
transform: scaleX(-1);
// background-size: 130%;
z-index: -1;
position: absolute;
right: -4px;
bottom: 0;
}
.smart-tag-content {
&::before {
content: '';
position: absolute;
height: 35px;
background: #e9efff;
width: 60%;
left: 0;
right: 0;
// top: 0;
bottom: 0;
margin: auto;
z-index: -1;
}
&::after {
display: none;
}
}
.smart-page-tag-close {
color: @color-primary;
}
}
:deep(.ant-tabs-ink-bar) {
display: none;
}
:deep(.ant-tabs-nav .ant-tabs-tab:hover) {
&:not(.ant-tabs-tab-active) {
&::before {
content: '';
background: url(/@/assets/images/nav/active_bg2_default.svg) no-repeat left;
width: 50%;
height: 35px;
// background-size: 130%;
z-index: -2;
position: absolute;
left: -4px;
bottom: 0;
}
&::after {
content: '';
background: url(/@/assets/images/nav/active_bg2_default.svg) no-repeat left;
width: 50%;
height: 35px;
transform: scaleX(-1);
// background-size: 130%;
z-index: -1;
position: absolute;
right: -4px;
bottom: 0;
}
.smart-tag-content {
color:rgba(0,0,0,.88);
&::before {
content: '';
position: absolute;
height: 35px;
background: #dee1e6;
width: 60%;
left: 0;
right: 0;
// top: 0;
bottom: 0;
margin: auto;
z-index: -1;
}
&::after {
display: none;
}
}
}
// background-color: #eeeeee;
.smart-page-tag-close {
color: @color-primary;
}
}
}
</style>

View File

@ -11,6 +11,7 @@
<div id="smartAdminPageTag"> <div id="smartAdminPageTag">
<DefaultTab v-if="pageTagStyle === PAGE_TAG_ENUM.DEFAULT.value" /> <DefaultTab v-if="pageTagStyle === PAGE_TAG_ENUM.DEFAULT.value" />
<AntdTab v-if="pageTagStyle === PAGE_TAG_ENUM.ANTD.value" /> <AntdTab v-if="pageTagStyle === PAGE_TAG_ENUM.ANTD.value" />
<NaiveTab v-if="pageTagStyle === PAGE_TAG_ENUM.NAIVE.value" />
</div> </div>
</template> </template>
@ -19,6 +20,7 @@
import { useAppConfigStore } from '/@/store/modules/system/app-config'; import { useAppConfigStore } from '/@/store/modules/system/app-config';
import DefaultTab from './components/default-tab.vue'; import DefaultTab from './components/default-tab.vue';
import AntdTab from './components/antd-tab.vue'; import AntdTab from './components/antd-tab.vue';
import NaiveTab from './components/naive-tab.vue';
import { PAGE_TAG_ENUM } from '/@/constants/layout-const.js'; import { PAGE_TAG_ENUM } from '/@/constants/layout-const.js';
const pageTagStyle = computed(() => useAppConfigStore().$state.pageTagStyle); const pageTagStyle = computed(() => useAppConfigStore().$state.pageTagStyle);

View File

@ -206,6 +206,7 @@ export const useUserStore = defineStore({
// @ts-ignore // @ts-ignore
menuTitle: route.meta.title, menuTitle: route.meta.title,
menuQuery: route.query, menuQuery: route.query,
menuIcon:route.meta?.icon,
// @ts-ignore // @ts-ignore
fromMenuName: from.name, fromMenuName: from.name,
fromMenuQuery: from.query, fromMenuQuery: from.query,