#
zhou zhou
4 天以前 c338f12193ffea6922df314c4cb552ecea762fe3
pages/home/index.vue
@@ -3,123 +3,196 @@
      <view class="user-bg">
         <image src="../../static/img/toux.png" class="tx" mode="widthFix"></image>
         <view class="text-xl margin-top-sm margin-left-lg">
            <view class="text-blue text-bold text-xxl">
               张经理
            <view class="text-blue text-bold text-xl">
               {{user.username}}
            </view>
            <view class="text-gray">仓库主管 | zy32423423</view>
            <view class="text-gray text-l">{{user.code}}</view>
         </view>
         <view class="cu-btn bg-red margin-tb-sm lg round" style="position: absolute; right: 20px; width: 30%; height: 50%;" @click="equit">{{$t('index.outLogin')}}</view>
      </view>
      <view class="cu-bar bg-white solid-bottom margin-top">
         <view class="action">
            <text class="cuIcon-title text-orange "></text> 收货
         </view>
      <!-- 加载中提示 -->
      <view v-if="loading" class="loading-container">
         <text>加载中...</text>
      </view>
      <view class="cu-list grid col-4 no-border">
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/rece/standard" navigateTo>
               <view class="cuIcon-apps text-blue">
               </view>
               <text>标准收货</text>
            </navigator>
      <!-- 动态菜单区域 -->
      <block v-for="category in filteredMenus" :key="category.id">
         <view class="cu-bar bg-white solid-bottom margin-top-sm">
            <view class="action">
               <text class="cuIcon-title text-orange "></text> {{category.name}}
            </view>
         </view>
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/rece/other" navigateTo>
               <view class="cuIcon-taoxiaopu text-blue">
               </view>
               <text>其他收货</text>
            </navigator>
         <view class="cu-list grid col-4 no-border">
            <view class="cu-item" v-for="menu in category.menus" :key="menu.id" @click="goToPage(menu)">
               <view :class="'cuIcon-' + menu.icon + ' text-blue'"></view>
               <text>{{menu.name}}</text>
            </view>
         </view>
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/listing/disc" navigateTo>
               <view class="cuIcon-cardboard text-blue">
               </view>
               <text>组盘</text>
            </navigator>
         </view>
         <!--          <view class="cu-item">
            <navigator hover-class='none' url="/pages/listing/untie" navigateTo>
               <view class="cuIcon-cardboardforbid text-blue">
               </view>
               <text>解绑</text>
            </navigator>
         </view> -->
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/inspect/report" navigateTo>
               <view class="cuIcon-edit text-blue">
               </view>
               <text>报检</text>
            </navigator>
         </view>
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/inspect/check" navigateTo>
               <view class="cuIcon-warn text-blue">
               </view>
               <text>质检</text>
            </navigator>
         </view>
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/inspect/bad" navigateTo>
               <view class="cuIcon-appreciate text-blue">
               </view>
               <text>货物标记</text>
            </navigator>
         </view>
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/listing/labour" navigateTo>
               <view class="cuIcon-friendadd text-blue">
               </view>
               <text>人工上架</text>
            </navigator>
         </view>
         <view class="cu-item">
            <navigator hover-class='none' url="/pages/listing/upper" navigateTo>
               <view class="cuIcon-punch text-blue">
               </view>
               <text>上架</text>
            </navigator>
         </view>
      </block>
      <!-- 无菜单权限时显示提示 -->
      <view v-if="!loading && filteredMenus.length === 0" class="no-permission">
         <text>暂无可用菜单</text>
      </view>
      <!-- <view class="cu-list menu card-menu margin-top-xl margin-bottom-xl shadow-lg radius">
         <view class="cu-item arrow">
            <navigator class="content" url="/pages/userinfo/userinfo" hover-class="none">
               <text class="cuIcon-profile text-blue"></text>
               <text class="text-grey">个人信息</text>
            </navigator>
         </view>
      </view> -->
      <view class="padding flex flex-direction">
         <view class="cu-btn bg-red margin-tb-sm lg round" @click="equit">退出登录</view>
      </view>
   </view>
   </view>
</template>
<script>
   import {
      request
   } from '../../common/request2.js'
   export default {
      data() {
         return {
            user: {},
            menuTree: [],        // 完整菜单树
            permissionIds: new Set(), // 用户权限ID集合
            filteredMenus: [],   // 按分类组织的过滤后菜单
            loading: true        // 加载状态
         }
      },
      onShow() {
         this.user = uni.getStorageSync('userData');
         this.loadMenusAndPermissions();
      },
      methods: {
         // 并行获取菜单和权限数据
         async loadMenusAndPermissions() {
            this.loading = true;
            try {
               const [menuRes, permRes] = await Promise.all([
                  this.fetchMenuTree(),
                  this.fetchPermissions()
               ]);
               this.menuTree = menuRes;
               this.permissionIds = new Set(permRes);
               this.filterMenus();
            } catch (e) {
               console.error('加载菜单权限失败:', e);
               uni.showToast({
                  title: '加载菜单失败',
                  icon: 'none'
               });
            } finally {
               this.loading = false;
            }
         },
         // 获取菜单树
         async fetchMenuTree() {
            const { code, data, msg } = await request('/menuPda/tree', {});
            if (code === 200) {
               return data || [];
            } else if (code === 403) {
               uni.showToast({
                  title: msg,
                  icon: 'none'
               });
               setTimeout(() => {
                  uni.reLaunch({
                     url: '/pages/login/index'
                  });
               }, 1000);
               throw new Error(msg);
            } else {
               throw new Error(msg || '获取菜单失败');
            }
         },
         // 获取权限(支持多角色)
         async fetchPermissions() {
            const roleIds = this.user.userRoleIds || [];
            console.log('roleIds:', roleIds);
            if (roleIds.length === 0) {
               console.warn('用户没有角色ID');
               return [];
            }
            const allIds = [];
            for (const roleId of roleIds) {
               console.log('请求角色权限, roleId:', roleId);
               const ids = await this.fetchRolePermission(roleId);
               console.log('角色权限结果:', ids);
               allIds.push(...ids);
            }
            return [...new Set(allIds)]; // 去重合并
         },
         // 获取单个角色的权限
         async fetchRolePermission(roleId) {
            try {
               const { code, data } = await request('/rolePda/scope/list', { roleId: roleId },'GET');
               if (code === 200) {
                  return data || [];
               }
               return [];
            } catch (e) {
               return [];
            }
         },
         // 过滤菜单并按分类组织
         filterMenus() {
            this.filteredMenus = [];
            for (const category of this.menuTree) {
               if (category.type === 1) continue; // 跳过按钮
               const menus = this.filterChildren(category.children || []);
               // 只有当分类有可见子菜单时才显示该分类
               if (menus.length > 0) {
                  this.filteredMenus.push({
                     id: category.id,
                     name: category.name,
                     menus: menus
                  });
               }
            }
         },
         // 过滤子菜单
         filterChildren(children) {
            return children.filter(item => {
               if (item.type === 1) return false; // 过滤按钮
               return this.permissionIds.has(item.id);
            }).map(item => ({
               id: item.id,
               name: item.name,
               route: '/pages' + item.route,
               icon: item.component || 'apps', // 默认图标
               buttons: this.getButtons(item.children || [])
            }));
         },
         // 获取按钮权限
         getButtons(children) {
            return children.filter(item => item.type === 1 && this.permissionIds.has(item.id))
               .map(btn => ({
                  id: btn.id,
                  name: btn.name,
                  route: btn.route
               }));
         },
         // 检查权限(供其他地方使用)
         hasPermission(id) {
            return this.permissionIds.has(id);
         },
         // 跳转页面并传递按钮权限
         goToPage(menu) {
            // 将按钮权限存入 storage,以 route 为 key
            const buttonRoutes = (menu.buttons || []).map(btn => btn.route);
            uni.setStorageSync('buttonPermissions', buttonRoutes);
            console.log('按钮权限:', buttonRoutes);
            // 跳转页面
            uni.navigateTo({
               url: menu.route
            });
         },
         // 退出登录
         equit() {
            uni.showToast({
               title: '注销成功',
@@ -128,7 +201,7 @@
            setTimeout(() => {
               uni.removeStorageSync('token');
               uni.reLaunch({
                  url: "/pages/login/login"
                  url: "/pages/login/index"
               });
            }, 1000);
         }
@@ -137,38 +210,44 @@
</script>
<style>
   /* .container {
      background-color: #fff;
   } */
   .user-bg {
      display: flex;
      flex-direction: row;
      background-size: cover;
      height: 280rpx;
      height: 150rpx;
      position: relative;
      color: #000;
      align-items: center;
      justify-content: start;
      padding: 0 40rpx;
      background-color: #fff;
   }
   .tx {
      width: 160rpx;
      width: 100rpx;
      border-radius: 50%;
      border: 1px solid #e9e9e9;
   }
   .left {
      display: flex;
      flex-direction: column;
   }
   .avatar {
      width: 160rpx;
      height: 160rpx;
      border-radius: 50%;
   }
   .loading-container {
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 40rpx;
      color: #999;
   }
   .no-permission {
      display: flex;
      justify-content: center;
      align-items: center;
      padding: 80rpx;
      color: #999;
   }
</style>