index.vue 5.81 KB
<template>
  <!-- 外层容器:包含蓝色块 + 原始内容 -->
  <view class="page-container">
    <!-- 加载页:覆盖整个容器,渲染完成后隐藏 -->
    <up-loading-page

        :loading="loading"
        loading-text="加载中..."
        color="#577ee3"
        zIndex="1000"
    ></up-loading-page>

    <!-- 蓝色装饰块:#577ee3 -->
    <view class="blue-decor-block" v-show="!loading"></view>

    <!-- 原始内容容器 -->
    <view class="content-wrap">
      <!-- uview-plus空状态组件 -->
      <u-empty
          v-if="!moduleList.length && !loading"
          mode="permission"
      ></u-empty>

      <!-- 菜单卡片列表(替换grid为flex布局) -->
      <view  class="menu-card-wrap">
        <up-card
            :title-size="18"
            :border="false"
            :shadow="true"
            :foot-border-top="false"
            v-for="(parentModule, index) in moduleList"
            :key="`$parentModule.id_${index}`"
            :title="parentModule.name"
            class="card-container"
        >
          <template #body>
            <!-- 替换up-grid:改用flex流式布局容器 -->
            <view class="card-content">
              <view
                  v-for="(listItem, listIndex) in parentModule.children"
                  :key="listItem.id"
                  class="content-block"
                  @click="handleMenuClick(listItem)"
              >
                <u-image
                    :src="listItem.icon"
                    mode="aspectFit"
                    width="80rpx"
                    height="80rpx"
                    lazy-load
                    radius="16rpx"
                    class="block-icon"
                ></u-image>
                <text class="grid-text">{{ listItem.name }}</text>
              </view>
            </view>
          </template>
        </up-card>
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
// 原始代码完全保留,无任何修改
import { ref, nextTick } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { useUserStore } from '@/pinia/user';
import globalConfig from '@/common/config/global';
import cache from '@/common/utils/cache';

interface MenuItem {
  id: number;
  name: string;
  subtitle?: string;
  type: number;
  sort: number;
  parentId: number;
  icon: string;
  jumpUrl: string;
  miniAppId?: string;
  badgeText?: string;
  badgeColor?: string;
  statisticCount: number | null;
  hasStatistic: boolean;
  extra: any;
  children: MenuItem[];
}

const loading = ref(true);
const userStore = useUserStore();
const moduleList = ref<MenuItem[]>([]);

onShow(async () => {
  try {
    loading.value = true;

    const rawMenuData = userStore.moduleListInfo || cache.get(globalConfig.cache.moduleListKey);
    const menuData = rawMenuData || [];
    moduleList.value = menuData;
    //
    // // await nextTick();
    // setTimeout(() => {
    //   loading.value = false;
    // }, 500);
    loading.value = false;
    console.log('菜单数据:', moduleList.value);
  } catch (error) {
    console.error('获取菜单数据失败:', error);
    moduleList.value = [];
    await nextTick();
    loading.value = false;
  }
});

const handleMenuClick = (item: MenuItem) => {
  if (!item.jumpUrl) {
    uni.showToast({
      title: '暂无跳转链接',
      icon: 'none',
      duration: 2000
    });
    return;
  }
  console.log(item.jumpUrl);
  uni.navigateTo({
    url: item.jumpUrl,
    fail: (err) => {
      console.error('页面跳转失败:', err);
      uni.showToast({
        title: '页面路径错误',
        icon: 'none',
        duration: 2000
      });
    }
  });
};
</script>

<style scoped lang="scss">
/* 原有样式保留 + 新增/调整图片居中样式 */
.page-container {
  position: relative; // 新增:让蓝色块绝对定位生效
  min-height: 100vh; // 新增:防止内容高度不足
}

/* 蓝色块样式(保留) */
.blue-decor-block {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 200px;
  background-color: #577ee3;
  z-index: 1;
}

/* 内容容器样式(保留 + 微调) */
.content-wrap {
  position: relative;
  z-index: 2;
  padding: 120px 0 0 ; // 新增左右内边距,避免卡片贴边
  display: flex;
  flex-direction: column;
  gap: 20rpx; // 新增:卡片之间的上下间距
}

/* 菜单卡片容器(新增:统一卡片外层间距) */
.menu-card-wrap {
  width: 100%;
}

/* 卡片容器:重置up-card默认样式 */
.card-container {
  --u-card-content-padding: 0; // 取消卡片默认内边距
  border-radius: 8rpx; // 新增:卡片圆角
  overflow: hidden; // 新增:裁剪内部元素
}

/* 核心:小块容器(Flex 流式布局) */
.card-content {
  display: flex;
  flex-wrap: wrap; // 自动换行
  gap: 20rpx; // 关键:小块之间的上下+左右间距统一

}

/* 小块样式:一行最多4个,宽度自适应 + 内部flex布局 */
.content-block {
  // 宽度计算:(100% - 3*间距) / 4 (4个元素有3个间距)
  width: calc((100% - 3 * 20rpx) / 4);
  // 小块内部样式:改用flex布局,确保子元素居中
  display: flex;
  flex-direction: column;
  align-items: center; // 水平居中(核心:解决图片不居中问题)
  justify-content: center; // 垂直居中(可选,优化视觉)
  padding: 24rpx 0;
  border-radius: 8rpx;
  text-align: center;
  // 点击反馈
  touch-action: manipulation;
  transition: background-color 0.2s;
}

/* 小块点击态 */
.content-block:active {
  background-color: #e9ecef;
}

/* 新增:图片居中样式(兜底保障) */
.block-icon {
  display: block; // 转为块级元素
  margin: 0 auto; // 水平居中(双重保障)
}

/* 网格文字样式(保留 + 微调) */
.grid-text {
  font-size: 26rpx;
  color: #333;
  text-align: center;
  margin-top: 10rpx;
  display: block; // 新增:确保文字换行
}
</style>