feat: tabs
							parent
							
								
									5733a2f2c9
								
							
						
					
					
						commit
						d1eb0dbd13
					
				|  | @ -5,7 +5,7 @@ | |||
| @namespace: vben; | ||||
| 
 | ||||
| // tabs | ||||
| @multiple-height: 30px; | ||||
| @multiple-height: 36px; | ||||
| 
 | ||||
| // headers | ||||
| @header-height: 48px; | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ export function useMultipleTabSetting() { | |||
| 
 | ||||
|   const getShowMultipleTab = computed(() => appStore.getMultiTabsSetting.show) | ||||
| 
 | ||||
|   const getShowMultipleTabIcon = computed(() => appStore.getMultiTabsSetting.showIcon) | ||||
| 
 | ||||
|   const getShowQuick = computed(() => appStore.getMultiTabsSetting.showQuick) | ||||
| 
 | ||||
|   const getShowRedo = computed(() => appStore.getMultiTabsSetting.showRedo) | ||||
|  | @ -21,6 +23,7 @@ export function useMultipleTabSetting() { | |||
|   return { | ||||
|     setMultipleTabSetting, | ||||
|     getShowMultipleTab, | ||||
|     getShowMultipleTabIcon, | ||||
|     getShowQuick, | ||||
|     getShowRedo, | ||||
|     getShowFold | ||||
|  |  | |||
|  | @ -72,7 +72,7 @@ export default defineComponent({ | |||
| 
 | ||||
|     const { getShowHeader, getFixed: getHeaderFixed, getHeaderBgColor, getShowSearch } = useHeaderSetting() | ||||
| 
 | ||||
|     const { getShowMultipleTab, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting() | ||||
|     const { getShowMultipleTab, getShowMultipleTabIcon, getShowQuick, getShowRedo, getShowFold } = useMultipleTabSetting() | ||||
| 
 | ||||
|     const getShowMenuRef = computed(() => { | ||||
|       return unref(getShowMenu) && !unref(getIsHorizontal) | ||||
|  | @ -255,6 +255,13 @@ export default defineComponent({ | |||
| 
 | ||||
|           <SwitchItem title={t('layout.setting.tabs')} event={HandlerEnum.TABS_SHOW} def={unref(getShowMultipleTab)} /> | ||||
| 
 | ||||
|           <SwitchItem | ||||
|             title={t('layout.setting.tabsIcon')} | ||||
|             event={HandlerEnum.TABS_SHOW_ICON} | ||||
|             def={unref(getShowMultipleTabIcon)} | ||||
|             disabled={!unref(getShowMultipleTab)} | ||||
|           /> | ||||
| 
 | ||||
|           <SwitchItem | ||||
|             title={t('layout.setting.tabsRedoBtn')} | ||||
|             event={HandlerEnum.TABS_SHOW_REDO} | ||||
|  |  | |||
|  | @ -36,6 +36,7 @@ export enum HandlerEnum { | |||
|   TABS_SHOW_REDO, | ||||
|   TABS_SHOW, | ||||
|   TABS_SHOW_FOLD, | ||||
|   TABS_SHOW_ICON, | ||||
| 
 | ||||
|   LOCK_TIME, | ||||
|   FULL_CONTENT, | ||||
|  |  | |||
|  | @ -149,6 +149,9 @@ export function handler(event: HandlerEnum, value: any): DeepPartial<ProjectConf | |||
|     case HandlerEnum.TABS_SHOW: | ||||
|       return { multiTabsSetting: { show: value } } | ||||
| 
 | ||||
|     case HandlerEnum.TABS_SHOW_ICON: | ||||
|       return { multiTabsSetting: { showIcon: value } } | ||||
| 
 | ||||
|     case HandlerEnum.TABS_SHOW_REDO: | ||||
|       return { multiTabsSetting: { showRedo: value } } | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,6 +7,9 @@ | |||
|     @menu-event="handleMenuEvent" | ||||
|   > | ||||
|     <div :class="`${prefixCls}__info`" @contextmenu="handleContext" v-if="getIsTabs"> | ||||
|       <span v-if="getShowTabsIcon" :class="`${prefixCls}__prefix-icon`" @click="handleContext"> | ||||
|         <Icon :icon="prefixIconType" /> | ||||
|       </span> | ||||
|       <span class="ml-1">{{ getTitle }}</span> | ||||
|     </div> | ||||
|     <span :class="`${prefixCls}__extra-quick`" v-else @click="handleContext"> | ||||
|  | @ -26,6 +29,7 @@ import { TabContentProps } from '../types' | |||
| import { useDesign } from '@/hooks/web/useDesign' | ||||
| import { useI18n } from '@/hooks/web/useI18n' | ||||
| import { useTabDropdown } from '../useTabDropdown' | ||||
| import { useMultipleTabSetting } from '@/hooks/setting/useMultipleTabSetting' | ||||
| 
 | ||||
| defineOptions({ name: 'TabContent' }) | ||||
| 
 | ||||
|  | @ -46,10 +50,26 @@ const getTitle = computed(() => { | |||
| 
 | ||||
| const getIsTabs = computed(() => !props.isExtra) | ||||
| 
 | ||||
| const prefixIconType = computed(() => { | ||||
|   if (props.tabItem.meta.icon) { | ||||
|     return props.tabItem.meta.icon | ||||
|   } else if (props.tabItem.path === '/dashboard/analysis') { | ||||
|     return 'ant-design:home-outlined' | ||||
|   } else { | ||||
|     return 'ant-design:code' | ||||
|   } | ||||
| }) | ||||
| 
 | ||||
| const getTrigger = computed((): ('contextmenu' | 'click' | 'hover')[] => (unref(getIsTabs) ? ['contextmenu'] : ['click'])) | ||||
| 
 | ||||
| const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown(props as TabContentProps, getIsTabs) | ||||
| 
 | ||||
| const { getShowMultipleTabIcon } = useMultipleTabSetting() | ||||
| 
 | ||||
| const getShowTabsIcon = computed(() => { | ||||
|   return unref(getShowMultipleTabIcon) | ||||
| }) | ||||
| 
 | ||||
| function handleContext(e) { | ||||
|   props.tabItem && handleContextMenu(props.tabItem)(e) | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
| html[data-theme='dark'] { | ||||
|   .@{prefix-cls} { | ||||
|     .ant-tabs-tab { | ||||
|       border-bottom: 1px solid @border-color-base; | ||||
|       border-bottom: none !important; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -11,7 +11,7 @@ html[data-theme='dark'] { | |||
| html[data-theme='light'] { | ||||
|   .@{prefix-cls} { | ||||
|     .ant-tabs-tab:not(.ant-tabs-tab-active) { | ||||
|       border: 1px solid #d9d9d9 !important; | ||||
|       border: none !important; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | @ -21,7 +21,7 @@ html[data-theme='light'] { | |||
|   height: @multiple-height + 2; | ||||
|   line-height: @multiple-height + 2; | ||||
|   background-color: @component-background; | ||||
|   border-bottom: 1px solid @border-color-base; | ||||
|   box-shadow: 0 1px 4px rgb(0 21 41 / 8%); | ||||
| 
 | ||||
|   .ant-tabs-small { | ||||
|     height: @multiple-height; | ||||
|  | @ -29,45 +29,73 @@ html[data-theme='light'] { | |||
| 
 | ||||
|   .ant-tabs.ant-tabs-card { | ||||
|     .ant-tabs-nav { | ||||
|       padding-top: 2px; | ||||
|       height: @multiple-height; | ||||
|       margin: 0; | ||||
|       background-color: @component-background; | ||||
|       border: 0; | ||||
|       box-shadow: none; | ||||
|       padding-left: 10px; | ||||
| 
 | ||||
|       .ant-tabs-nav-container { | ||||
|         height: @multiple-height; | ||||
|         padding-top: 2px; | ||||
|         margin-top: 12px; | ||||
|       } | ||||
| 
 | ||||
|       .ant-tabs-tab { | ||||
|         height: calc(@multiple-height - 2px); | ||||
|         padding-right: 12px; | ||||
|         line-height: calc(@multiple-height - 2px); | ||||
|         height: @multiple-height; | ||||
|         line-height: @multiple-height; | ||||
|         color: @text-color-base; | ||||
|         background-color: @component-background; | ||||
|         transition: none; | ||||
|         transition: padding 0.3s; | ||||
|         padding: 0 24px; | ||||
|         margin: 0 -14px 0 0 !important; | ||||
|         mask: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANoAAAAkBAMAAAAdqzmBAAAAMFBMVEVHcEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlTPQ5AAAAD3RSTlMAr3DvEM8wgCBA379gj5//tJBPAAAAnUlEQVRIx2NgAAM27fj/tAO/xBsYkIHyf9qCT8iWMf6nNQhAsk2f5rYheY7Dnua2/U+A28ZEe8v+F9Ax2v7/F4DbxkUH2wzgtvHTwbYPo7aN2jZq26hto7aN2jZq25Cy7Qvctnw62PYNbls9HWz7S8/G6//PsI6H4396gAUQy1je08W2jxDbpv6nD4gB2uWp+J9eYPsEhv/0BPS1DQBvoBLVZ3BppgAAAABJRU5ErkJggg==); | ||||
|         mask-size: 100% 100%; | ||||
|         position: relative; | ||||
|         z-index: 1; | ||||
| 
 | ||||
|         .ant-tabs-tab-btn { | ||||
|           color: @text-color-base; | ||||
|         } | ||||
| 
 | ||||
|         &:hover { | ||||
|           .ant-tabs-tab-remove { | ||||
|           z-index: 2; | ||||
|           padding: 0 30px 0 36px; | ||||
| 
 | ||||
|           .ant-tabs-tab-remove .anticon-close { | ||||
|             opacity: 1; | ||||
| 
 | ||||
|             &:hover { | ||||
|               color: #fff; | ||||
|               background-color: #c0c4cc; | ||||
|             } | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         .ant-tabs-tab-remove { | ||||
|           width: 8px; | ||||
|           height: 28px; | ||||
|           font-size: 12px; | ||||
|           color: inherit; | ||||
|           opacity: 0; | ||||
|           transition: none; | ||||
|           margin-left: 2px; | ||||
|           margin-right: -4px; | ||||
|           top: 4px; | ||||
|           left: 10px; | ||||
|           margin-right: -10px; | ||||
|           margin-left: 0; | ||||
| 
 | ||||
|           &:hover { | ||||
|             svg { | ||||
|               width: 0.8em; | ||||
|           .anticon-close { | ||||
|             position: relative; | ||||
|             width: 14px; | ||||
|             height: 14px; | ||||
|             font-size: 18px; | ||||
|             color: inherit; | ||||
|             opacity: 0; | ||||
|             transition: opacity 0.15s; | ||||
|             vertical-align: middle; | ||||
|             line-height: 10px; | ||||
|             overflow: hidden; | ||||
|             transform-origin: 100% 50%; | ||||
|             border-radius: 100%; | ||||
| 
 | ||||
|             &:hover { | ||||
|               svg { | ||||
|                 fill: #fff; | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | @ -81,32 +109,51 @@ html[data-theme='light'] { | |||
|         svg { | ||||
|           fill: @text-color-base; | ||||
|         } | ||||
| 
 | ||||
|         &:first-child { | ||||
|           padding: 0 16px !important; | ||||
|         } | ||||
| 
 | ||||
|         &:active { | ||||
|           padding: 0 16px !important; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       .ant-tabs-tab:not(.ant-tabs-tab-active) { | ||||
|         &:hover { | ||||
|           color: @primary-color; | ||||
|           color: inherit; | ||||
|           background-color: #dee1e6; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       .ant-tabs-tab-active { | ||||
|         position: relative; | ||||
|         padding-left: 18px; | ||||
|         background: @primary-color; | ||||
|         padding: 0 20px; | ||||
|         color: @primary-color !important; | ||||
|         background: #e8f4ff; | ||||
|         border: 0; | ||||
|         transition: none; | ||||
|         font-weight: inherit; | ||||
|         z-index: 3; | ||||
| 
 | ||||
|         span { | ||||
|           color: @white !important; | ||||
|           color: @primary-color !important; | ||||
|         } | ||||
| 
 | ||||
|         .ant-tabs-tab-remove { | ||||
|         .ant-tabs-tab-btn { | ||||
|           color: @primary-color; | ||||
|         } | ||||
| 
 | ||||
|         .ant-tabs-tab-remove .anticon-close { | ||||
|           opacity: 1; | ||||
| 
 | ||||
|           svg { | ||||
|             width: 0.6em; | ||||
|           } | ||||
|         } | ||||
| 
 | ||||
|         svg { | ||||
|           width: 0.7em; | ||||
|           fill: @white; | ||||
|           width: inherit; | ||||
|           fill: @primary-color; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | @ -115,7 +162,7 @@ html[data-theme='light'] { | |||
|       padding: 0 6px; | ||||
| 
 | ||||
|       .ant-tabs-tab { | ||||
|         margin-right: 3px !important; | ||||
|         margin-right: -20px !important; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | @ -130,12 +177,18 @@ html[data-theme='light'] { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   .ant-tabs-extra-content { | ||||
|     position: relative; | ||||
|     top: 0; | ||||
|     line-height: calc(@multiple-height - 12px) !important; | ||||
|   } | ||||
| 
 | ||||
|   .ant-dropdown-trigger { | ||||
|     display: inline-flex; | ||||
|   } | ||||
| 
 | ||||
|   &--hide-close { | ||||
|     .ant-tabs-tab-remove { | ||||
|     .ant-tabs-tab-remove .anticon-close { | ||||
|       opacity: 0 !important; | ||||
|     } | ||||
|   } | ||||
|  | @ -173,11 +226,16 @@ html[data-theme='light'] { | |||
|       width: 100%; | ||||
|       height: @multiple-height - 2; | ||||
|       padding-left: 0; | ||||
|       margin-left: -10px; | ||||
|       font-size: 12px; | ||||
|       font-size: 14px; | ||||
|       cursor: pointer; | ||||
|       user-select: none; | ||||
|     } | ||||
| 
 | ||||
|     &__prefix-icon { | ||||
|       & .app-iconify.anticon { | ||||
|         margin-right: 4px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -84,6 +84,7 @@ export default { | |||
|     breadcrumb: 'Breadcrumbs', | ||||
|     breadcrumbIcon: 'Breadcrumbs Icon', | ||||
|     tabs: 'Tabs', | ||||
|     tabsIcon: 'Tabs Icon', | ||||
|     tabDetail: 'Tab Detail', | ||||
|     tabsQuickBtn: 'Tabs quick button', | ||||
|     tabsRedoBtn: 'Tabs redo button', | ||||
|  |  | |||
|  | @ -85,6 +85,7 @@ export default { | |||
|     breadcrumb: '面包屑', | ||||
|     breadcrumbIcon: '面包屑图标', | ||||
|     tabs: '标签页', | ||||
|     tabsIcon: '标签页图标', | ||||
|     tabDetail: '标签详情页', | ||||
|     tabsQuickBtn: '标签页快捷按钮', | ||||
|     tabsRedoBtn: '标签页刷新按钮', | ||||
|  |  | |||
|  | @ -119,6 +119,8 @@ const setting: ProjectConfig = { | |||
|     cache: false, | ||||
|     // 开启
 | ||||
|     show: true, | ||||
|     // 显示图标
 | ||||
|     showIcon: true, | ||||
|     // 开启快速操作
 | ||||
|     showQuick: true, | ||||
|     // 是否可以拖拽
 | ||||
|  |  | |||
|  | @ -39,6 +39,7 @@ export interface MenuSetting { | |||
| export interface MultiTabsSetting { | ||||
|   cache: boolean | ||||
|   show: boolean | ||||
|   showIcon: boolean | ||||
|   showQuick: boolean | ||||
|   canDrag: boolean | ||||
|   showRedo: boolean | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 xingyu
						xingyu