优化细节
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<view class="layout-root">
|
||||
<!-- 移动端遮罩层 -->
|
||||
<!-- 统一遮罩层 (复刻 CRMEB: 用于所有 Overlay 状态) -->
|
||||
<view
|
||||
v-if="isMobile && isMobileMenuOpen"
|
||||
class="mobile-mask"
|
||||
@click="isMobileMenuOpen = false"
|
||||
:class="{ 'mask-show': isOverlayVisible || (isMobile && isMobileMenuOpen) }"
|
||||
@click="closeAllMenu"
|
||||
></view>
|
||||
|
||||
<!-- 主侧边栏 (CRMEB风格) -->
|
||||
<!-- 主侧边栏 (CRMEB风格: 70px) -->
|
||||
<AdminAside
|
||||
class="admin-sidebar"
|
||||
:class="{ 'mobile-aside-open': isMobileMenuOpen }"
|
||||
:collapsed="isMainAsideCollapsed"
|
||||
:collapsed="false"
|
||||
:topMenus="topMenus"
|
||||
:activeTopMenuId="activeTopMenuId"
|
||||
@toggle="toggleMainAsideCollapse"
|
||||
@@ -19,14 +19,15 @@
|
||||
:asideWidth="ASIDE_W"
|
||||
/>
|
||||
|
||||
<!-- 二级侧边栏 (CRMEB风格 - 内容区左侧) -->
|
||||
<!-- 二级侧边栏 (1:1 复刻 CRMEB 抽屉/Dock 平滑切换) -->
|
||||
<AdminSubSider
|
||||
v-if="showSubSider && !isMobile"
|
||||
:visible="isSubSiderVisible"
|
||||
:class="{ 'sub-sider-overlay': isSubSiderOverlay || layoutMode === 'mobile' }"
|
||||
:topMenuTitle="activeTopMenuTitle"
|
||||
:groups="activeGroups"
|
||||
:routes="activeRoutes"
|
||||
:activeRouteId="activeRouteId"
|
||||
:asideWidth="ASIDE_W"
|
||||
:asideWidth="layoutMode === 'mobile' ? 0 : ASIDE_W"
|
||||
:siderWidth="SUB_W"
|
||||
@route-click="onRouteClick"
|
||||
/>
|
||||
@@ -41,7 +42,6 @@
|
||||
:breadcrumb="breadcrumb"
|
||||
:hasNotification="hasNotification"
|
||||
:isMobile="isMobile"
|
||||
@toggle-mobile-menu="isMobileMenuOpen = !isMobileMenuOpen"
|
||||
@search="onSearch"
|
||||
@refresh="onRefresh"
|
||||
@notify="onNotify"
|
||||
@@ -93,30 +93,73 @@ import {
|
||||
isMainAsideCollapsed,
|
||||
showSubSider,
|
||||
windowWidth,
|
||||
layoutMode,
|
||||
isMobile,
|
||||
isMobileMenuOpen,
|
||||
isOverlayVisible,
|
||||
openRoute,
|
||||
closeTab,
|
||||
closeOtherTabs,
|
||||
closeAllTabs,
|
||||
toggleMainAsideCollapse as storeToggleCollapse,
|
||||
toggleSubSider as storeToggleSubSider,
|
||||
initNavState
|
||||
} from '@/layouts/admin/store/adminNavStore.uts'
|
||||
import type { TabItem } from '@/layouts/admin/store/adminNavStore.uts'
|
||||
|
||||
import { getComponent } from '@/layouts/admin/router/adminComponentMap.uts'
|
||||
|
||||
// 侧边栏宽度配置
|
||||
const ASIDE_W = 96 // 主侧边栏宽度
|
||||
const SUB_W = 180 // 二级侧边栏宽度
|
||||
// 侧边栏宽度配置 (CRMEB 1:1)
|
||||
const ASIDE_W = 70
|
||||
const SUB_W = 200
|
||||
|
||||
const hasNotification = ref<boolean>(false)
|
||||
|
||||
// 计算主内容区左边距
|
||||
/**
|
||||
* 核心逻辑:计算二级菜单是否应该以 Overlay (抽屉) 模式展示
|
||||
* CRMEB 规则:Tablet 屏 (768~1199) 为 Overlay
|
||||
*/
|
||||
const isSubSiderOverlay = computed<boolean>(() => {
|
||||
return layoutMode.value === 'tablet'
|
||||
})
|
||||
|
||||
/**
|
||||
* 核心逻辑:二级菜单是否可见
|
||||
* 1. 如果有子菜单内容 (activeGroups > 0)
|
||||
* 2. 如果是 Desktop 且 showSubSider 为真 (Dock模式)
|
||||
* 3. 如果是 Tablet/Mobile 且 isOverlayVisible 为真 (Overlay模式)
|
||||
*/
|
||||
const isSubSiderVisible = computed<boolean>(() => {
|
||||
if (activeGroups.value.length === 0) return false
|
||||
|
||||
if (layoutMode.value === 'desktop') {
|
||||
return showSubSider.value
|
||||
}
|
||||
|
||||
// Tablet 和 Mobile 模式下,作为 Overlay 受 isOverlayVisible 控制
|
||||
return isOverlayVisible.value
|
||||
})
|
||||
|
||||
/**
|
||||
* 核心逻辑:计算主内容区左偏移量 (mainLeft)
|
||||
* 严格按照断点策略计算,防止遮挡
|
||||
* 1. Desktop: ASIDE_W + (SUB_W if dock)
|
||||
* 2. Tablet: ASIDE_W (sub-sider 是 overlay,不占位)
|
||||
* 3. Mobile: 0
|
||||
*/
|
||||
const mainLeft = computed<string>(() => {
|
||||
const asideWidth = isMainAsideCollapsed.value ? 0 : ASIDE_W
|
||||
const subWidth = showSubSider.value ? SUB_W : 0
|
||||
return (asideWidth + subWidth) + 'px'
|
||||
if (layoutMode.value === 'mobile') {
|
||||
return '0px'
|
||||
}
|
||||
|
||||
let left = ASIDE_W // 只要不是 Mobile,主侧栏 70px 始终 Dock
|
||||
|
||||
// 只有在 Desktop 模式且二级菜单处于 Dock 模式显示时,才累加宽度
|
||||
if (layoutMode.value === 'desktop' && showSubSider.value && activeGroups.value.length > 0) {
|
||||
left += SUB_W
|
||||
}
|
||||
|
||||
return left + 'px'
|
||||
})
|
||||
|
||||
// 获取一级菜单列表
|
||||
@@ -162,13 +205,28 @@ const currentComponent = computed<any>(() => {
|
||||
|
||||
function onTopMenuClick(menu: TopMenu): void {
|
||||
activeTopMenuId.value = menu.id
|
||||
if (menu.groups.length === 0) {
|
||||
|
||||
// 1:1 复刻 CRMEB 交互:
|
||||
// 1. 如果有子菜单:Desktop 下 dock,Tablet/Mobile 下唤起 Overlay
|
||||
if (menu.groups.length > 0) {
|
||||
if (layoutMode.value === 'desktop') {
|
||||
showSubSider.value = true
|
||||
} else {
|
||||
isOverlayVisible.value = true
|
||||
}
|
||||
} else {
|
||||
// 2. 如果没有子菜单:直接跳转并关闭所有 Overlay
|
||||
openRoute(menu.id + '_index')
|
||||
closeAllMenu()
|
||||
}
|
||||
}
|
||||
|
||||
function onRouteClick(routeId: string): void {
|
||||
openRoute(routeId)
|
||||
// 1:1 复刻 CRMEB:在移动端或平板叠加模式下,点击具体子路由后自动收起
|
||||
if (layoutMode.value !== 'desktop') {
|
||||
closeAllMenu()
|
||||
}
|
||||
}
|
||||
|
||||
function onTabClick(tab: TabItem): void {
|
||||
@@ -191,6 +249,12 @@ function toggleMainAsideCollapse(): void {
|
||||
storeToggleCollapse()
|
||||
}
|
||||
|
||||
function closeAllMenu(): void {
|
||||
isMobileMenuOpen.value = false
|
||||
isOverlayVisible.value = false
|
||||
// 注意:在 Desktop 模式下,closeAllMenu 通常不隐藏 showSubSider,除非用户手动点汉堡按钮
|
||||
}
|
||||
|
||||
function onSearch(): void {
|
||||
uni.showToast({ title: '搜索', icon: 'none' })
|
||||
}
|
||||
@@ -207,19 +271,37 @@ function onNotify(): void {
|
||||
// 生命周期
|
||||
// ============================================
|
||||
|
||||
let resizeTid: any = null
|
||||
|
||||
onMounted(() => {
|
||||
initNavState()
|
||||
|
||||
// 初始化窗口宽度
|
||||
windowWidth.value = uni.getWindowInfo().windowWidth
|
||||
|
||||
// 监听窗口变化
|
||||
// 监听窗口变化 (增加节流保护与跨断点状态重置)
|
||||
uni.onWindowResize((res) => {
|
||||
windowWidth.value = res.size.windowWidth
|
||||
// 窗口变大时自动关闭移动端菜单
|
||||
if (windowWidth.value >= 768) {
|
||||
isMobileMenuOpen.value = false
|
||||
if (resizeTid != null) {
|
||||
cancelAnimationFrame(resizeTid)
|
||||
}
|
||||
|
||||
resizeTid = requestAnimationFrame(() => {
|
||||
const oldMode = layoutMode.value
|
||||
windowWidth.value = res.size.windowWidth
|
||||
const newMode = layoutMode.value
|
||||
|
||||
// 跨断点自动关闭所有 Overlay,防止状态残留遮挡内容
|
||||
if (oldMode != newMode) {
|
||||
isOverlayVisible.value = false
|
||||
isMobileMenuOpen.value = false
|
||||
// 如果切到桌面端,默认展开二级侧栏以符合 CRMEB 习惯
|
||||
if (newMode === 'desktop') {
|
||||
showSubSider.value = true
|
||||
}
|
||||
}
|
||||
|
||||
resizeTid = null
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -237,7 +319,7 @@ onMounted(() => {
|
||||
/* 移动端侧边栏样式 */
|
||||
.mobile-aside {
|
||||
position: absolute;
|
||||
left: -100px; /* 隐藏在左侧 */
|
||||
left: -70px; /* 隐藏在左侧,匹配 ASIDE_W: 70 */
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1001;
|
||||
@@ -246,17 +328,26 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.mobile-aside-open {
|
||||
transform: translateX(100px); /* 移入视图 */
|
||||
transform: translateX(70px); /* 移入视图 */
|
||||
}
|
||||
|
||||
.mobile-mask {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
z-index: 1000;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 300ms ease, visibility 0s linear 300ms;
|
||||
}
|
||||
|
||||
.mask-show {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: opacity 300ms ease, visibility 0s linear 0s;
|
||||
}
|
||||
|
||||
.main {
|
||||
@@ -264,7 +355,7 @@ onMounted(() => {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
transition: margin-left 0.3s ease;
|
||||
transition: margin-left 300ms ease;
|
||||
background: #f0f2f5;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -278,7 +369,7 @@ onMounted(() => {
|
||||
/* 强行改变侧边栏布局模式 */
|
||||
.admin-sidebar {
|
||||
position: absolute !important;
|
||||
left: -100px !important; /* 隐藏在左侧,假设 ASIDE_W 是 96 */
|
||||
left: -70px !important; /* 隐藏在左侧 */
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 1001;
|
||||
@@ -287,7 +378,7 @@ onMounted(() => {
|
||||
|
||||
/* 展开时的状态 */
|
||||
.mobile-aside-open {
|
||||
transform: translateX(100px) !important;
|
||||
transform: translateX(70px) !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,16 +21,18 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="aside-footer" @click="onToggle">
|
||||
<!-- 1:1 复刻 CRMEB: 一级侧边栏通常不单独折叠,由顶部汉堡菜单控制整体 -->
|
||||
<!-- <view class="aside-footer" @click="onToggle">
|
||||
<view class="toggle-btn">
|
||||
<text class="toggle-icon">{{ collapsed ? '>' : '<' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import type { TopMenu } from '@/layouts/admin/router/adminRoutes.uts'
|
||||
import { isMobile } from '@/layouts/admin/store/adminNavStore.uts'
|
||||
|
||||
const props = defineProps<{
|
||||
collapsed: boolean
|
||||
@@ -86,7 +88,7 @@ function onLogoClick(): void {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: width 0.3s ease;
|
||||
z-index: 1000;
|
||||
z-index: 1002; /* 确保在遮罩层之上 */
|
||||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
<view class="header">
|
||||
<view class="header-left">
|
||||
<!-- 移动端菜单切换按钮 (CSS 控制显隐) -->
|
||||
<view class="menu-toggle mobile-only" @click="$emit('toggle-mobile-menu')">
|
||||
<view class="menu-toggle mobile-only" @click="onToggleSubSider">
|
||||
<text class="menu-icon">☰</text>
|
||||
</view>
|
||||
|
||||
<!-- Desktop/Tablet Hamburger (1:1 复刻 CRMEB 切换二级侧边栏) -->
|
||||
<view class="menu-toggle desktop-only" @click="onToggleSubSider">
|
||||
<text class="menu-icon">☰</text>
|
||||
</view>
|
||||
|
||||
@@ -30,6 +35,13 @@
|
||||
|
||||
<script setup lang="uts">
|
||||
import { computed } from 'vue'
|
||||
import {
|
||||
toggleSubSider,
|
||||
showSubSider,
|
||||
layoutMode,
|
||||
isOverlayVisible,
|
||||
isMobileMenuOpen
|
||||
} from '@/layouts/admin/store/adminNavStore.uts'
|
||||
|
||||
const props = defineProps<{
|
||||
breadcrumb: Array<{id: string, title: string}>
|
||||
@@ -44,6 +56,22 @@ defineEmits<{
|
||||
(e:'toggle-mobile-menu'): void
|
||||
}>()
|
||||
|
||||
/**
|
||||
* 核心切换逻辑:
|
||||
* 1. Desktop: 切换 showSubSider (Dock状态)
|
||||
* 2. Tablet: 切换 isOverlayVisible (Overlay状态)
|
||||
* 3. Mobile: 切换 isMobileMenuOpen (Mobile Aside)
|
||||
*/
|
||||
function onToggleSubSider(): void {
|
||||
if (layoutMode.value === 'desktop') {
|
||||
toggleSubSider()
|
||||
} else if (layoutMode.value === 'tablet') {
|
||||
isOverlayVisible.value = !isOverlayVisible.value
|
||||
} else {
|
||||
isMobileMenuOpen.value = !isMobileMenuOpen.value
|
||||
}
|
||||
}
|
||||
|
||||
const currentTitle = computed((): string => {
|
||||
if (props.breadcrumb.length > 0) {
|
||||
return props.breadcrumb[props.breadcrumb.length - 1].title
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<view class="admin-subsider" :style="{ left: asideWidth + 'px', width: siderWidth + 'px' }">
|
||||
<view
|
||||
class="admin-subsider"
|
||||
:class="{ 'is-hidden': !visible }"
|
||||
:style="{ left: asideWidth + 'px', width: siderWidth + 'px' }"
|
||||
>
|
||||
<view class="subsider-header">
|
||||
<text class="header-title">{{ topMenuTitle }}</text>
|
||||
</view>
|
||||
@@ -10,8 +14,8 @@
|
||||
<text>{{ group.title }}</text>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-for="route in getGroupRoutes(group.id)"
|
||||
<view
|
||||
v-for="route in getGroupRoutes(group.id)"
|
||||
:key="route.id"
|
||||
class="menu-item"
|
||||
:class="{ active: route.id === activeRouteId }"
|
||||
@@ -28,6 +32,7 @@
|
||||
import type { MenuGroup, RouteRecord } from '@/layouts/admin/router/adminRoutes.uts'
|
||||
|
||||
const props = defineProps<{
|
||||
visible: boolean // ✅ 新增:由父层控制显示/隐藏(不要用 v-if 卸载)
|
||||
topMenuTitle: string
|
||||
groups: MenuGroup[]
|
||||
routes: Map<string, RouteRecord[]>
|
||||
@@ -56,10 +61,45 @@ function onRouteClick(routeId: string): void {
|
||||
bottom: 0;
|
||||
background: #fff;
|
||||
border-right: 1px solid #e8e8e8;
|
||||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.06);
|
||||
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.05);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
/* ✅ 动画只用 GPU 友好属性,避免 width/left 导致卡顿 */
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
will-change: transform, opacity;
|
||||
|
||||
/* ✅ 可点击时才需要高 z-index */
|
||||
z-index: 999;
|
||||
|
||||
/* ✅ 注意:visibility 默认可见 */
|
||||
visibility: visible;
|
||||
|
||||
/* 显示态:visibility 不延迟 */
|
||||
transition: transform 300ms ease, opacity 250ms ease, visibility 0s linear 0s;
|
||||
}
|
||||
|
||||
/* 悬浮/抽屉模式:复刻 CRMEB 核心逻辑 */
|
||||
.sub-sider-overlay {
|
||||
z-index: 1001;
|
||||
box-shadow: 6px 0 16px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.admin-subsider.is-hidden {
|
||||
/* ✅ 立即禁止拦截点击,彻底解决“遮挡可操作区” */
|
||||
pointer-events: none;
|
||||
|
||||
/* ✅ 先淡出 + 滑出(推荐滑出 100%:完全离开可视区) */
|
||||
opacity: 0;
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
|
||||
/* ✅ 动画结束后再隐藏(避免那一帧还挡住) */
|
||||
visibility: hidden;
|
||||
transition: transform 300ms ease, opacity 250ms ease, visibility 0s linear 300ms;
|
||||
|
||||
/* 可选:进一步避免层叠影响 */
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.subsider-header {
|
||||
@@ -68,7 +108,7 @@ function onRouteClick(routeId: string): void {
|
||||
align-items: center;
|
||||
padding: 0 16px;
|
||||
border-bottom: 1px solid #e8e8e8;
|
||||
|
||||
|
||||
.header-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
@@ -79,7 +119,9 @@ function onRouteClick(routeId: string): void {
|
||||
.subsider-menu {
|
||||
flex: 1;
|
||||
padding: 8px 0;
|
||||
overflow-y: scroll;
|
||||
|
||||
/* ✅ 用 auto,避免一直显示滚动条影响布局 */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.menu-group {
|
||||
@@ -91,7 +133,7 @@ function onRouteClick(routeId: string): void {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
font-weight: 500;
|
||||
|
||||
|
||||
text {
|
||||
display: block;
|
||||
}
|
||||
@@ -103,17 +145,19 @@ function onRouteClick(routeId: string): void {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
position: relative;
|
||||
|
||||
|
||||
/* ✅ 不要 transition: all(会引发布局属性动画/回流) */
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
|
||||
&.active {
|
||||
background: #e6f7ff;
|
||||
color: #1890ff;
|
||||
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
@@ -124,7 +168,7 @@ function onRouteClick(routeId: string): void {
|
||||
background: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.item-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@@ -35,25 +35,30 @@ export const activeRouteId = ref<string>('home_index')
|
||||
/** 打开的标签页列表 */
|
||||
export const tabs = ref<TabItem[]>([])
|
||||
|
||||
/** 是否折叠主侧边栏 */
|
||||
/** 是否折叠主侧边栏 (CRMEB: 70px) */
|
||||
export const isMainAsideCollapsed = ref<boolean>(false)
|
||||
|
||||
/** 是否显示二级侧边栏状态控制 */
|
||||
export const showSubSider = ref<boolean>(true)
|
||||
|
||||
/** 屏幕宽度 */
|
||||
export const windowWidth = ref<number>(1024)
|
||||
|
||||
/** 是否为移动端布局 (width < 768) */
|
||||
export const isMobile = computed<boolean>(() => windowWidth.value < 768)
|
||||
/** 布局模式:desktop | tablet | mobile */
|
||||
export const layoutMode = computed<string>(() => {
|
||||
if (windowWidth.value < 768) return 'mobile'
|
||||
if (windowWidth.value < 1200) return 'tablet'
|
||||
return 'desktop'
|
||||
})
|
||||
|
||||
/** 移动端菜单是否展开 */
|
||||
/** 是否为移动端简易判断 */
|
||||
export const isMobile = computed<boolean>(() => layoutMode.value === 'mobile')
|
||||
|
||||
/** 移动端开关 */
|
||||
export const isMobileMenuOpen = ref<boolean>(false)
|
||||
|
||||
/** 是否显示二级侧边栏 */
|
||||
export const showSubSider = computed<boolean>(() => {
|
||||
if (isMobile.value) return false // 移动端不显式二级侧边栏在主体区域
|
||||
const topMenus = getTopMenus()
|
||||
const activeMenu = topMenus.find(m => m.id === activeTopMenuId.value)
|
||||
return activeMenu ? activeMenu.groups.length > 0 : false
|
||||
})
|
||||
/** 遮罩层开关 (用于 tablet 的 subSider overlay 和 mobile 的 aside overlay) */
|
||||
export const isOverlayVisible = ref<boolean>(false)
|
||||
|
||||
// ============================================
|
||||
// Actions
|
||||
@@ -175,6 +180,13 @@ export function toggleMainAsideCollapse(): void {
|
||||
isMainAsideCollapsed.value = !isMainAsideCollapsed.value
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换二级侧边栏显示状态 (Desktop 模式)
|
||||
*/
|
||||
export function toggleSubSider(): void {
|
||||
showSubSider.value = !showSubSider.value
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化导航状态
|
||||
* 在 AdminLayout 组件 onMounted 时调用
|
||||
|
||||
@@ -29,8 +29,35 @@
|
||||
}
|
||||
|
||||
/* 强制子项允许收缩,防止内部长文本撑爆网格 */
|
||||
.kpi-grid > * {
|
||||
.kpi-grid > *,
|
||||
.kpi-grid-6 > * {
|
||||
min-width: 0 !important;
|
||||
flex: none !important; /* 覆盖旧的 flex 逻辑 */
|
||||
width: auto !important; /* 让 grid 控制宽度 */
|
||||
}
|
||||
|
||||
/* 6-2-1 网格规范 (对标 CRMEB 统计概况) */
|
||||
.kpi-grid-6 {
|
||||
display: grid !important;
|
||||
gap: 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.kpi-grid-6 {
|
||||
grid-template-columns: repeat(6, minmax(0, 1fr)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) and (max-width: 1199.98px) {
|
||||
.kpi-grid-6 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.kpi-grid-6 {
|
||||
grid-template-columns: repeat(1, minmax(0, 1fr)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user