基于vite2.x+electron12桌面端后台管理系统Vite2ElectronVAdmin

继上一次分享vite2整合electron搭建后台框架,这次带来的是最新开发的跨桌面中后台权限管理系统。使用最新的前端技术栈,内置 i18n 国际化解决方案,动态权限路由,权限验证,整合了典型的表格/表单等业务模块功能。

一、技术栈

  • 编码器:vscode
  • vue3技术:vite2.1.5+vue3.0+vuex4+vue-router@4
  • 跨端框架:electron^12.0.4
  • 打包工具:vue-cli-plugin-electron-builder
  • UI组件库:element-plus^1.0.2 (饿了么vue3组件库)
  • 表格拖拽:sortablejs^1.13.0
  • 图表组件:echarts^5.1.1
  • 国际化方案:vue-i18n^9.1.6
  • 数据模拟:mockjs^1.1.0

二、主要特性

  1. 前端技术栈Vite2、Vue3、Electron12、Element Plus、Vue-i18n、Echarts5.x、Sortable、Mockjs。
  2. 权限认证支持组件式+指令式两种方式。
  3. 支持中文/英文/繁体国际化解决方案。
  4. 支持表格拖拽排序、缩放、树形表格等功能。
  5. 支持加载动态权限菜单,多方式轻松权限控制。
  6. 高效率开发,整个框架已经搭建完毕,只需新增相应模块即可。

三、项目结构图

整个项目使用最新vue3语法编码,采用标准的分层目录结构形式,数据均是使用Mock.js进行模拟。

◆ electron支持多开新窗口

项目支持打开多个窗口,如主题换肤、关于等窗口。只需通过如下的方式调用即可。

import { winCfg, createWin } from '@/windows/actions'

// 换肤窗口
const handleOpenTheme = () => {
createWin({
title: '个性装扮',
route: '/skin',
width: 750,
height: 480,
modal: true,
parent: winCfg.window.id,
resize: false,
})
}

大家如果对electron创建多窗口模式感兴趣的话,可以去看看下面这篇文章。

https://www.cnblogs.com/xiaoyan2017/p/14403820.html

◆ electron实现无边框Mac导航栏效果

如上图:顶部导航栏默认是Mac风格,也支持自定义标题、背景/文字颜色、是否沉浸式透明背景等功能。

通过设置 -webkit-app-region: drag 实现导航条可拖拽,标题及按钮设置 -webkit-app-region:no-drag 可响应点击事件。

<!-- //顶部导航 -->
<template>
<WinBar zIndex="1000">
<template #wbtn>
<MsgMenu />
<Lang />
<a class="wbtn" title="换肤" @click="handleSkinWin"><i class="iconfont icon-huanfu"></i></a>
<Setting />
<a class="wbtn" title="刷新" @click="handleRefresh"><i class="iconfont el-icon-refresh"></i></a>
<a class="wbtn" :class="{'on': isAlwaysOnTop}" :title="isAlwaysOnTop ? '取消置顶' : '置顶'" @click="handleAlwaysTop"><i class="iconfont icon-ding"></i></a>
<Avatar @logout="handleLogout" />
</template>
</WinBar>
</template>

对于自定义导航条的实现方式,由于之前有过相关分享文章,这里就不详细介绍了。

https://www.cnblogs.com/xiaoyan2017/p/14449570.html

◆ Vite2|electron项目布局模板

为了使得项目分层结构更加清晰,布局分为 Auth 和 Main 两大模块。

<!-- //Auth主模块模板 -->
<template>
<div class="vadmin__wrapper">
<router-view class="vadmin__layouts-auth"></router-view>
</div>
</template> <script>
import { useRoute } from "vue-router"
import useTitle from '@/hooks/useTitle' export default {
components: {},
setup() {
const route = useRoute() // 设置标题
useTitle(route)
}
}
</script>
<!-- //Main主模块模板 -->
<template>
<div class="vadmin__wrapper" :style="{'--themeSkin': store.state.skin}">
<div v-if="!route.meta.isNewin" class="vadmin__layouts-main flexbox flex-col">
<!-- //顶部导航 -->
<div class="layout__topbar">
<TopNav />
</div> <div class="layout__workpanel flex1 flexbox">
<!-- //侧边栏 -->
<div v-show="rootRouteEnable" class="panel__leftlayer">
<SideMenu :routes="mainRoutes" :rootRoute="rootRoute" />
</div> <!-- //中间栏 -->
<div class="panel__middlelayer" :class="{'collapsed': collapsed}">
<RouteMenu
:routes="getAllRoutes"
:rootRoute="rootRoute"
:defaultActive="defaultActive"
:rootRouteEnable="rootRouteEnable"
/>
</div> <!-- //右边栏 -->
<div class="panel__rightlayer flex1 flexbox flex-col">
<!-- 面包屑导航 -->
<BreadCrumb /> <!-- 主内容区 -->
<v3-scroll autohide>
<div class="lay__container">
<!-- //路由权限控制 -->
<permission :roles="route.meta.roles">
<template #tooltips>
<Forbidden />
</template>
<router-view></router-view>
</permission>
</div>
</v3-scroll>
</div>
</div>
</div>
<router-view v-else class="vadmin__layouts-main flexbox flex-col"></router-view>
</div>
</template>

◆ Vue-Router路由配置

/**
* 路由配置 Router util
* @author XiaoYan
*/ import { createRouter, createWebHashHistory } from "vue-router" import { ElLoading } from "element-plus"
import { loginWin } from "@/windows/actions" import store from '@/store' // 导入公共模板/路由配置
import mainLayout from "@/layouts/main"
import authLayout from "@/layouts/auth"
import mainRoutes from "@/layouts/main/routes.js"
import authRoutes from "@/layouts/auth/routes.js" const RoutesLs = [
// 主页面模块
{
path: '/',
redirect: '/home/index',
component: mainLayout,
children: mainRoutes,
},
// 验证模块
{
path: '/auth',
redirect: '/auth/login',
component: authLayout,
children: authRoutes,
},
// 错误模块
{
path: '/:pathMatch(.*)*',
component: () => import('@/views/error/404.vue'),
meta: {
title: 'app__global-page-notfound',
}
}
] const router = createRouter({
history: createWebHashHistory(),
routes: RoutesLs,
}) // 全局钩子拦截验证状态
let loadingIns
router.beforeEach((to, from, next) => {
// 开启加载提示
loadingIns = ElLoading.service({
lock: true,
text: 'Loading...',
spinner: 'el-icon-loading',
background: 'rgba(19, 209, 122, .1)'
}) // 判断当前路由是否需要验证状态
const isLogined = store.state.isLogin
if(to.meta.auth) {
if(isLogined) {
next()
}else {
loginWin()
loadingIns.close()
}
}else {
next()
}
}) router.afterEach(() => {
// 关闭加载提示
loadingIns.close()
})

◆ Vue-I18n国际化解决方案

项目中路由采用了 vue-i18n 国际化,支持中文|繁体|英文三种语言。

目前vue-i18n插件支持vue3项目了,大家需安装最新版本即可。

npm i vue-i18n@next -D

如上图:新建locale目录用来处理相应模块语言配置。

import { createI18n } from "vue-i18n"
import Storage from "@/utils/storage" // 默认值
export const langKey = 'lang'
export const langVal = 'zh-CN' /* elementPlus国际化配置 */
import enUS from "element-plus/lib/locale/lang/en"
import zhCN from "element-plus/lib/locale/lang/zh-cn"
import zhTW from "element-plus/lib/locale/lang/zh-tw"
export const elPlusLang = {
'en-US': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW,
} /* 初始化多语言 */
export const $messages = importAllLang()
export const $lang = getLang()
const i18n = createI18n({
legacy: false,
locale: $lang,
messages: $messages
})

◆ 动态化图表Hooks

项目中图表是使用最新的Echarts组件。为了避免每次都使用echarts.init调用图表接口。于是就封装了调用图表hook函数。

一开始是使用监听window.resize来自适应图表尺寸,这里有一个bug,只有窗口大小改变才会触发,而DOM改变则不会触发了,于是改用 element-resize-detector 来监听,完美解决问题。

/**
* 动态化图表Hook
* @author XiaoYan
*/ import { onMounted, onBeforeUnmount, ref } from "vue"
import * as echarts from "echarts"
import elementResizeDetectorMaker from "element-resize-detector"
import utils from "@/utils" export default function useChart(refs, options) {
let chartInst
let chartRef = ref(null)
let erd = elementResizeDetectorMaker() const handleResize = utils.debounce(() => {
chartInst.resize()
}, 100) onMounted(() => {
if(refs.value) {
chartInst = echarts.init(refs.value)
chartInst.setOption(options)
chartRef.value = chartInst
}
// window.addEventListener('resize', handleResize)
erd.listenTo(refs.value, handleResize)
}) onBeforeUnmount(() => {
chartInst.dispose()
// window.removeEventListener('resize', handleResize)
erd.removeListener(refs.value, handleResize)
}) return chartRef
}

◆ 路由权限管理

项目中的权限尺寸组件式和指令式两种模式。

<!-- //权限验证模板 -->
<template>
<slot v-if="isPermission"/>
<slot v-else name="tooltips">
<el-alert title="对不起,您没有权限操作此页面!" type="error" show-icon></el-alert>
</slot>
</template>
<script>
import { computed } from "vue";
import { useStore } from "vuex";
import { getPermissionRoute } from "@/utils/routes";
export default {
props: { roles: { type: [String, Array] } },
components: {},
setup(props) {
const store = useStore();
// 判断是否有权限
const isPermission = computed(() =>
getPermissionRoute(JSON.stringify(store.state.roles), props.roles)
);
return { isPermission };
}
};
</script>
import store from "@/store"
import { getPermissionRoute } from "@/utils/routes" const Permission = (el, binding) => {
const { value } = binding
if(value) {
const userRoles = JSON.stringify(store.state.roles)
if(!getPermissionRoute(userRoles, value)) {
el.parentNode && el.parentNode.removeChild(el)
}
}else {
console.error(`Set Roles! Like v-permission="['admin', 'dev']" or v-permission="'test'"`)
}
} export default Permission

组件调用

<Permission roles="test">
<template #tooltips>
<h2 style="color:red;">此模块只有test角色才能操作!</h2>
</template>
<el-button type="primary" icon="el-icon-search">查询</el-button>
</Permission> <el-divider /> <Permission roles="dev">
<template #tooltips>
<h2 style="color:red;">你无权操作Dev模块!</h2>
</template>
<el-button type="primary" icon="el-icon-edit">编辑</el-button>
<el-button type="warning" icon="el-icon-delete">删除</el-button>
</Permission>

指令调用

<el-button v-permission="'test'" type="primary" icon="el-icon-search">查询</el-button>
<el-button v-permission="'dev'" type="success" icon="el-icon-plus">新增</el-button>
<el-button v-permission="['test', 'dev']" type="warning" icon="el-icon-edit">编辑</el-button>
<el-button v-permission="['admin']" type="danger" icon="el-icon-delete">删除</el-button>

◆ electron-builder打包配置

{
"productName": "electron-vadmin",
"appId": "cc.xiaoyan.electron-vadmin",
"copyright": "Copyright 2021-present XiaoYan",
"compression": "maximum",
"asar": false,
"extraResources": [{
"from": "./resource","to": "resource"
}],
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"perMachine": true,
"deleteAppDataOnUninstall": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "ElectronVAdmin"
},
"win": {
"icon": "./resource/shortcut.ico",
"artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}",
"target": [{
"target": "nsis","arch": ["ia32"]
}]
},
"mac": {
"icon": "./resource/shortcut.icns","artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}"
},
"linux": {
"icon": "./resource","artifactName": "${productName}-v${version}-${platform}-${arch}-setup.${ext}"
}
}

最后还需注意

1、项目路径命名不能包含中文,否则打包会报错!
2、尽量不要使用 getCurrentInstance 函数来使用router或store,打包也会报错!
3、打包后运行出现白屏情况,可配置 history: createWebHashHistory()
4、提示fs.existsSync错误,设置nodeIntegration: true开启Node支持;

好了,基于vite2+electron开发后台管理系统就分享到这里,希望对大家有些帮助~

最后附上一个electron+vue3+vant短视频项目

https://www.cnblogs.com/xiaoyan2017/p/14585223.html

Electron-Vue3-Vadmin后台系统|vite2+electron桌面端权限管理系统的更多相关文章

  1. 分享一个基于ligerui的系统应用案例ligerRM V2(权限管理系统)(提供下载)

    阅读目录 简介 系统特色 系统介绍 - 首页 系统介绍 - 列表页 系统介绍 - 明细页(表单) 系统介绍 - 菜单/按钮 系统介绍 - 权限中心 系统介绍 - 数据权限 系统介绍 - 字段权限 系统 ...

  2. 基于vite2+electron12后台管理模板|Electron后台框架系统

    前一溜时间有给大家分享一个 electron+vite跨端短视频 项目.这次分享的是vite2.x和electron实现跨平台后台框架,支持国际化多语言配置.导航菜单+树形菜单两种路由菜单模式.展开/ ...

  3. Vite2+Electron仿抖音|vite2.x+electron12+vant3短视频|直播|聊天

    整合vite2+electron12跨平台仿抖音电脑版实战Vite2-ElectronDouYin. 基于vite2.0+electron12+vant3+swiper6+v3popup等技术跨端仿制 ...

  4. 快速了解Electron:新一代基于Web的跨平台桌面技术

    本文引用了作者“ ConardLi”的<用JS开发跨平台桌面应用,从原理到实践>一文部分内容,原文链接:segmentfault.com/a/1190000019426512,感谢原作者的 ...

  5. 【electron+vue3+ts实战便笺exe】一、搭建框架配置

    不要让自己的上限成为你的底线 前言 诈尸更新系列,为了跟上脚步,尝试了vue3,在学习vue3的时候顺便学习一手electron和ts,本教程将分别发布,源码会在最后的文章发布.因为还在开发中,目前也 ...

  6. Vite ❤ Electron——基于Vite搭建Electron+Vue3的开发环境【一】

    背景 目前社区两大Vue+Electron的脚手架:electron-vue和vue-cli-plugin-electron-builder, 都有这样那样的问题,且都还不支持Vue3,然而Vue3已 ...

  7. 【electron+vue3+ts实战便笺exe】二、electron+vue3开发内容

    不要让自己的上限成为你的底线 本来以为有万字的..没想到才堪堪近6000字.为了水文的嫌疑,只挑了重点的地方讲,比如component内的组件就挑了右键弹窗去说明,建议在看本文的时候边查看项目,有不懂 ...

  8. 【原创】从零开始搭建Electron+Vue+Webpack项目框架(六)Electron打包,同时构建客户端和web端

    导航: (一)Electron跑起来(二)从零搭建Vue全家桶+webpack项目框架(三)Electron+Vue+Webpack,联合调试整个项目(四)Electron配置润色(五)预加载及自动更 ...

  9. 【Electron】在 WSL2 中 打包 electron Linux 版本

    [Electron]在 WSL2 中 打包 electron Linux 版本. 安装 WSL 我使用的是 Ubuntu 20.04.4 LTS 的版本. 安装 WSL 文档地址:https://do ...

随机推荐

  1. Mardown语法

    1.什么是Markdown Mardown是一种文本标记语言,使用它,能让我们更加专注于内容的输出,而不是排版样式. 我们平常使用的.txt文档书写的文字是没有样式的,使用Markdown语法就可以给 ...

  2. MySQL语法基础

    一.通用语法 1.MySQL数据库的SQL语句不区分大小写 2.可以用/**/完成注释 3.常用数据类型 类型 描述 int 整型 double 浮点型 varchar 字符串型 date 日期类型, ...

  3. Asp.Net Core 学习随笔

    1.依赖注入 configureServices 中 //单例 services.AddSingleton<i,c>(); //http请求内 services.AddScopend< ...

  4. toastr通知插件的使用

    /显示一个警告,没有标题 toastr.warning('My name is Inigo Montoya. You killed my father, prepare to die!') 显示一个成 ...

  5. JS中dom操作的事件

    Click--点击事件 优先级:dom.onclick 高于标签上的onClick属性 监听事件 --不会覆盖前面的事件效果 dom.addEventListener()    括号里面有三个参数 1 ...

  6. PAT (Advanced Level) Practice 1005 Spell It Right (20 分) 凌宸1642

    PAT (Advanced Level) Practice 1005 Spell It Right (20 分) 凌宸1642 题目描述: Given a non-negative integer N ...

  7. PAT (Basic Level) Practice (中文) 1050 螺旋矩阵 (25 分) 凌宸1642

    PAT (Basic Level) Practice (中文) 1050 螺旋矩阵 (25 分) 目录 PAT (Basic Level) Practice (中文) 1050 螺旋矩阵 (25 分) ...

  8. Python函数参数和注解是什么

    四种参数 Python函数func定义如下: def func(first, *args, second="Hello World", **kwargs): print(first ...

  9. Windows Server 2016不小心卸载了.NET Framwork4.6后服务器管理器等功能都不能用的解决方案

    之前卸载IIS的时候手贱把.NET FrameWork 4.6给卸载了,下面有一个比较简单的恢复方法. 可以尝试一下通过cmd命令DISM启用.NET 4.6:1. 首先运行如下命令查看当前的功能安装 ...

  10. 【源码解析】- ArrayList源码解析,绝对详细

    ArrayList源码解析 简介 ArrayList是Java集合框架中非常常用的一种数据结构.继承自AbstractList,实现了List接口.底层基于数组来实现动态容量大小的控制,允许null值 ...