Vue3 + Antdv4 + Vite5超轻普系统开源!!!

4,873 阅读3分钟

为毛要做个超轻?社区上不是很多启动模板?请看图

image.png image.png

是不是很炫?但是对于启动一个新项目有什么用呢?拉取下来后还得删各种没用的文件和一些不必要的配置

包含通用基础配置的启动框架

1、路由配置

image.png

在modules中插入路由文件自动读取

import { RouteRecordRaw, createRouter, createWebHistory } from "vue-router";

const modules = import.meta.glob("./modules/**/*.ts", {
  eager: true,
  import: "default",
});
const routeModuleList: Array<RouteRecordRaw> = [];
Object.keys(modules).forEach((key) => {
  // @ts-ignore
  routeModuleList.push(...modules[key]);
});

// 存放动态路由
export const asyncRouterList: Array<RouteRecordRaw> = [...routeModuleList];

const routes = [
  {
    path: "/",
    name: "/",
    redirect: asyncRouterList[0].path,
  },
  ...asyncRouterList,
  {
    path: "/login",
    name: "login",
    component: () => import("@/views/login/index.vue"),
  },
  {
    path: "/:catchAll(.*)*",
    name: "404",
    component: () => import("@/views/result/404.vue"),
  },
];

const router = createRouter({
  routes,
  history: createWebHistory(),
});

router.beforeEach((to, from, next) => {
  // TODO 各种操作
  next();
});

export default router;

Axios 配置

对返回的状态码进行异常提示,请求拦截器做了通用的Token注入操作、响应拦截器做了数据处理

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
// import { MessagePlugin, NotifyPlugin } from 'tdesign-vue-next';
import { getUserStore } from "@/store";
import { message, notification } from "ant-design-vue";

interface AxiosConfig extends AxiosRequestConfig {
  method?: "GET" | "POST" | "DELETE" | "PUT";
  url: string;
  params?: Record<string, any>;
  data?: Record<string, any>;
  config?: Record<string, string>;
}

const codeMessage: Record<number, string> = {
  200: "服务器成功返回请求的数据。",
  201: "新建或修改数据成功。",
  202: "一个请求已经进入后台排队(异步任务)。",
  204: "删除数据成功。",
  400: "发出的请求有错误,服务器没有进行新建或修改数据的操作。",
  401: "用户没有权限(令牌、用户名、密码错误)。",
  403: "用户得到授权,但是访问是被禁止的。",
  404: "发出的请求针对的是不存在的记录,服务器没有进行操作。",
  406: "请求的格式不可得。",
  410: "请求的资源被永久删除,且不会再得到的。",
  422: "当创建一个对象时,发生一个验证错误。",
  500: "服务器发生错误,请检查服务器。",
  502: "网关错误。",
  503: "服务不可用,服务器暂时过载或维护。",
  504: "网关超时。",
};

const notificationBox = (status: number, url: string, errorText: string) => {
  return notification.error({
    message: errorText,
    description: `请求错误 ${status}: ${url}`,
  });
};

// 请求错误
const requestInterceptorsError = (error: any) => Promise.reject(error);

// 响应数据
const responseInterceptors = (response: AxiosResponse) => {
  if (response && response.status === 200) {
    const { code } = response.data;
    if (code === -999) {
      message.info("登录过期, 即将跳转登录页面");
      const timer = setTimeout(() => {
        getUserStore().logout();
        clearTimeout(timer);
      }, 2000);
      return null;
    }
    return response.data;
  }
  return response.data;
};
// 响应错误
const responseInterceptorsError = (error: any) => {
  const { response } = error;
  if (response && response.status) {
    const errorText = codeMessage[response.status] || response.statusText;
    const { status } = response;
    const url = response.request.responseURL;

    if (response.status !== 400 && response.status !== 401) {
      notificationBox(status, url, errorText);
    }
    switch (status) {
      case 401:
        notificationBox(status, url, errorText);
        // TODO
        break;
      case 403:
        // TODO
        break;
      default:
        break;
    }
  } else {
    notification.error({
      message: "网络异常",
      description: "您的网络发生异常,无法连接服务器",
    });
  }
  return Promise.reject(error);
};
/** 不能token的接口 */
const noTokenList = ["/login"];

const createAxiosByInterceptors = (
  config?: AxiosRequestConfig
): AxiosInstance => {
  const instance = axios.create({
    // TODO
    baseURL: "/api",
    timeout: 60000,
    headers: {
      "Content-Type": "application/json",
    },
    ...config,
  });

  // 请求拦截器
  instance.interceptors.request.use((config) => {
    const { token } = getUserStore();
    // 如果有 token 强制带上 token
    if (token && config.url && !noTokenList.includes(config.url))
      config.headers.Authorization = token;
    return config;
  }, requestInterceptorsError);
  // 响应拦截器
  instance.interceptors.response.use(
    responseInterceptors,
    responseInterceptorsError
  );
  return instance;
};

const axiosRequest = <T>(axiosParams: AxiosConfig): Promise<T | null> => {
  const { method = "GET", url, params, data, config } = axiosParams;
  const request = createAxiosByInterceptors(axiosParams);

  switch (method) {
    case "GET":
      return request.get(url, { ...params, ...config });
    case "POST":
      return request.post(url, data, config);
    case "DELETE":
      return request.delete(url, { ...data, ...config });
    case "PUT":
      return request.put(url, { ...data, ...config });
    default:
      // 需要添加错误请求
      return Promise.resolve(null);
  }
};

export default axiosRequest;

Pinia状态管理配置

分模块处理用户信息和配置信息,可自加,具体看源码

image.png

layout布局

采用通用的左右分模式

image.png layout组件非常支持自定义、自定性强可根据需求随意改动

通用登录页

看图

image.png

二次封装组件

组件代码全在components文件中可自行修改符合需求的组件

CombineTable

看图就知道有多方便使用了,这点代码就可以生成一个表单查询+表格

image.png

结语

这个框架很轻、几乎拿来就能开发了;

github:github.com/jesseice/an…

可以通过脚手架使用,输入npm create wyd_cli即可下载

框架还会继续优化!!!