Ant Design Pro初始化

对于如何使用前端脚手架,这里就不在概述,不懂的可以直接查看官网。 官网地址:pro.ant.design/zh-CN 框架的目录结构如图所示: 现在我们开始来移除某些我们不需要的模块。 注意:在移除每一个模块的时候,都要重新运行一下,看项目是否能成功运行,好发现问题。

移除模块

移除husky

一个用来提交前检查代码的规范,保证代码的一致性,一般用于团体协作,个人可以不用使用。 移除相关的命令:

移除mock

mock是官方提供的模拟数据,我们自己有后端接口请求数据,不需要使用到,第一次使用的话,可以直接使用mock来进行查看页面。 使用mock命令:

shell 复制代码
npm start

使用开发命令:

shell 复制代码
npm run dev

移除icons和manifest.json

图标和适配移动端所需要的配置,我们用不到直接删除。

移除cname

官方提供的域名映射

移除国际化

我们自己的项目一般只对大陆开放,国际化根本用不到,所以需要删除。 我们使用删除国际化的命令:

shell 复制代码
npm run i18n-remove

但是在删完国际化会出现以下的错误,这是因为目前的版本中还不支持eslint2022。 以下是删除国际化的正确方法:

  • 前端本地执行以下命令:
shell 复制代码
yarn add eslint-config-prettier --dev
yarn add eslint-plugin-unicorn --dev
  • 找到node_modules/@umijs/lint/dist/config/eslint/index.js文件,注释掉以下代码
shell 复制代码
// es2022: true
  • 最后执行npm run i18n-remove,就能成功删除了
  • 删除完成后我们就可以把locales文件夹了。

这里移除完后,如果登录之后,发现页面没有菜单了,我们需要在routes.ts文件添加name属性

移除单元测试

移除types

我们自己会使用open API插件去生成后端对应接口和类型。这里是官方提供的接口,我们不需要。

移除swagger

移除oneapi.json

删除完后报错的话,是因为这个文件在config.js文件引用到了,所以我们来这边,可以先临时使用下它提供的在线地址,后面我们会换成自己接口文档地址。

javascript 复制代码
/**
   * @name openAPI 插件的配置
   * @description 基于 openapi 的规范生成serve 和mock,能减少很多样板代码
   * @doc https://pro.ant.design/zh-cn/docs/openapi/
   */
  openAPI: [
     {
       requestLibPath: "import { request } from '@umijs/max'",
       // 或者使用在线的版本
       schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json"
       // schemaPath: join(__dirname, 'oneapi.json'),
       mock: false,
     },
  ],

初始化代码

生成接口地址

刚刚在上面我们有提到openAPI的字眼,现在我们就需要来使用这个插件,来帮助我们生成后端接口文档的请求地址,这样就不用在一个一个的写请求了。后端我这里的使用的是springdoc,大家可根据实际文档来生成。

typescript 复制代码
openAPI: [
    {
      requestLibPath: "import { request } from '@umijs/max'",
      schemaPath: 'http://localhost:8090/api/doc-api.html',
      projectName: 'backend-center',
    },
  ],

然后我们来执行命令:所有的命令都可以到package.json查看

shell 复制代码
npm run openapi

它生成的文件会在servies文件夹下。

全局请求配置

目录中有个requestErrorConfig文件,它在app.tsx引入的文件是这样的

typescript 复制代码
/**
 * @name request 配置,可以配置错误处理
 * 它基于 axios 和 ahooks 的 useRequest 提供了一套统一的网络请求和错误处理方案。
 * @doc https://umijs.org/docs/max/request#配置
 */
export const request = {
  ... errConfig
};

我们可以改下名字,并且配置都直接在requestErrorConfig这个文件就好了。 目录和导出的模块名直接改成requestConfig 在app.tsx引入:

tsx 复制代码
export const request = requestConfig;

接下来我们创建文件夹constan,并在里面创建index.ts区分开发环境和生成环境地址:

typescript 复制代码
/**
 * 本地后端地址
 */
export const BACKEND_HOST_LOCAL: string = "http://localhost:8090/api";

/**
 * 线上后端地址
 */
export const BACKEND_HOST_PROD: string = "https://...";

�在requestConfig文件中,官方给的错误处理过于复杂,我们直接简化下,一般后端都会传递token给前端,token一般都会保存在对应的localstorage,这里我对它做了一个封装,然后前端需要在请求头中添加token才能访问对应的接口。

typescript 复制代码
import type {RequestOptions} from '@@/plugin-request/request';
import {history, RequestConfig} from '@umijs/max';
import {message} from 'antd';
import {localCache} from "@/utils/cache";
import {TOKEN} from "@/constant";


// 与后端约定的响应数据格式
interface ResponseStructure {
  success: boolean;
  data: any;
  errorCode?: number;
  errorMessage?: string;
}

// const isDev = process.env.NODE_ENV === 'development';

/**
 * @name 错误处理
 * pro 自带的错误处理, 可以在这里做自己的改动
 * @doc https://umijs.org/docs/max/request#配置
 */
export const requestConfig: RequestConfig = {
  // baseURL: isDev ? BACKEND_HOST_LOCAL : BACKEND_HOST_PROD,
  baseURL: "/api",
  // 请求拦截器
  requestInterceptors: [
    (config: RequestOptions) => {
      // 拦截请求配置,进行个性化处理。
      const token = localCache.getCache(TOKEN);
      if (config.headers && token) {
        config.headers["token"] = 'Bearer ' + token;
      }
       //进入到主页面,并且没有token就重新登录
      if (!token && !location.pathname.includes('/user/login')) {
        // 用户未登录,跳转到登录页
        message.warning("您还未登录,请先登录!")
        window.location.href = `/user/login?redirect=${window.location.href}`;
      }
      return config
    },
  ],

  // 响应拦截器
  responseInterceptors: [
    (response) => {
      //token
      const token: string = localCache.getCache(TOKEN);
      // 拦截响应数据,进行个性化处理
      const {data} = response as unknown as ResponseStructure;
      if (!data) {
        throw new Error('服务异常');
      }
      if (!token && !location.pathname.includes('/user/login') && !location.pathname.includes('/user/register')) {
        message.error("您还未登录,请先登录!");
        history.push("/user/login")
      }
      return response;
    },
  ],
};

修改全局文件

全局文件中有个getInitialState函数,主要是来保存初始状态的,里面有主题样式当前用户加载状态等内容,这里我直接修改成自己后端获取用户信息的接口。

tsx 复制代码
export async function getInitialState(): Promise<{
  settings?: Partial<LayoutSettings>;
  currentUser?: API.User;
  loading?: boolean;
  fetchUserInfo?: () => Promise<API.User | undefined>;
}> {
  const fetchUserInfo = async () => {
    try {
      const res = await getCurrentUser();
      return res.data;
    } catch (error) {
      message.warning("您还未登录,请先登录!")
      history.push(loginPath);
    }
    return undefined;
  };

  // 如果不是登录页面,执行
  const {location} = history;
  if (location.pathname !== loginPath && location.pathname !== registerPath) {
    const currentUser = await fetchUserInfo();
    return {
      fetchUserInfo,
      currentUser,
      settings: defaultSettings as Partial<LayoutSettings>,
    };
  }
  return {
    fetchUserInfo,
    settings: defaultSettings as Partial<LayoutSettings>,
  };
}

�其中getCurrentUser是封装的api,内容如下

typescript 复制代码
/** 获取当前用户 GET /user/currentUser */
export async function getCurrentUser(options?: { [key: string]: any }) {
  return request<API.currentUserResult>('/user/currentUser', {
    method: 'GET',
    ...(options || {}),
  });
}

然后还有个layout的布局配置,有一些我们不需要的直接删掉。 其中里面有头像对应的字段photo,是通过调用接口后端返回的,水印中的内容也是,都需要修改成自己后端返回的字段。

tsx 复制代码
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({initialState}) => {
  return {
    avatarProps: {
      src: initialState?.currentUser?.photo,
      title: <AvatarName/>,
      render: (_, avatarChildren) => {
        return <AvatarDropdown>{avatarChildren}</AvatarDropdown>;
      },
    },
    //水印
    waterMarkProps: {
      content: initialState?.currentUser?.nickname,
    },
    footerRender: () => <Footer/>,
    onPageChange: () => {
      const {location} = history;
      // 如果没有登录,重定向到 login
      if (!initialState?.currentUser && location.pathname !== loginPath) {
        history.push(loginPath);
      }
    },
    menuHeaderRender: undefined,
    // 自定义 403 页面
    // unAccessible: <div>unAccessible</div>,
    ...initialState?.settings,
  };
};

相关推荐
bidepanm几秒前
Vue.use()和Vue.component()
前端·javascript·vue.js
顾平安17 分钟前
手写 PromiseA+ 实现,轻松通过 872 条用例
前端
胡西风_foxww20 分钟前
【ES6复习笔记】对象方法扩展(17)
前端·笔记·es6·对象·方法·扩展·对象方法扩展
bin91531 小时前
npm报错
前端·npm·node.js
一指流沙q1 小时前
Chrome被360导航篡改了怎么改回来?
前端·chrome
laocooon5238578861 小时前
HTML CSS 超链
前端·css·html
LUwantAC2 小时前
CSS(二):美化网页元素
前端·css
m0_748251082 小时前
docker安装nginx,docker部署vue前端,以及docker部署java的jar部署
java·前端·docker
我是ed2 小时前
# thingjs 基础案例整理
前端
Ashore_2 小时前
从简单封装到数据响应:Vue如何引领开发新模式❓❗️
前端·vue.js