Electron-Vue3-Vadmin后台系统|vite2+electron桌面端权限管理系统
基于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
二、主要特性
- 前端技术栈Vite2、Vue3、Electron12、Element Plus、Vue-i18n、Echarts5.x、Sortable、Mockjs。
- 权限认证支持组件式+指令式两种方式。
- 支持中文/英文/繁体国际化解决方案。
- 支持表格拖拽排序、缩放、树形表格等功能。
- 支持加载动态权限菜单,多方式轻松权限控制。
- 高效率开发,整个框架已经搭建完毕,只需新增相应模块即可。
三、项目结构图
整个项目使用最新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桌面端权限管理系统的更多相关文章
- 分享一个基于ligerui的系统应用案例ligerRM V2(权限管理系统)(提供下载)
阅读目录 简介 系统特色 系统介绍 - 首页 系统介绍 - 列表页 系统介绍 - 明细页(表单) 系统介绍 - 菜单/按钮 系统介绍 - 权限中心 系统介绍 - 数据权限 系统介绍 - 字段权限 系统 ...
- 基于vite2+electron12后台管理模板|Electron后台框架系统
前一溜时间有给大家分享一个 electron+vite跨端短视频 项目.这次分享的是vite2.x和electron实现跨平台后台框架,支持国际化多语言配置.导航菜单+树形菜单两种路由菜单模式.展开/ ...
- Vite2+Electron仿抖音|vite2.x+electron12+vant3短视频|直播|聊天
整合vite2+electron12跨平台仿抖音电脑版实战Vite2-ElectronDouYin. 基于vite2.0+electron12+vant3+swiper6+v3popup等技术跨端仿制 ...
- 快速了解Electron:新一代基于Web的跨平台桌面技术
本文引用了作者“ ConardLi”的<用JS开发跨平台桌面应用,从原理到实践>一文部分内容,原文链接:segmentfault.com/a/1190000019426512,感谢原作者的 ...
- 【electron+vue3+ts实战便笺exe】一、搭建框架配置
不要让自己的上限成为你的底线 前言 诈尸更新系列,为了跟上脚步,尝试了vue3,在学习vue3的时候顺便学习一手electron和ts,本教程将分别发布,源码会在最后的文章发布.因为还在开发中,目前也 ...
- Vite ❤ Electron——基于Vite搭建Electron+Vue3的开发环境【一】
背景 目前社区两大Vue+Electron的脚手架:electron-vue和vue-cli-plugin-electron-builder, 都有这样那样的问题,且都还不支持Vue3,然而Vue3已 ...
- 【electron+vue3+ts实战便笺exe】二、electron+vue3开发内容
不要让自己的上限成为你的底线 本来以为有万字的..没想到才堪堪近6000字.为了水文的嫌疑,只挑了重点的地方讲,比如component内的组件就挑了右键弹窗去说明,建议在看本文的时候边查看项目,有不懂 ...
- 【原创】从零开始搭建Electron+Vue+Webpack项目框架(六)Electron打包,同时构建客户端和web端
导航: (一)Electron跑起来(二)从零搭建Vue全家桶+webpack项目框架(三)Electron+Vue+Webpack,联合调试整个项目(四)Electron配置润色(五)预加载及自动更 ...
- 【Electron】在 WSL2 中 打包 electron Linux 版本
[Electron]在 WSL2 中 打包 electron Linux 版本. 安装 WSL 我使用的是 Ubuntu 20.04.4 LTS 的版本. 安装 WSL 文档地址:https://do ...
随机推荐
- Mardown语法
1.什么是Markdown Mardown是一种文本标记语言,使用它,能让我们更加专注于内容的输出,而不是排版样式. 我们平常使用的.txt文档书写的文字是没有样式的,使用Markdown语法就可以给 ...
- MySQL语法基础
一.通用语法 1.MySQL数据库的SQL语句不区分大小写 2.可以用/**/完成注释 3.常用数据类型 类型 描述 int 整型 double 浮点型 varchar 字符串型 date 日期类型, ...
- Asp.Net Core 学习随笔
1.依赖注入 configureServices 中 //单例 services.AddSingleton<i,c>(); //http请求内 services.AddScopend< ...
- toastr通知插件的使用
/显示一个警告,没有标题 toastr.warning('My name is Inigo Montoya. You killed my father, prepare to die!') 显示一个成 ...
- JS中dom操作的事件
Click--点击事件 优先级:dom.onclick 高于标签上的onClick属性 监听事件 --不会覆盖前面的事件效果 dom.addEventListener() 括号里面有三个参数 1 ...
- 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 ...
- PAT (Basic Level) Practice (中文) 1050 螺旋矩阵 (25 分) 凌宸1642
PAT (Basic Level) Practice (中文) 1050 螺旋矩阵 (25 分) 目录 PAT (Basic Level) Practice (中文) 1050 螺旋矩阵 (25 分) ...
- Python函数参数和注解是什么
四种参数 Python函数func定义如下: def func(first, *args, second="Hello World", **kwargs): print(first ...
- Windows Server 2016不小心卸载了.NET Framwork4.6后服务器管理器等功能都不能用的解决方案
之前卸载IIS的时候手贱把.NET FrameWork 4.6给卸载了,下面有一个比较简单的恢复方法. 可以尝试一下通过cmd命令DISM启用.NET 4.6:1. 首先运行如下命令查看当前的功能安装 ...
- 【源码解析】- ArrayList源码解析,绝对详细
ArrayList源码解析 简介 ArrayList是Java集合框架中非常常用的一种数据结构.继承自AbstractList,实现了List接口.底层基于数组来实现动态容量大小的控制,允许null值 ...