Skip to content

使用Vue3组合式API + script setup 语法糖,实现后台管理业务的通用解决方案:路由渲染菜单+页面模糊搜索+全屏+明暗主题切换+RBAC访问控制+i18n国际化。Use Vue3 combined API + script setup syntax sugar to implement a general solution for background management services: routing rendering menu + page fuzzy search + full screen + light and dark theme switching + RBAC access control + i18n internationalization.

License

Notifications You must be signed in to change notification settings

Tmaof/vue3-admin-template-combined-api

Repository files navigation

在线文档

https://www.yuque.com/maofu-rzqcp/snisqw/mtopy4gfmqezmoyd

项目演示

视频演示

概览

https://lark-video.oss-cn-hangzhou.aliyuncs.com/outputs/prod/yuque/2023/34576819/wmv/1694087905309-55475a3b-0d56-4bb5-aa71-692f28d52c3a.mp4?OSSAccessKeyId=LTAI4GGhPJmQ4HWCmhDAn4F5&Expires=1694244040&Signature=Z3hoAXO3x8EVp5vahaJLAKOtOFM%3D

RBAC-访问权限控制

https://lark-video.oss-cn-hangzhou.aliyuncs.com/outputs/prod/yuque/2023/34576819/wmv/1694237431114-4146909f-d64d-4da7-bf3e-13819eb07c7b.mp4?OSSAccessKeyId=LTAI4GGhPJmQ4HWCmhDAn4F5&Expires=1694244726&Signature=nd2%2Fl6lQMcCjP9yALUnt2GZZwIs%3D

https://lark-video.oss-cn-hangzhou.aliyuncs.com/outputs/prod/yuque/2023/34576819/wmv/1694089929549-74c348b3-fcac-41ea-856d-a64e32286abd.mp4?OSSAccessKeyId=LTAI4GGhPJmQ4HWCmhDAn4F5&Expires=1694244040&Signature=MlGG9iQ0TYO1OjVUItnCDao6ZL0%3D

图片预览

PC端

登录页面

image.png

注册页面

image.png

信息提示页

image.png

权限管理页

员工列表

image.png
image.png

角色列表

image.png
image.png

权限列表

image.png
image.png

导航栏折叠

image.png

移动端

登录页面

image.png

注册页面

image.png

信息提示页

image.png

权限管理页

员工列表

image.png
image.png

角色列表

image.png
image.png

权限列表

image.png
image.png

导航栏展开

image.png

功能展示

页面搜索

image.png

多语言

image.png

暗夜模式

image.png

在线体验地址

vue3c-admin在线体验地址


技术栈说明

依赖名 应用于哪些分支 官网
vue3 all https://cn.vuejs.org/guide/introduction.html
vue-cli all Vue CLI
element-plus all 快速开始 | Element Plus
axios all Axios 中文文档 | Axios 中文网 | Axios 是一个基于 promise 的网络请求库,可以用于浏览器和 node.js
vuex 4 all Vuex 是什么? | Vuex
vue router all Vue Router
mock.js
(模拟api接口服务器数据)
除了包含mockjs-pro的分支 Getting Started
mockjs-pro
(
该项目 fork 自 mockjs,修复了 mockjs 中 Mock.mock()不能使用 Promise 和 async 异步函数的 bug。
)
version-RBAC_page
version-RBAC_page-S-T
version-RBAC_page-S-T-i18n
mockjs-pro
dexie
(用于操作IndexedDB数据库)
version-RBAC_page
version-RBAC_page-S-T
version-RBAC_page-S-T-i18n
Dexie.js - Minimalistic IndexedDB Wrapper
md5
(加密密码传输到服务器)
all md5
screenfull all screenfull
vue-i18n version-xxx-i18n Vue I18n | Vue I18n
day.js version-RBAC_page
version-RBAC_page-S-T
version-RBAC_page-S-T-i18n
Day.js · 2kB JavaScript date utility library
xlsx version-RBAC_page
version-RBAC_page-S-T
version-RBAC_page-S-T-i18n
xlsx
file-saver
(文件下载)
version-RBAC_page
version-RBAC_page-S-T
version-RBAC_page-S-T-i18n
file-saver
fuse.js(模糊搜索) version-xxx-search
version-xxx-S-T
fuse.js

选择合适你的版本(分支)

分组 分支名称 包含功能 页面
1
基础本版
version-base 路由渲染菜单栏
明暗切换
全屏
image.png
version-base-i18n 路由渲染菜单栏
明暗切换
全屏
+i18n国际化
2
实现页面模糊搜索
version-seach 路由渲染菜单栏
明暗切换
全屏
+页面模糊搜索
image.png
version-search-i18n 路由渲染菜单栏
明暗切换
全屏
+页面模糊搜索
+i18n国际化
3
实现tags标签栏
version-tagsView 路由渲染菜单栏
明暗切换
全屏
+tags标签栏
image.png
version-tagsView-i18n 路由渲染菜单栏
明暗切换
全屏
+tags标签栏
+i18n国际化
4
同时集成 页面搜索+tags标签栏
version-search-tagsView 路由渲染菜单栏
明暗切换
全屏
+页面模糊搜索
+tags标签栏
image.png
version-search-tagsView-i18n 路由渲染菜单栏
明暗切换
全屏
+页面模糊搜索
+tags标签栏
+i18n国际化
5
实现RBAC访问控制
version-RBAC 路由渲染菜单栏
明暗切换
全屏
+在src\\store\\modules\\routes.js中实现了根据用户权限信息动态添加路由
image.png
version-RBAC-i18n 路由渲染菜单栏
明暗切换
全屏
+在src\\store\\modules\\routes.js中实现了根据用户权限信息动态添加路由
+i18n国际化
version-RBAC_page 路由渲染菜单栏
明暗切换
全屏
+实现RBAC管理页面
image.png
6
集成 页面搜索+tags标签栏+RBAC访问控制
version-RBAC_page-S-T 路由渲染菜单栏
明暗切换
全屏
+页面模糊搜索
+tags标签栏
+实现RBAC管理页面
image.png
version-RBAC_page-S-T-i18n 路由渲染菜单栏
明暗切换
全屏
+页面模糊搜索
+tags标签栏
+实现RBAC管理页面
+i18n国际化

快速开始

克隆该项目

例如

 git clone https://gitee.com/tmaofu/back_office_management.git

安装依赖

进入项目目录,打开终端
先安装yarn包管理器

npm install -g yarn

再安装项目依赖

yarn install

启动项目

npm start

打包输出

npm run build

使用 eslint 代码规范校验

请根据需要修改.eslintrc.js配置文件。

使用 git cz 提交本地仓库

全局安装Commitizen

npm install -g commitizen@4.2.4

修改文件代码
添加到暂存区:

git add .

使用 git cz 代替 git commit :

git cz

在合适的时候移除mockjs

当你已经根据api接口文档,完成了一部分api接口的时候,你想要使用自己的api接口进行测试,那么这时候你就可以删除mock的接口。
例如你已经完成了注册接口,那么你就可以删除以下mock的接口:
image.png
当你已经完成了所有接口时,你可以删除整个mock 文件夹,并在main.js中解除引入:
image.png


目录结构说明

顶层目录概览

image.png
dist:打包后的文件
node_modules:npm包
public:静态资源,不会被压缩
src:

  • api:api接口统一管理
  • assets:存放所需的静态资源
  • components:存放公用组件
  • constant:存放常量,如一些键值
  • directives:存放自定义vue指令
  • filter:存放过滤器
  • i18n:实现国际化
  • layout:实现layout布局页面
  • mock:拦截api请求,放回mock的数据
  • router:app路由
  • store:状态仓库
  • style:存放通用样式文件
  • utility:存放工具性质的文件
  • validator:存放合法性校验的文件
  • views:存放路由页面

image.png

  • App.vue:根组件
  • main.js:入口文件
  • settings.js:该应用的一些配置,可根据需要修改

src目录详解

api:api接口统一管理

├─api
      permission-manage.js //权限列表管理api
      read.md
      role-manage.js //角色列表管理api
      sys.js
      user-manage.js //员工列表管理api

assets:存放所需的静态资源

├─assets
    logo.png 
  
  ├─icon
      index.js //使webpack打包svg图标
    
    └─svg
          	//存放svg图标
  
  ├─img
        //存放图片
  
  └─scss
          reset.scss //清除浏览器默认样式

components:存放公用组件

Breadcrumb

image.png

LanguageSwitch

image.png

LightDarkSwitch

image.png

PageSearch

image.png

ScreenFull

image.png

SvgIcon

使用方式:
使用icon 这个props进行传参,可接收:
1.图标字体类名
2.svg的url
3.'my-'+本地src/assets/icon/svg中的svg名称,例如:icon="my-login"

image.png

TagsView

image.png

UploadExcel

image.png

constant:存放常量,如一些键值

export const TOKEN = 'token'
export const USERLANGUAGE = 'user-language'

directives:存放自定义vue指令

image.png

filter:存放过滤器

import dayjs from 'dayjs'

export function dateFilter(val, format = 'YYYY-MM-DD') {
  if (!isNaN(val)) {
    val = parseInt(val)
  }
  return dayjs(val).format(format)
}

export default function useFilter(vueApp) {
  vueApp.config.globalProperties.$filters = {
    dateFilter
  }
}

i18n:实现国际化

layout:实现layout布局页面

AppMain

image.png

NavBar

image.png

SideBar

image.png

SidebarItem

image.png

SidebarMenu

image.png

mock:拦截api请求,反回mock(模拟)的数据

├─mock
    index.js //入口文件
    permission-list.js //拦截权限列表相关的api
    role-manage.js //拦截角色列表相关的api
    sys.js //拦截登录,注册相关的api
    user-manage.js //拦截员工列表相关的api
  
  └─IndexedDB
          index.js //操作IndexedDB数据库的方法

router:app路由

├─router
      index.js //入口文件,配置路由对象
      permission.js //定义全局前置导航守卫
      routes.js //定义 公有路由和私有路由

store:状态仓库

├─store
    getters.js //类似计算属性
    index.js //入口文件
  
  └─modules
          layout.js //关于layout布局页面的状态仓库
          routes.js //关于路由的状态仓库
          user.js //关于用户的状态仓库

style:存放通用样式文件

├─style
      index.scss
      mobile.scss //一些通用的全局移动端样式
      theme-dark.scss //暗夜主题样式
      theme-filter-invert-dark.scss //使用css-filter 实现暗夜主题样式
      theme-filter-invert-light.scss //使用css-filter 实现明亮主题样式
      theme-light.scss //明亮主题样式
      variables-dark.scss //暗夜主题使用的颜色变量
      variables-light.scss //明亮主题使用的颜色变量
      variables.scss //一些样式变量

utility:存放工具性质的文件

├─utility
      export2Excel.js //导出为excel
      get-screen-info.js //获取屏幕信息,判断是否是移动端
      request.js //封装axios
      resolveBugs.js //解决element-plus 报错问题
      set-document-title.js //设置文档标题
      storage.js //封装localStorage

validator:存放合法性校验的文件

├─validator
      index.js //包含 登录注册密码校验规则

views:存放路由页面

404

image.png

Acl

Menu

image.png

Role

image.png

User

image.png

Client

image.png

Info

image.png

Login

image.png

Register

image.png

App.vue:根组件

<template>
  <div class="app-container">
    <router-view></router-view>
  </div>
</template>

<style lang="scss" scoped>
.app-container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
</style>

main.js:入口文件

settings.js:该应用的一些配置,可根据需要修改

import i18n from '@/i18n'
export default {
  /**
   * 页面标题
   */
  pageTile: i18n.$t('src.settings.808362-0'),

  /**
   * 侧边栏
   */
  sideBar: {
    // sideBarLogo: {
    //   isShow: true,
    //   type: 'text', // 'text'or'img'
    //   value: '后台管理系统'
    // },
    sideBarLogo: {
      isShow: true,
      type: 'img', // 'text'or'img'
      value: '/favicon.ico'
    },
    uniqueOpened: true, // 是否只保持一个子菜单的展开
    // 侧边栏宽度
    initWidth: 200, // 初始宽度,填写整数,单位是px
    minDargWidth: 180, // 最小宽度
    maxDargWidth: 250, // 最大宽度
    mobileCollapseToZero: true // 为移动端页面时,收缩侧边栏宽度到0
  },

  /**
   * 顶部导航栏
   */
  narBarFixed: true, // 是否固定导航条
  narBarSeparator: '/' // 面包屑分隔符
}

功能使用指南

根据路由表渲染侧边栏菜单功能

公共路由表 与 私有路由表

路由表的配置在 src\router\routes.js中,如果要添加公共路由记录请添加在 publicRoutes中,如果要添加私有路由记录请添加在 privateRoutes中。

字段说明

        {
          path: 'client',
          name: 'client-management',
          meta: {
            title: '客户管理',//会显示为菜单名称
            icon: 'my-user'//配置菜单名称左侧的图标,使用自定义SvgIcon组件实现,可选值可以查看SvgIcon组件的说明。
          },
          component: () => import('@/views/Client')
        }

顶层菜单

效果 实现方式
image.png src\\router\\routes.js的路由表中添加类似这样一条记录```javascript
{
  path: '/',
  component: Layout,
  children: [
    {
      path: 'client',
      name: 'client-management',
      meta: {
        title: i18n.$t('router.routes.817884-1'),
        icon: 'my-user'
      },
      component: () => import('@/views/Client')
    }
  ]
},
 |

<a name="f0ExB"></a>
### 子级菜单
| **效果** | **实现方式** |
| --- | --- |
| ![image.png](https://cdn.nlark.com/yuque/0/2023/png/34576819/1694154280116-c4e82107-80c4-46cc-a21b-a7d76f02e2c0.png#averageHue=%23fcfbfb&clientId=uc900d602-642b-4&from=paste&height=611&id=u272590e6&originHeight=916&originWidth=298&originalType=binary&ratio=1.5&rotation=0&showTitle=false&size=23792&status=done&style=none&taskId=u5e052a1f-ced6-49c1-88c2-f2642104247&title=&width=198.66666666666666) | 在 `src\\router\\routes.js`的路由表中添加类似这样一条记录```javascript
    {
      path: '/info',
      component: Layout,
      redirect: '/info/info',
      meta: {
        title: i18n.$t('router.routes.817884-0'),
        icon: 'my-info'
      },
      children: [
        {
          path: 'info',
          name: 'info',
          component: () => import('@/views/Info'),
          meta: {
            title: i18n.$t('router.routes.817884-0'),
            icon: 'my-info'
          }
        }
      ]
    },

|

多层菜单

效果 实现方式
image.png src\\router\\routes.js的路由表中添加类似这样一条记录```javascript
{
path: '/info',
component: Layout,
redirect: '/info/info',
meta: {
title: i18n.$t('router.routes.817884-0'),
  icon: 'my-info'
},

children: [ { path: 'info', name: 'info', component: () => import('@/views/Info'), meta: { title: i18n.$t('router.routes.817884-0'), icon: 'my-info' }, children: [ { path: 'info', name: 'info', component: () => import('@/views/Info'), meta: { title: i18n.$t('router.routes.817884-0'), icon: 'my-info' } } ] } ] },

 |


<a name="HKVhp"></a>
## 页面搜索功能
只要配置了路由表,并且改登录用户拥有该路由记录,就可以进行模糊搜索。具体实现可以查看:`src\components\PageSearch`

<a name="QCE6s"></a>
## 动态路由表/RBAC功能
首先,请查看`src\router\permission.js`中 路由导航守卫的逻辑
​```javascript
...
    // 需要需要权限的页面
    else {
      // 有token,已经登录过
      if (store.getters.token) {
        // 状态仓库中是否有用户信息,
        // 如果有:代表没有刷新页面|不是重新访问web应用,这时是不需要判断token是否过期的。
        if (store.getters.userInfo) {
          next()
          // eslint-disable-next-line brace-style
        }
        // 没有用户信息,代表用户刚刚访问本站
        else {
          // 用已有的token去获取用户信息,看token是否过期
          const ok = await store.dispatch('user/getUserInfo')

          if (ok) {
            // 没有过期,放行
            // 由于在导航守卫中添加了动态路由,所以需要重定向,而不是直接next()
            next(to.fullPath)
          } else {
            // token过期,需要用户重新登录
            // 先清除token,才能跳转登录页
            ElMessage.warning(i18n.t('router.permission.808363-0'))
            store.commit('user/SET_token', '')
            next('/login')
          }
        }
        // eslint-disable-next-line brace-style
      }
      // 无token,没有登录过,需要让用户登录
      else {
        next('/login')
      }
    }
...

当用户首次访问该网站是由于没有token,会先跳转到登录页,进行登录

// 处理登录
function handleLogin() {
  // 参数校验
  if (loginFromRef.value) {
    loginFromRef.value.validateField().then(() => {
      // 动画
      isLoading.value = true
      // 发请求
      store
        .dispatch('user/login', loginForm)
        .then(() => {
          // 如果有重定向参数redirect,将进行重定向
          router.push({
            path: route.query.redirect ? route.query.redirect : '/'
          })
          ElMessage.success({ message: i18n.t('Login.index.808362-5') })
        })
        .finally(() => {
          isLoading.value = false
        })
    })
  }
}

store.dispatch('user/login', loginForm)的实现如下:

    login({ commit }, payload) {
      return new Promise((resolve, reject) => {
        login(payload)
          .then((data) => {
            // 登录成功,保存token
            commit('SET_token', data.token)
            resolve()
          })
          .catch((error) => reject(error))
      })
    },

当登录成功后会保存服务器返回的token,并跳转首页,这时会再次进入导航守卫:

          // 用已有的token去获取用户信息,看token是否过期
          const ok = await store.dispatch('user/getUserInfo')

由于有了token,会利用token去获取用户信息:

import { login, getUserInfo, logout } from '@/api/sys'
。。。
getUserInfo({ commit, dispatch }) {
      return new Promise((resolve, reject) => {
        getUserInfo()
          .then(async (data) => {
            // 保存用户信息到仓库
            commit('SET_userInfo', data)
            // 等待路由计算完成
            // 启用了命名空间的 getter 和 action 会收到局部化的 getter,dispatch 和 commit。
            // 若需要在全局命名空间内分发 action 或提交 mutation,将 { root: true } 作为第三参数传给 dispatch 或 commit 即可。
            await dispatch('routes/computedUserRoutes', data.permission.menus, {
              root: true
            })
            resolve(true)
          })
          .catch(() => {
            // eslint-disable-next-line prefer-promise-reject-errors
            reject(false)
          })
      })
    },
。。。

在这时候会根据用户的权限信息 data.permission.menus去计算用户所拥有的路由记录,这是实现权限控制的关键。服务端返回的 data 数据结构应该如下所示:

    "data": {
        "id": 0,
        "role": [
            2
        ],
        "openTime": "2023-05-04",
        "username": "admin",
        "avatar": "/favicon.ico",
        "permission": {
            "menus": [
                "acl",
                "user-list",
                "role-list",
                "menu-list",
                "client-management"
            ],
            "points": [
                "excel-import",
                "delete-user",
                "assign-role",
                "add-role",
                "delete-role",
                "assign-perm",
                "add-root-perm",
                "add-children-perm",
                "delete-perm"
            ]
        }
    },

menus保存了可以访问的路由的name,这个值应该是唯一的。points保存了可以使用的按钮权限。

根据用户的权限信息 data.permission.menus去计算用户所拥有的路由记录的核心实现如下:
完整实现请查看:src\store\modules\routes.js

。。。

computedUserRoutes({ commit }, menus) {
  return new Promise((resolve, reject) => {
    // 根据户信息计算出用户所拥有的路由表
    const userPrivateRoutes = getUserPrivateRoutes(privateRoutes(), menus)
    // 将计算出的私有路由表添加到vue-router
    addRoutes(userPrivateRoutes)
    // 将用户拥有的私有路由与公有路由合并,保存到state.routes
    // state.routes主要用于:侧边栏渲染,页面搜索,
    commit('SET_routes', [...publicRoutes(), ...userPrivateRoutes])
    commit('SET_userPrivateRoutes', userPrivateRoutes)
    resolve()
  })
},

。。。

/**
 * 根据户信息计算出用户所拥有的路由表
 * @param {*} flatPrivateRoutes
 * @param {*} menus
 */
function getUserPrivateRoutes(privateRoutes, menus) {
  // 不要在数组迭代中删除数组该数组中元素
  const newList = [...privateRoutes]
  newList.forEach((route) => {
    // 从子路由开始向上遍历
    if (route.children && route.children.length) {
      getUserPrivateRoutes(route.children, menus)
    }

    if (!(route.children && route.children.length)) {
      // 因为先过滤的子路由
      // 如果过滤后,该路由还有子路由,不管你有没有该路由页面权限,都应该保留,否则看不到(不能添加到vue-router)子路由
      // 如果没有子路由,我就要看看是否过滤该路由
      const exist = menus.includes(route.name)
      if (!exist) {
        privateRoutes.splice(privateRoutes.indexOf(route), 1)
      }
    }
  })
  return privateRoutes
}

当获取用户信息成功,动态路由也计算完成后,再回到我们的导航守卫中:

          // 用已有的token去获取用户信息,看token是否过期
          const ok = await store.dispatch('user/getUserInfo')

          if (ok) {
            // 没有过期,放行
            // 由于在导航守卫中添加了动态路由,所以需要重定向,而不是直接next()
            next(to.fullPath)
          }

此时就会跳转到要去的页面了。

所以,要使用该项目的RBAC功能,请配合后端规划好API接口以及请求/响应数据。请查看API接口文档了解更多。

SvgIcon 组件

SvgIcon组件已经在main.js 中进行全局注册,可以直接使用:

// 注册SvgIcon为全局组件
import SvgIcon from '@/components/SvgIcon'

const app = createApp(App)
  .use(store)
  .use(router)
  .use(I18N)
  .use(ElementPlus, elementPlusConf)

app.component('SvgIcon', SvgIcon)

具体实现方式可以查看:**src\components\SvgIcon\index.vue**
使用方式:
使用hoverScale这个props可以让鼠标悬浮图标时有缩放效果。
使用icon 这个props进行传参,可接收:
1.图标字体类名
2.svg的url
3.'my-'+本地src/assets/icon/svg中的svg名称,例如:icon="my-login"

  <SvgIcon icon="my-login"></SvgIcon>

明暗主题功能

明暗切换组件在 src\components\LightDarkSwitch\index.vue

const isDark = useDark({
  selector: 'html', // 要为哪一个元素添加属性,默认添加的属性名为class。element-plus的drak类必须添加在html标签上
  valueDark: props.normalMode
  ? 'theme-dark dark'
  : 'theme-filter-invert-light theme-filter-invert-dark', // 添加的属性值,drak是 element-plus 的暗夜样式的类(https://element-plus.gitee.io/zh-CN/guide/dark-mode.html)
  valueLight: props.normalMode ? 'theme-light' : 'theme-filter-invert-light'
  })

当切换主题时,会更改html元素上的css类名,以更改不同的样式类,实现不同的样式效果。
具体的明暗css样式实现,可以查看和修改 src\style中的文件。

├─style
│      index.scss
│      mobile.scss //一些通用的全局移动端样式
│      theme-dark.scss //暗夜主题样式
│      theme-filter-invert-dark.scss //使用css-filter 实现暗夜主题样式
│      theme-filter-invert-light.scss //使用css-filter 实现明亮主题样式
│      theme-light.scss //明亮主题样式
│      variables-dark.scss //暗夜主题使用的颜色变量
│      variables-light.scss //明亮主题使用的颜色变量
│      variables.scss //一些样式变量

setting.js配置文件

import i18n from '@/i18n'
export default {
  /**
   * 页面标题
   */
  pageTile: i18n.$t('src.settings.808362-0'),

  /**
   * 侧边栏
   */
  sideBar: {
    // sideBarLogo: {
    //   isShow: true,
    //   type: 'text', // 'text'or'img'
    //   value: '后台管理系统'
    // },
    sideBarLogo: {
      isShow: true,
      type: 'img', // 'text'or'img'
      value: '/favicon.ico'
    },
    uniqueOpened: true, // 是否只保持一个子菜单的展开
    // 侧边栏宽度
    initWidth: 200, // 初始宽度,填写整数,单位是px
    minDargWidth: 180, // 最小宽度
    maxDargWidth: 250, // 最大宽度
    mobileCollapseToZero: true // 为移动端页面时,收缩侧边栏宽度到0
  },

  /**
   * 顶部导航栏
   */
  narBarFixed: true, // 是否固定导航条
  narBarSeparator: '/' // 面包屑分隔符
}

pageTile文档标题后缀,可以自行修改,前面会拼接上菜单项的名称,可以在 src\utility\set-document-title.js 中修改拼接行为。
image.png

Layout/布局样式

可以自行修改 src\layout中的布局文件。

国际化/i18n功能

具体实现

关于i18n的实现,可以查看如下文件:
src\layout\NavBar\index.vue
src\components\LanguageSwitch\index.vue
src\i18n\index.js

手动添加

添加译文到json文件

src\i18n\locale\en.json添加英文译文
image.png
src\i18n\locale\zh.json中添加中文译文
image.png
注意,此处的key均为:404.index.808362-0

在vue模板中使用

image.png

<p>{{ $t('404.index.808362-0') }}</p>

此处的$t方法已经挂载到了全局

在<script setup>中使用

<script setup>

  import i18n from '@/i18n'
  let str = i18n.$t('404.index.808362-0')

<script>

在JS文件中使用

import i18n from '@/i18n'
let str = i18n.$t('404.index.808362-0')

自动提取文字并翻译

对于中文使用者

如果你想要将项目中的中文快速提取并翻译成英文,你可以尝试以下vscode插件:
Du I18N (https://marketplace.visualstudio.com/items?itemName=DewuTeam.du-i18n)
使用帮助:(https://juejin.cn/post/7191769910685466679)

i18n pro(https://marketplace.visualstudio.com/items?itemName=wumo1016.i18n-pro)
使用帮助:(https://juejin.cn/post/7213665579701731385)
它fork自i18n Ally,提供了百度翻译的API接口配置,对中国开发者来说更加方便.

对于英文使用者

如果你想要将项目中的英文快速提取并翻译成中文,你可以尝试以下这一个vscode插件:
i18n Ally

一些配置

如果你使用i18n Ally 或者 i18n pro,你可以在项目根目录的.vscode中的settings.json中进行如下配置:

{
  "i18n-ally.localesPaths": ["src/i18n/locale"],
  "i18n-ally.keystyle": "nested",
  "i18n-ally.sortKeys": true,
  // "i18n-ally.namespace": true,
  // "i18n-ally.pathMatcher": "{locale}/{namespaces}.{ext}",
  "i18n-ally.enabledParsers": ["json"],
  "i18n-ally.sourceLanguage": "zh",
  "i18n-ally.displayLanguage": "zh",
  "i18n-ally.enabledFrameworks": ["vue", "react"],
  "i18n-ally.extract.autoDetect": true,
  // i18n pro
  "i18n-ally.translate.engines": ["baidu"],
  "i18n-ally.translate.baidu.appid": "百度平台APPID",
  "i18n-ally.translate.baidu.apiSecret": "百度平台分配的密钥",
  "vue.features.codeActions.enable": false
}

版权问题

图片

404,登录,注册中使用的图片均来自该网站
Free to Use Clip Art Images & Vector Illustrations | ManyPixels
Illustration Gallery是来自ManyPixels设计团队,完全免费且可商用的一个插画库,可搜索关键字,可以任意改颜色,插画形式也非常舒服,重点是可下载格式有svg和png,非常方便。

图标

该项目中所使用的svg图标均来自该网站
Heroicons
Heroicons 是一套由 Tailwind CSS 制作的精美的手绘风格 SVG 图标,适用于各种网站和应用。Heroicons 有三种风格:Outline(描边),Solid(填充)和 Mini(迷你),每种风格都有 292 个图标,共计 876 个图标。Heroicons 支持 React 和 Vue 库,也可以直接在 HTML 中使用。Heroicons 的许可证是 MIT,可以免费使用和修改。


了解更多

API接口文档

API接口文档

开发笔记

开发笔记

About

使用Vue3组合式API + script setup 语法糖,实现后台管理业务的通用解决方案:路由渲染菜单+页面模糊搜索+全屏+明暗主题切换+RBAC访问控制+i18n国际化。Use Vue3 combined API + script setup syntax sugar to implement a general solution for background management services: routing rendering menu + page fuzzy search + full screen + light and dark theme switching + RBAC access control + i18n internationalization.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published