从零开始,手打一个权限管理系统(第八章 完善前端代码)

第八章 整理前端代码


前言

这章主要是清除前端多余的代码,移除不用的模块和包,完善用户管理,角色管理,菜单管理,机构管理!


一、清除多余的模块和代码

1、所有跟mock相关的不需要
2、跟国际化相关的不需要(用的上国际化的可以留着)
3、多余的路由配置不需要
4、其他用不上的组件库


二、Vue请求库

我用的是vue-request,不了解的可以先学习下,后面用到地方很多,像接口请求、手动触发请求、loading、分页、刷新、轮询等,都可以用到。


三、分页配置

用法可以参考vue-request的官方文档。

import { usePagination } from 'vue-request';

分页的默认配置我们自己写一个pagination.ts,放到util目录下

import { PaginationOptions } from 'vue-request';

/**
 * 后台的默认分页查询信息
 */
const defaultPageOptions: PaginationOptions<any, any> = {
  // 默认大小改成20
  // @ts-ignore
  defaultParams: [{ current: 1, size: 10 }] as any,
  // 默认 10毫秒
  loadingDelay: 10,
  // 默认有个10毫秒的判定 阻止连续触发问题 拖到最后
  debounceInterval: 10,
  pagination: {
    /**
     * 后端的分页数据格式
     */
    // 当前页面
    currentKey: 'current',
    // 分页大小的key
    pageSizeKey: 'size',
    // 所有页面
    totalPageKey: 'pages',
    // 总条数
    totalKey: 'total',
  },
};
export default defaultPageOptions;


四、显隐配置

对应模态框的显示和隐藏我们也需要一个公共的方法来统一处理,这个钩子方法我放到hooks目录下。
visible.ts

/**
 * 定义公用模态框的类型信息
 * 方便对模态框弹出等处理
 *
 */

import { computed, watch } from 'vue';

/**
 * 显示隐藏对应的props
 * 和类型信息
 */
export interface Visible {
  visible: boolean;
}

/**
 * 相关的emits对应类型
 * 参数等定义
 */
export interface VisibleEmits {
  (e: 'update:visible', visible: boolean): void;
}

/**
 * composable 对应的显示隐藏属性
 * @param props 属性
 * @param emits 事件
 * @returns
 */
export const useVisible = (props: Visible, emits: VisibleEmits) => {
  // 间接托管的可见状态
  const formVisible = computed({
    get: () => props.visible,
    set: (v) => emits('update:visible', v),
  });

  return {
    formVisible,
    /**
     * 当状态变为打开的时候
     * @param callback 回调执行
     * @returns
     */
    open: (callback: () => any) => watch(formVisible, (v) => v && callback()),
    /**
     * 关闭方法
     */
    close: () => {
      formVisible.value = false;
    },
  };
};


五、动态加载菜单

官方文档都是把路由菜单写死到文件里面的,但是实际项目中都是从后台动态加载的,我们修改一下,改成从后端读取菜单数据。
代码逻辑也很简单,就是在用户登录完成后请求菜单数据,然后组装菜单,添加到路由就可以了,核心代码如下:
MenuStore

import { defineStore } from 'pinia';
import { getMenuList } from '@/api/upms/menu';
import { RouteRecordRaw } from 'vue-router';
import { MenuState, Menu } from './types';

const components = import.meta.glob('@/views/**/index.vue');
const modules = Object.fromEntries(
  Object.entries(components).map(([k, v]) => [k.slice(5, -4), v])
);
const useMenuStore = defineStore('menu', {
  state: (): MenuState => ({
    serverMenu: [],
  }),
  getters: {
    asyncMenus(state: MenuState): RouteRecordRaw[] {
      return state.serverMenu as RouteRecordRaw[];
    },
  },
  actions: {
    generatorDynamicRouter(menuList: Menu[], parent: string): RouteRecordRaw[] {
      return menuList?.map((item) => {
        const { component, name, icon, path, sort, title } = item;
        // ??为NULL判断运算符,运算符左侧的值为null或undefined时,才会返回右侧的值
        const children = item.children ?? [];
        const meta = {
          icon,
          title,
          sort,
        };
        const isChild = children != null && children.length !== 0;
        const currentRouter: RouteRecordRaw = {
          //  路由地址动态拼接生成如 /dashboard/workplace
          path: parent ? `${parent}/${path}` : `${path || ''}`,
          name,
          meta,
          children: [],
          // 动态导入页面
          component:
            !component || component === 'Layout'
              ? () => import('@/layout/default-layout.vue')
              : modules?.[component],
        };
        // 为了防止出现后端返回结果不规范,处理有可能出现拼接出两个 反斜杠
        if (!currentRouter.path.startsWith('http')) {
          currentRouter.path = currentRouter.path.replace('//', '/');
        }
        // 是否有子菜单,并递归处理
        if (isChild) {
          currentRouter.children = this.generatorDynamicRouter(
            children,
            currentRouter.path
          );
        }
        return currentRouter;
      });
    },
    async fetchServerMenuConfig() {
      const data = await getMenuList();
      this.serverMenu = this.generatorDynamicRouter(data, '');
    },
    clearServerMenu() {
      this.serverMenu = [];
    },
  },
});

export default useMenuStore;

路由守卫:
在这里插入图片描述

六、管理页面

管理页面就很简单,参考官方的文档写起来就没啥难度,这里我就不再啰嗦了。前端页面大部分都是相通的,写好一个其他的都可以复用,看看我效果:
在这里插入图片描述

当前版本tag:1.0.7
代码仓库


七、 体验地址

后台数据库只给了部分权限,报错属于正常!
想学的老铁给点点关注吧!!!
不清楚明白的地方欢迎留言,空了我会给大家解答的!!!

我是阿咕噜,一个从互联网慢慢上岸的程序员,如果喜欢我的文章,记得帮忙点个赞哟,谢谢!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值