0.0.3 • Published 2 months ago

vue3-kld-components v0.0.3

Weekly downloads
-
License
ISC
Repository
-
Last release
2 months ago

1.1 介绍


基于 Vue3、Vite4、ant-design-vue4、Pinia、UnoCSS 和 Typescript 的一整套企业级中后台前端/设计解决方案,参考了阿里 react 版本 antd-pro 的设计模式, 使用了最新最流行的前端技术栈,内置了动/静态路由、多主题、多布局、多应用等功能.

特性


  • pnpm:使用了最新的 pnpm 作为包管理工具,它可以大大减少 node_modules 的体积,加快包的安装速度,同时还可以共享依赖,减少磁盘占用。
  • vite:vite 作为前端开发工具,它可以大大加快项目的启动速度,同时还支持热更新,可以大大提高开发效率。
  • vue3:vue3.3.x 作为前端框架,基础代码全部使用 script-setup 的写法,代码量少维护成本低。
  • Mirage JS :采用 Mirage JS 作为服务端的数据,从工程中解耦处理,更加灵活易用。
  • ant-design-vue4:ant-design-vue4 作为 UI 框架。
  • pinia:pinia 作为状态管理工具,可以大大提高代码的可读性和可维护性,同时还支持 Typescript。
  • UnoCSS:原子化的 CSS 框架,减少通用类名带来的烦恼,提升开发效率。
  • 代码规范:封装了一套基于 eslint 的代码规范配置文件,开箱即用,统一不同团队所带来的问题。
  • 主题:延用了 react 版本的 antd-pro 的设计规范,开发了一套基于 vue 的主题模式,在此基础上增加了一些新的功能,尽可能的满足各种不同的需求。
  • 请求函数:基于 axios 封装了一套具有完善类型的请求函数,以及一些基础的拦截器的封装,只需要按照需求做对应的实现调整就能满足各种项目带来的不一样的需求。
  • 移动端兼容:基础框架部分尽可能的对移动端的模式进行了兼容处理,但是由于目标主要是企业级中后台产品,所以并没有对移动端做过多的适配,如果项目需要移动端的适配,可以对代码进行相应的调整。

浏览器支持


本地开发 推荐使用Chrome 最新版浏览器,不支持 Chrome 80以下版本。 生产环境 支持现代浏览器,不支持 IE。由于 vue3 本身对 IE 浏览器不在兼容,所以项目不支持 IE.

IEEdgeFirefoxChromeSafari
not supportlast 2 versionslast 2 versionslast 2 versionslast 2 versions

1.1.1 知识储备


本项目需要一定前端基础知识,请确保掌握 Vue3 的基础知识,以便能处理一些常见的问题。 建议在开发前先学一下以下内容,提前了解和学习这些知识,会对项目理解非常有帮助:

1.2 开始

本部分内容会帮助您从头启动项目。

1.2.1 前言


关于组件 项目虽然二次封装了一些组件,但是可能不能满足大部分的要求。如果组件不满足你的要求,完全可以不用甚至删除代码自己写,不必坚持使用项目自带的组件。

1.2.2 准备工作


本地环境需要安装 Node.js、Pnpm/Npm 注意

  • Node.js 版本要求 18.12.0 或 >= 16.0.0,这里推荐 16.X 及以上

建议包管理工具使用 pnpm,若其他包管理器安装不了需要自行处理

  • Pnpm(建议最新版本) >= 7.0.0

1.2.3 工具配置


推荐使用 VSCode 进行开发,需要安装的插件如下:


1 配置对当前项目的 eslint 的自动保存: 在你的项目根目录下创建一个.vscode/settings.json 的文件(如果存在这个文件,直接修改即可)。

{
  "editor.codeActionsOnSave": {
    "source.fixAll": false, // 关闭全局自定义格式化
    "source.fixAll.eslint": true // 开启eslint保存自动格式化
  }
}

开启后在修改代码后保存,会自动格式化代码。如果不能格式化,请检查是否与全局配置的 setting.json 文件冲突。

2 代码爆红问题:

没有开启 volar takeover 模式。 没有禁用 vetur 插件。 重启 vscode 进入任意一个 vue 文件查看右下角是否显示 vue takeover 的标识,不显示代表没有配置成功

1.2.4 安装


1) 安装 Node: 如果您电脑未安装 Node.js,请安装它。验证

# 出现相应node版本即可
node -v
# 出现相应npm版本即可
npm -v

如果你需要同时存在多个 node 版本,可以使用 nvm 或者其他工具进行 Node.js 进行版本管理。

2) 安装依赖:

(1) pnpm 安装

建议使用 pnpm 进行依赖安装(若其他包管理器安装不了需要自行处理)。 如果未安装 pnpm,可以用下面命令来进行全局安装

# 全局安装pnpm
npm install -g pnpm
# 验证
pnpm -v # 出现对应版本号即代表安装成功

(2) 依赖安装命令

在项目根目录下,打开命令窗口执行,耐心等待安装完成即可

# 安装依赖
pnpm install

1.2.5 npm scripts


"scripts": {
  // 启动开发服务器
  "dev": "vite",
  // 构建项目
  "build": "vite build",
  // 本地预览生产构建产物
  "build:dev": "vite build --mode development",
  // 检测eslint的规范
   "lint": "eslint src --fix"
},

1.2.6 目录说明


├── public                                  # 静态资源文件夹
│   ├── favicon.png                         # favicon
├── src                                     # 主项目文件夹
│   ├── api                                 # 后端请求文件夹,对应各个业务模块
│   │   ├─ dictionary                       # 字典数据api
│   │   ├─ login                            # 登录/退出登录/清除token接口/切换token/修改密码
│   │   ├─ menu                             # 菜单api
│   │   ├─ platform                         # 平台管理模块对应api
│   │   │   ├─ applicationManagement        # 平台管理-平台管理-应用管理
│   │   │   │   ├─ applicationGrouping      # 平台管理-平台管理-应用管理-应用分组
│   │   │   │   ├─ applicationInformation   # 平台管理-平台管理-应用管理-应用信息
│   │   │   │   └─ applicationTags          # 平台管理-平台管理-应用管理-应用标签
│   │   │   ├─ dictionaryManagement         # 平台管理-平台管理-字典管理
│   │   │   │   ├─ applyingDictionaries     # 平台管理-平台管理-字典管理-应用字典
│   │   │   │   └─ dictionaryGrouping       # 平台管理-平台管理-字典管理-字典分组
│   │   │   ├─ logManagement                # 平台管理-平台管理-日志管理
│   │   │   │   ├─ auditLog                 # 平台管理-平台管理-日志管理-审计日志
│   │   │   │   └─ systemLog                # 平台管理-平台管理-日志管理-系统日志
│   │   │   ├─ platformRole                 # 平台管理-平台管理-平台角色
│   │   │   ├─ tenantManagement             # 平台管理-平台管理-租户管理
│   │   │   └─ userManagement               # 平台管理-平台管理-用户管理
│   │   ├─ tenant                           # 平台管理-租户管理模块对应api
│   │   │   ├─ organization                 # 平台管理-租户管理-组织机构
│   │   │   │   ├─ generalPosition          # 平台管理-租户管理-组织机构-通用岗位
│   │   │   │   ├─ organDimension           # 平台管理-租户管理-组织机构-机构纬度
│   │   │   │   ├─ orgManage                # 平台管理-租户管理-组织机构-机构信息
│   │   │   │   ├─ orgPersonnel             # 平台管理-租户管理-组织机构-机构成员
│   │   │   │   ├─ orgType                  # 平台管理-租户管理-组织机构-机构类型
│   │   │   │   └─ positionManagement       # 平台管理-租户管理-组织机构-岗位管理
│   │   │   ├─ rolesManage                  # 平台管理-租户管理-角色管理
│   │   │   └─ tenantMembers                # 平台管理-租户管理-租户成员
│   │   └─ user                             # 用户信息api/应用按钮api(user.ts)/切换租户,机构api(userTenant.ts)
│   ├── assets                              # 本地静态资源
│   ├── components                          # 内置通用组件
│   │   ├─ layouts                          # 布局文件夹
│   │   └─ mkdir                            # 公共组件封装
│   ├── hooks                               # 组合式api文件夹,默认会自动导入
│   ├── config                              # 系统配置
│   │   ├─ common-variables                 # 常用变量
│   │   └─ default-setting.ts               # 主题配置文件
│   ├── locales                             # 全局多语言配置
│   ├── mock                                # 模拟数据
│   ├── pages                               # 页面
│   │   ├─ exception                        # 异常模块
│   │   ├─ home                             # 首页模块
│   │   ├─ login                            # 登录模块
│   │   ├─ platform                         # 平台管理-平台管理模块
│   │   │   ├─ applicationManagement        # 平台管理-平台管理-应用管理
│   │   │   │   ├─ applicationGrouping      # 平台管理-平台管理-应用管理-应用分组
│   │   │   │   ├─ applicationInformation   # 平台管理-平台管理-应用管理-应用信息
│   │   │   │   └─ applicationTags          # 平台管理-平台管理-应用管理-应用标签
│   │   │   ├─ dictionaryManagement         # 平台管理-平台管理-字典管理
│   │   │   │   ├─ applyingDictionaries     # 平台管理-平台管理-字典管理-应用字典
│   │   │   │   └─ dictionaryGrouping       # 平台管理-平台管理-字典管理-字典分组
│   │   │   ├─ logManagement                # 平台管理-平台管理-日志管理
│   │   │   │   ├─ auditLog                 # 平台管理-平台管理-日志管理-审计日志
│   │   │   │   └─ systemLog                # 平台管理-平台管理-日志管理-系统日志
│   │   │   ├─ tenantRoleManagement         # 平台管理-平台管理-平台角色
│   │   │   ├─ tenantManagement             # 平台管理-平台管理-租户管理
│   │   │   └─ userManagement               # 平台管理-平台管理-用户管理
│   │   │  tenant                           # 平台管理-租户管理模块
│   │   │   ├─ organization                 # 平台管理-租户管理-组织机构
│   │   │   │   ├─ generalPosition          # 平台管理-租户管理-组织机构-通用岗位
│   │   │   │   ├─ organDimension           # 平台管理-租户管理-组织机构-机构纬度
│   │   │   │   ├─ orgManage                # 平台管理-租户管理-组织机构-机构信息
│   │   │   │   ├─ orgPersonnel             # 平台管理-租户管理-组织机构-机构成员
│   │   │   │   ├─ orgType                  # 平台管理-租户管理-组织机构-机构类型
│   │   │   │   └─ positionManagement       # 平台管理-租户管理-组织机构-岗位管理
│   │   │   ├─ rolesManage                  # 平台管理-租户管理-角色管理
│   │   │   └─ tenantMembers                # 平台管理-租户管理-租户成员
│   ├── router                              # 路由配置
│   │   ├─ business  			    # 路由文件夹,配置按钮跳转路由
│   │   ├─ module  			    # 路由文件夹,这里对应各个业务模块的静态路由一般用于开发
│   │   ├─ index.ts  			    # 路由入口文件
│   │   ├─ dynamic-routes.ts                # 动态异步路由
│   │   ├─ generate-route.ts                # 动态路由相关方法
│   │   ├─ router-guard.ts                  # 路由引导文件
│   │   ├─ router-modules.ts  		    # 控制动态路由component(路由的组件路径)
│   │   └─ static-routes.ts                 # 常量路由
│   ├── stores                              # 状态管理器相关,默认支持自动导入
│   ├── utils                               # 工具方法
│   ├── App.vue                             # 应用入口组件
│   └── main.ts                             # 项目整体入口
├── types                                   # 类型声明文件夹
├── .env                                    # 环境变量
├── .env.development                        # 开发环境变量
├── .env.production                         # 生产环境变量
├── .eslintignore                           # eslint忽略文件
├── .eslintrc                               # eslint配置文件
├── .gitignore                              # git忽略文件
├── index.html                              # 项目入口文件
├── package.json                            # package.json
├── README.md                               # README.md
├── README.zh-CN.md                         # README.zh-CN.md
├── pnpm-lock.yaml                          # pnpm包管理版本锁定文件
├── tsconfig.json                           # TypeScript 编译器选项
├── tsconfig.node.json                      # 专门用于 vite.config.ts 的 TypeScript 配置文件
├── unocss.config.ts                        # unocss配置文件
└── vite.config.ts                          # vite 配置文件

1.3 项目配置

用于修改项目的环境变量、Ant Design Vue 主题色等配置


项目的环境变量配置位于项目根目录下的 .env、.env.development、.env.production

  .env                # 在所有的环境中被载入
  .env.[mode]         # 只在指定的模式中被载入 如开发环境 .env.development

.env 通用环境适用:

NODE_OPTIONS=--max_old_space_size=2048

## 基础路径
VITE_APP_PUBLIC_PATH = /

## 后端服务代理前缀
VITE_APP_MOCK_PREFIX = /mockApi

## 后端服务代理前缀
VITE_APP_BASE_API_PREFIX = /basiApi

## 后端服务基础路径
VITE_APP_BASE_API = http://11.11.242.101:33002/

## 鉴权认证代理前缀
VITE_APP_OAUTH_API_PREFIX = /oauthApi

# 鉴权认证路径 - 测试应用服务
VITE_APP_OAUTH_API = http://11.11.242.101:33003/

## 路由切换 FRONTEND(静态路由) / BACKEND(动态路由) 
VITE_APP_LOAD_ROUTE_WAY="BACKEND"

##端口号
VITE_APP_BASE_PORT=9080

# 登录模式 mock 本地模拟数据  api  有独立的登录接口  sso 单点登录 有认证中心跳转到认证中心登录
VITE_APP_LOGIN_MODE = api

#单/多应用切换,"true" 为单应用,"false" 为多应用
VITE_APP_IS_SINGLE_APP = 'true'

.env.development 开发环境适用:

## 基础路径
VITE_APP_PUBLIC_PATH = /

## 后端服务代理前缀
VITE_APP_BASE_API_PREFIX = /basiApi

## 后端服务基础路径
VITE_APP_BASE_API = http://11.53.67.12:8002/basic

## 鉴权认证代理前缀
VITE_APP_OAUTH_API_PREFIX = /oauthApi

# 鉴权认证路径 - 测试应用服务
VITE_APP_OAUTH_API = http://11.53.67.12:8001

## 路由切换 FRONTEND(静态路由) / BACKEND(动态路由) 
VITE_APP_LOAD_ROUTE_WAY="BACKEND"

# 登录模式 mock 本地模拟数据  api  有独立的登录接口  sso 单点登录 有认证中心跳转到认证中心登录

VITE_APP_LOGIN_MODE = api

.env.productionn 生产环境适用:

VITE_APP_PUBLIC_PATH = /

## 后端服务代理前缀
VITE_APP_BASE_API_PREFIX = /basiApi

## 后端服务基础路径http://11.11.242.101:33002
VITE_APP_BASE_API = /basiApi

## 鉴权认证代理前缀
VITE_APP_OAUTH_API_PREFIX = /oauthApi

# 鉴权认证路径 - 测试应用服务
VITE_APP_OAUTH_API = http://11.53.67.12:8001

## 路由切换 FRONTEND(静态路由) / BACKEND(动态路由) 
VITE_APP_LOAD_ROUTE_WAY="BACKEND"

# 登录模式  mock 本地模拟数据  api  有独立的登录接口  sso 单点登录 有认证中心跳转到认证中心登录
VITE_APP_LOGIN_MODE = api

1.3.2 项目配置


配置 Ant Design Vue 主题色

使用右侧抽屉来帮助完成布局相关的整体风格、主题色、导航模式、内容区域宽度、固定 Header、固定侧边菜单、色弱模式等配置选择。 然后将拷贝的配置粘贴在 default-setting.ts 的配置中。

export default {
  title: "平台管理", // 配置标题
  theme: "light", // 设置主题色
  logo: "", // 配置展示的logo
  collapsed: false, // 设置菜单是否收起
  drawerVisible: false, // 设置抽屉是否显示
  colorPrimary: "#1677FF", // 设置主题色
  layout: "mix", // 设置布局模式
  contentWidth: "Fluid", // 设置内容区域宽度
  fixedHeader: false, // 设置固定 Header
  fixedSider: true, // 设置固定侧边菜单
  splitMenus: false, // 设置分割菜单
  header: true, // 设置显示 Header
  menu: true, // 设置显示菜单
  menuHeader: true, // 设置显示菜单头部
  footer: false, // 设置显示页脚
  colorWeak: false, // 设置色弱模式
  multiTab: true, // 设置多页签模式
  multiTabFixed: false, // 设置固定多页签
  headerHeight: 48, // 设置头部高度
  copyright: "昆仑数智版权所有", // 设置底部版权信息
};

在 ant-design-vue@4 的版本中,全部使用了 cssinjs 进行重构后,想要封装一些兼容 antd 样式主题风格的组件是比较麻烦的,所以提供了两种可行的实现方案。

方案一

使用提供的 useAntdToken,默认会加载所有的 antd 样式变量,具体的变量信息定制主题。

const { token } = useAntdToken()

const colorPrimary = computed(() => token.value.colorPrimary)

方案二

考虑到部分会抽离成单个的 css 文件,所以提供了 css-var 模式的变量支持,同样,支持也是支持 useAntdToken 中导出的所有变量。

具体使用如下:

  • 在 useAntdToken 中,需要通过 token.colorPrimary 进行使用,那么在 css 文件中需要通过 var(--pro-ant-color-primary)进行使用。

  • 所有的 css-var 变量的前缀都是--pro-ant-开始,驼峰命名,例如 colorPrimary,那么对应的 css-var 就是--pro-ant-color-primary。

.a{
    color: var(--pro-ant-color-primary);
}

uno 用法

对于 unocss,也提供了一套相对简单的使用方案,这种方案是基于 css-var 的方案实现的,已经在 unocss 中进行了内置。

在项目中,你可以通过 c-primary、bg-primary 等方式调用 ant-design-vue 的主题色变量。

  • 目前并没有支持所有的变量,内置的变量如下:

你也可以根据自己的需求,进行自定义的变量,具体的使用方式可以参考 UnoCSS Theme(https://unocss.dev/config/theme) 注意变量列表是驼峰,但是在写类名的时候,需要使用-进行连接,例如 textSecondary,那么对应的类名就是 bg-text-secondary。

内置 css-var 变量:

primary
success
warning
error
info
textBase
bgBase
text
textSecondary
textTertiary
textQuaternary
fill
fillSecondary
fillTertiary
fillQuaternary
bgLayout
bgContainer
bgElevated
bgSpotlight
border
borderSecondary
primaryBg
primaryBgHover
primaryBorder
primaryBorderHover
primaryHover
primaryActive
primaryTextHover
primaryText
primaryTextActive
successBg
successBgHover
successBorder
successBorderHover
successHover
successActive
successTextHover
successText
successTextActive
errorBg
errorBgHover
errorBorder
errorBorderHover
errorHover
errorActive
errorTextHover
errorText
errorTextActive
warningBg
warningBgHover
warningBorder
warningBorderHover
warningHover
warningActive
warningTextHover
warningText
warningTextActive
infoBg
infoBgHover
infoBorder
infoBorderHover
infoHover
infoActive
infoTextHover
infoText
infoTextActive
bgMask
white

小贴士

对于自己重写ant-design-vue的样式,可能也会出现不生效的问题, 需要提升一下类名的等级, 可以通过给自己的类名的前面添加一个#app 类名的形式来保证写的优先级高于ant-design-vue中内置的样式。

#app{
  .test{
    color:red;
  }
  .test1{
    color: green;
  }
}

1.4 路由


路由配置

提供了一套完整的路由系统,可以根据动态路由文件自动生成所需要的菜单结构。

静态路由

静态路由也可以称之为基础路由,是一个完全脱离菜单的路由,可以用于一些不需要菜单的页面,比如登录页、401页面等。

在router/static-routes.ts中来配置的静态路由。

import type { RouteRecordRaw } from 'vue-router'
const Layout = () => import('@/components/layouts/index.vue')

export default [
  {
    path: '/login',
    component: () => import('@/pages/login/login.vue'),
    meta: {
      title: '登录',
    },
  },
  {
    path: '/401',
    name: 'Error401',
    component: () => import('@/pages/exception/401.vue'),
    meta: {
      title: '授权已过期',
    },
  },
  {
    path: '/common',
    name: 'LayoutBasicRedirect',
    component: Layout,
    redirect: '/common/redirect',
    children: [
      {
        path: '/common/redirect',
        component: () => import('@/components/routeView/route-view.vue'),
        name: 'CommonRedirect',
        redirect: '/redirect',
        children: [
          {
            path: '/redirect/:path(.*)',
            name: 'RedirectPath',
            component: () => import('@/components/redirect/redirect.vue'),
          },
        ],
      },

    ],
  },
  {
    path: '/:pathMatch(.*)',
    meta: {
      title: '找不到页面',
    },
    component: () => import('@/pages/exception/error.vue'),
  },
] as RouteRecordRaw[]

路由菜单

菜单的生成完全依赖于路由文件router/dynamic-routes.ts,会自动基于这个文件下的路系统动态的去生成所需要的菜单结构。

所有与菜单相关的参数全部罗列到meta属性下并为菜单扩展了如下的一些参数:

静态路由菜单

静态菜单的生成完全依赖于路由文件router/dynamic-routes.ts,会自动基于这个文件获取@/router/module下的TS文件去生成所需要的菜单结构。 需要在.env环境中配置一下VITE_APP_LOAD_ROUTE_WAY == 'FRONTEND'的加载方式

// 1. 首先导入路由所需的模块和组件
import { RouteRecordRaw } from 'vue-router';

// 2. 创建路由配置对象
const router: RouteRecordRaw = {
  path: '/home',
  name: 'home',

  component: () => import('@/pages/home/index.vue'),
  meta: {
    title: '首页-静态路由',
    icon: 'BankOutlined',
    id: '1000',
    parentId: null,
    menuType: 'menu'
  },
};
// 3. 导出路由配置对象
export default { router, order: 1 };

小贴士

默认情况下,使用的是后端api接口加载菜单的形式,如果你想要通过前端进行加载的话,那么你需要在.env环境中配置一下VITE_APP_LOAD_ROUTE_WAY的加载方式 默认是BACKEND表示后端加载菜单和路由。 改用FRONTEND后会通过src/router/dynamic-routes.ts去加载菜单和路由的信息,此功能支持是在release@0.0.13以及以后支持的。暂不使用

动态路由菜单

在大多数情况下,菜单都是由后端来提供的,所以需要将后端的菜单数据转换成需要的路由结构。

后端菜单的数据结构列如:

interface MenuDataItem {
  // 唯一id
  id?: string | number
  // 标题
  title: string | (() => VNodeChild)
  // 图标
  icon?: string | (() => VNodeChild)
  // 地址
  path: string
  // 绑定的哪个组件,默认自带的组件类型分别是:Iframe、RouteView和ComponentError
  component?: string
  // 子集菜单
  children?: MenuDataItem[]
  // 父级菜单的id
  parentId?: string | number | null
  // 同路由中的name,主要是用于保活的左右
  name?: string
  // 是否隐藏当前菜单
  hiddenMenu?: boolean
  // 如果当前是iframe的模式,需要有一个跳转的url支撑,其不能和path重复,path还是为路由
  url?: string
  // 全连接跳转模式
  target?: '_blank' | '_self' 
}

生成路由中的component的方法是通过,读取pages文件夹下的所有vue文件来实现的: 带有!的表示排除的文件,这些文件都是一些公共的文件,不需要作为路由来生成,如果你还有其他的文件夹需要排除,可以在router/router-modules.ts中进行配置。

const routerModules = import.meta.glob([
  '~/pages/**/*.vue',
  '!~/pages/**/*copy.vue',
  '!~/pages/**/component',
  '!~/pages/**/components',
  '!~/pages/**/hooks',
  '!~/pages/**/modules',
  '!~/pages/**/plugins',
  '!~/pages/**/tests',
  '!~/pages/**/test',
  '!~/pages/**/locales',
  '!~/pages/common',
  '!~/pages/exception',
])

配置规则

在后台添加一个页面的的时候,可以以pages作为根目录,比如pages/system/user/index.vue,那么在后台添加的时候,只需要给component属性一个system/user即可。

如果当前页面是一个父级页面的话,那么可以在后台添加的时候,component需要填写一个RouteView,父级页面需要有一个children属性,用于存放子页面,并且需要配置一个redirect作为重定向的地址。

如果当前是一个iframe页面的话,需要配置一个url属性,这个属性是一个全连接的地址,其中component需要配置为IFrame,比如https://www.baidu.com。

如果当前的页面是一个外链的话,不需要填写component的值或者你可以填写一个RouteView,然后在path属性中配置一个全连接的地址,比如https://www.baidu.com。

1.5请求配置

项目中默认自带了基于axios封装的基础的请求配置,在utils/request.ts中提供了最基础的配置,可以根据自己的需求进行二次扩展

自动导入

  • 为了方便在项目中使用,在hooks/api.ts中提供了自动导入的配置。

  • 默认支持了四种自动请求方式的自动导入,分别是:useGet、usePost、usePut以及useDelete。

请求用法

并没有对api的请求存放位置做过多的封装限制,大家可以根据自己的使用习惯进行使用。

src下创建一个api的目录用于存放所有的请求接口,按照与页面结构相同的分组形式进行使用。

例如在pages/login.vue的页面,可以在api/login.ts中创建一个login的请求接口(loginApi)。

import { oauthPrefix } from '@/api/getPrefix'
import { basePrefix } from '@/api/getPrefix'
import { ContentTypeEnum } from '@/utils/http-enum'

export interface LoginParams {
  username: string
  password: string
  type?: 'account'
  client_id: string
  client_secret: string
  grant_type: string
  redirect_uri?: any
  code?: any
}

export interface LoginResultModel {
  access_token: string
}

export const loginApi = (params: LoginParams) => {
  return usePost<LoginResultModel, LoginParams>(`${oauthPrefix}/oauth/token`, params, {
    headers: {
       'Content-Type': ContentTypeEnum.FORM_URLENCODED
    },
    // 设置为false的时候不会携带token
    token: false,
    // 开发模式下使用自定义的接口
    customDev: true,
    // 是否开启全局请求loading
    loading: true,
  })
}

//退出登录
export const logoutApi = () => {
  return useGet('/auth/logout')
}

/**
 * 清除token接口
 * @param {any} params - 请求的参数。
 * @returns {Promise} - 一个解析清除token结果的Promise。
 * @function
 */
export const removeToken = (params: any) => {
  return useDelete(`${oauthPrefix}/auth/remove_token?access_token=${params}`)
}

/**
 * 切换token接口
 * @param {any} params - 请求的参数。
 * @returns {Promise} - 一个解析切换token结果的Promise。
 * @function
 */
export const switchToken = (params: any) => {
  return useGet(`${oauthPrefix}/authentication/switch?token=${params.token}`,params,{
    notToken: true
  })
}

/**
 * 修改密码接口
 * @param {any} params - 请求的参数。
 * @returns {Promise} - 一个解析修改密码结果的Promise。
 * @function
 */
export const updatePassword = (params: any) => {
  return usePost(`${basePrefix}/uc/s/act/user/updatePassword`, params)
}

在页面中可以直接使用这个请求接口:

<script lang="ts" setup>
import { loginApi } from '@/api/login'

const handleSubmit = async()=>{
  const { data } = await loginApi({
    username: 'admin',
    password: 'admin',
    type: 'account',
    client_id: 'unity-client',
    client_secret: '123456',
    grant_type: 'password',
    redirect_uri: '',
    code: ''
  })
  console.log(data?.token)
}
</script>

1.6全局请求loading使用

全局loading相关配置可在utils/loading.ts中自行更改

如下:

import { useLoading } from '@/hooks/base-loading'
import { LoadingEnum } from '@/loadingEnum'
/**
 * 全局loading配置
 * @param spin loading样式
 * @param minTime loading最短时间
 * @param modal loading遮罩是否开启
 * @param background loading背景
 * @param textColor loading文字颜色
 * @param color loading文字
 */
const loading = useLoading({
  spin: LoadingEnum.CHASE,// PULSE、RECT 、PLANE、CUBE、PRELOADER、 CHASE 、DOT
  minTime: 500,
  // text: '正在加载中...'
  // textColor: '#79bbff'
  // background: 'rgba(0, 0, 0, .5)'
  // modal: true
})

export class AxiosLoading {
  loadingCount: number
  constructor() {
    this.loadingCount = 0
  }

  addLoading() {
    if (this.loadingCount === 0)
      loading.open()

    this.loadingCount++
  }

  closeLoading() {
    if (this.loadingCount > 0) {
      if (this.loadingCount === 1)
        loading.close()
      this.loadingCount--
    }
  }
}

下面是一个简单的例子:

例如在api/common/login.ts中的login接口使用,只需config配置中开启loading即可。

export interface LoginParams {
  username: string
  password: string
}

export interface LoginResultModel {
  token: string
  // 是否开启全局请求loading
  loading: true
}

export const loginApi = (params: LoginParams) => {
  return usePost<LoginResultModel, LoginParams>('/login', params)
}

1.7响应格式


默认情况下,希望后端接口返回的所有数据格式应使用如下的格式:

如若格式不一致,可以在utils/request.ts中进行修改。

export interface ResponseBody<T = any> {
  code: number
  data?: T // data作为一个可选参数,如果没有返回值,可以不传
  msg: string
}

建议使用restful的接口规范,例如:

1.7.1

  • 处理所有请求成功的状态,其中响应的状态码也应为200。
{
  "code": 200,
  "data": {
    "token": "xxxxx"
  },
  "msg": "success"
}

在这种情况下,还可以扩展一些常用的其他的code码,例如:

实现轮询查询某个任务的状态,如果任务还在执行中,可以返回一个100001code码,表示任务还在执行中

{
  "code": 100001,
  "msg": "任务正在执行中"
}

当code码为100002的时候,表示任务执行完成。

{
  "code": 100002,
  "msg": "任务执行完成"
}

就结束前端的轮询任务,等等
  • 处理未授权的请求,例如未登录的请求,响应的状态码应为401。
{
  "code": 401,
  "msg": "未登录"
}
  • 其他错误的请求,例如处理请求登录接口账号密码不正确等等,响应的状态码应为403。
{
  "code": 403,
  "msg": "账号或密码不正确"
}
  • 处理服务器错误的请求,例如处理服务端网关报错的情况,响应的状态码应为500。
{
  "code": 500,
  "msg": "服务器错误"
}

1.8权限管理


在项目中经常有的场景是不同的用户的权限不同,通常有如下场景:

  • 不同的用户在页面中可以看到的元素和操作不同

  • 不同的用户对页面的访问权限不同

  • 在不同的用户权限下你看到的菜单和按钮均不同

1.8.1路由控制

对于路由权限的控制,分为了两种情况,第一种就是采用前端静态路由的配置方式,为这种方式在meta中提供了id和parentId属性, 可以通过它控制层级关系与菜单显示,通过order控制路由排序,如下:

// 1. 首先导入路由所需的模块和组件
import { RouteRecordRaw } from 'vue-router';

// 2. 创建路由配置对象
const router: RouteRecordRaw = {
    path: '/demo',
    name: 'demo',

    component: () => import('@/pages/demo/index.vue'),
    meta: {
        title: '测试',
        icon: 'BankOutlined',
        id: '1000000',
        parentId: null,
        menuType: 'menu'
    },
};
// 3. 导出路由配置对象
export default { router, order: 1 };

1.8.4按钮权限控制/自定义指令控制

提供了内置按钮权限,通过菜单配置创建按钮,根据后台返回数据控制按钮显隐.

定义按钮路径: src/components/mkdir/btn-panel/btn-component/ErpBtnsRow.vue

 <template v-for="btn in curBtns">
      <a-button
        v-hasBtns="btn.code"
        class="btn"
        :class="btn.className"
        :type="btn.type"
        :size="btn.size"
        :disabled="btn.disabled"
        :shape="btn.shape"
        :danger="btn.danger"
        @click="handleClick(btn)"
      >
        <template #icon> <AsyncIcon v-if="btn.icon" :icon="btn.icon" /></template>
        {{ btn.name }}
      </a-button>
    </template>

它的使用方式如下:

    <ErpBtnsRow @click="handleClick" />

1.9服务端配置

采用Mirage JS作为数据服务。

为什么使用Mirage JS

Mirage JS服务尽可能的不要侵入到项目中和尽可能少的修改项目的代码.

优点

无侵入性 独立的服务 可以使用nodejs的任何模块 可以使用typescript进行开发 热更新支持

混合使用

  • 在开发后端的过程中,考虑到开发者并不会一次性的对接所有的数据结构,所以提供了一种混合使用的方案

  • 方便在开发完成一个接口以后,可以进行立即调试,也不会影响其他Mirage JS接口的访问,等完成全部接口的开发后只需要进行环境变量的替换即可

注意 !!!

需要注意的是这种模式只允许在开发模式下使用,在生产环境下不会生效!!! 配置 @/api/getPrefix

let { VITE_APP_LOGIN_MODE, VITE_APP_MOCK_PREFIX, MODE, VITE_APP_BASE_API_PREFIX, VITE_APP_BASE_API, VITE_APP_OAUTH_API_PREFIX } = import.meta.env
// 鉴权服务前缀 认证中心必然跨域,故前缀如此配置
export const oauthPrefix = VITE_APP_LOGIN_MODE === 'mock' ? VITE_APP_MOCK_PREFIX : VITE_APP_OAUTH_API_PREFIX
// 后端服务前缀
export const basePrefix = VITE_APP_LOGIN_MODE === 'mock' ? VITE_APP_MOCK_PREFIX : MODE === 'development' ? VITE_APP_BASE_API_PREFIX : VITE_APP_BASE_API
// mock前缀
export const mockPrefix = VITE_APP_MOCK_PREFIX

export default {
    oauthPrefix,
    basePrefix,
    mockPrefix
}

然后在需要自行调试接口的部分增加一个属性进行控制,例如登录接口@/mock/modules/login.ts:

import { mockPrefix } from "@/api/getPrefix"

export const login = (_this: any) => {
  return _this.post(`${mockPrefix}/oauth/token`, () => {
    let result = {
      message: '张三 欢迎回来',
      access_token: '767b1aba-73ca-406a-ae5b-bb85a8ffd389',
      refresh_token: '767b1aba-73ca-406a-ae5b-bb85a8ffd389',
      expires_in: 8 * 60 * 60 //有效期
    }
    return result
  })
}

通过@/mock/index.ts创建mock数据使用:

import { login } from '@/mock/modules/login'

import { createServer } from "miragejs"
export default function () {
    createServer({
        routes() {
            login(this)
        },
    })
}

2.0

国际化

完整版本的工程支持了国际化的配置

全局的国际化配置

默认情况下,在src/locales下的所有配置文件,表示全局的国际化文件,可以在这里添加一些全局的多语言配置。

locales  ## 国际化目录
├─ index.ts ## 入口
└─ lang ## 国际化配置目录
   ├─ global ## 全局国际化
   │  ├─ en-US.ts
   │  └─ zh-CN.ts
   ├─ pages ## 页面多语言配置
   │  ├─ en-US.ts
   │  └─ zh-CN.ts
   ├─ en-US.ts ## 英文配置
   └─ zh-CN.ts ## 中文配置

模块级别的国际化配置

本身一个项目增加对国际化的支持后,不应将所有的国际化的配置放到全局配置中,应该将多语言的国际化配置分散到各个模块中进行处理。

例如在pages/common中创建一个locales的文件夹用于存放只针对common模块的多语言的配置。

在locales中分别创建zh-CN.ts和en-US.ts的文件,用于导出多语言部分。

zh-CN.ts

export  default {
    common:{
        'login.title':"登录"
    }
}

en-US.ts

export default {
    common:{
        'login.title':"Login"
    }
}

如上配置后,工程会自动加载多语言的配置文件。

需要注意的是 !!!

请确保所有的key均是唯一的,重复的key会被覆盖,如果是模块下的多语言,建议前缀使用模块名.具体的多语言配置,参考如上的配置。

使用

在使用国际化的时候,推荐使用封装过的useI18nLocale的t函数来实现国际化的配置。

这是为了方便后期增加移除多语言功能后的兼容处理方式。