tauri-vue3-admin 基于 Tauri Rust Webview
跨端技术整合 vite4 vue3 pinia2 vue-router
等技术搭建跨端管理系统应用程序模板EXE。
框架技术
- 编码工具:Vscode
- 框架技术:tauri vite^4.2.1 vue^3.2.45 pinia2 vue-router
- UI组件库:ve-plus (基于vue3轻量级UI组件库)
- 样式处理:sass^1.63.6
- 图表组件:echarts^5.4.2
- 国际化方案:vue-i18n^9.2.2
- 编辑器组件:wangeditor^4.7.15
- 缓存组件:pinia-plugin-persistedstate^3.1.0
tauri-admin 支持多窗口切换管理、vue-i18n多语言包、动态路由权限、常用业务功能模块、3种布局模板及动态路由缓存
等功能。
项目结构
tauri vue3多窗口
新建一个multiwins目录处理tauri创建多窗口。
// 创建窗口参数配置 export const windowConfig = { label: null, // 窗口唯一label title: '', // 窗口标题 url: '', // 路由地址url width: 1000, // 窗口宽度 height: 640, // 窗口高度 minWidth: null, // 窗口最小宽度 minHeight: null, // 窗口最小高度 x: null, // 窗口相对于屏幕左侧坐标 y: null, // 窗口相对于屏幕顶端坐标 center: true, // 窗口居中显示 resizable: true, // 是否支持缩放 maximized: false, // 最大化窗口 decorations: false, // 窗口是否装饰边框及导航条 alwaysOnTop: false, // 置顶窗口 fileDropEnabled: false, // 禁止系统拖放 visible: false // 隐藏窗口 }
/** * @desc 窗口管理 * @author: YXY Q:282310962 * @time 2023.07 */ import { WebviewWindow, appWindow, getAll } from '@tauri-apps/api/window' import { relaunch, exit } from '@tauri-apps/api/process' import { emit, listen } from '@tauri-apps/api/event' import { setWin } from './actions' // 创建窗口参数配置 export const windowConfig = { label: null, // 窗口唯一label title: '', // 窗口标题 url: '', // 路由地址url width: 1000, // 窗口宽度 height: 640, // 窗口高度 minWidth: null, // 窗口最小宽度 minHeight: null, // 窗口最小高度 x: null, // 窗口相对于屏幕左侧坐标 y: null, // 窗口相对于屏幕顶端坐标 center: true, // 窗口居中显示 resizable: true, // 是否支持缩放 maximized: false, // 最大化窗口 decorations: false, // 窗口是否装饰边框及导航条 alwaysOnTop: false, // 置顶窗口 fileDropEnabled: false, // 禁止系统拖放 visible: false // 隐藏窗口 } class Windows { constructor() { // 主窗口 this.mainWin = null } // 创建新窗口 async createWin(options) { console.log('-=-=-=-=-=开始创建窗口') const args = Object.assign({}, windowConfig, options) // 判断窗口是否存在 const existWin = getAll().find(w => w.label == args.label) if(existWin) { console.log('窗口已存在>>', existWin) if(existWin.label.indexOf('main') == -1) { // 自定义处理... } } // 是否主窗口 if(args.label.indexOf('main') > -1) { console.log('该窗口是主窗口') // 自定义处理... } // 创建窗口对象 let win = new WebviewWindow(args.label, args) // 是否最大化 if(args.maximized && args.resizable) { win.maximize() } // 窗口创建完毕/失败 win.once('tauri://created', async() => { console.log('window create success!') await win?.show() }) win.once('tauri://error', async() => { console.log('window create error!') }) } // 获取窗口 getWin(label) { return WebviewWindow.getByLabel(label) } // 获取全部窗口 getAllWin() { return getAll() } // 开启主进程监听事件 async listen() { console.log('—— —— —— —— —— 开始监听窗口') // 创建新窗体 await listen('win-create', (event) => { this.createWin(event.payload) }) // 显示窗体 await listen('win-show', async(event) => { if(appWindow.label.indexOf('main') == -1) return await appWindow.show() await appWindow.unminimize() await appWindow.setFocus() }) // 隐藏窗体 await listen('win-hide', async(event) => { if(appWindow.label.indexOf('main') == -1) return await appWindow.hide() }) // 关闭窗体 await listen('win-close', async(event) => { await appWindow.close() }) // 退出应用 await listen('win-exit', async(event) => { setWin('logout') await exit() }) // ... } }
actions.js渲染进程/主进程通讯
/** * 处理渲染器进程到主进程的异步通信 */ import { WebviewWindow } from '@tauri-apps/api/window' import { emit } from '@tauri-apps/api/event' /** * @desc 创建新窗口 * @param args {object} {label: 'new', url: '/new', width: 500, height: 300, ...} */ export async function createWin(args) { console.log(args) await emit('win-create', args) } /** * @desc 获取窗口 * @param args {string} 'main'|'main_login' ... */ export async function getWin(label) { return await WebviewWindow.getByLabel(label) } /** * @desc 设置窗口 * @param type {string} 'show'|'hide'|'close'|'min'|'max'|'max2min'|'exit'|'relaunch' * @param id {number} */ export async function setWin(type) { await emit('win-' type) } /** * @desc 主|渲染进程数据传递 * @param args {object} {type: 'MSG_TYPE_XXX', value: 123} */ export async function setWinData(args) { await emit('win-setdata', args) } /** * @desc 屏蔽系统右键菜单 */ export function disableWindowMenu() { document.addEventListener('contextmenu', e => e.preventDefault()) } /** * @desc 登录窗口 */ export async function loginWin() { await createWin({ label: 'main_login', title: '登录', url: '/login', width: 520, height: 420, resizable: false, alwaysOnTop: true }) } /** * @desc 主窗口 */ export async function mainWin() { await createWin({ label: 'main', title: 'TAURI-ADMIN', url: '/', width: 1000, height: 640, minWidth: 750, minHeight: 500 }) }
布局模板
tauri-admin内置了三种常见的布局模板。
路由配置router
创建路由配置,多路由地址合并/批量引入路由。
/** * 路由配置 * @author YXY */ import { appWindow } from '@tauri-apps/api/window' import { createRouter, createWebHistory } from 'vue-router' import { appStore } from '@/pinia/modules/app' import { hasPermission } from '@/hooks/usePermission' import { loginWin } from '@/multiwins/actions' // 批量导入modules路由 const modules = import.meta.glob('./modules/*.js', { eager: true }) const patchRoutes = Object.keys(modules).map(key => modules[key].default).flat() /** * @description 动态路由参数配置 * @param path ==> 菜单路径 * @param redirect ==> 重定向地址 * @param component ==> 视图文件路径 * 菜单信息(meta) * @param meta.icon ==> 菜单图标 * @param meta.title ==> 菜单标题 * @param meta.activeRoute ==> 路由选中(默认空 route.path) * @param meta.rootRoute ==> 所属根路由选中(默认空) * @param meta.roles ==> 页面权限 ['admin', 'dev', 'test'] * @param meta.breadcrumb ==> 自定义面包屑导航 [{meta:{...}, path: '...'}] * @param meta.isAuth ==> 是否需要验证 * @param meta.isHidden ==> 是否隐藏页面 * @param meta.isFull ==> 是否全屏页面 * @param meta.isKeepAlive ==> 是否缓存页面 * @param meta.isAffix ==> 是否固定标签(tabs标签栏不能关闭) * */ const routes = [ // 首页 { path: '/', redirect: '/home' }, // 错误模块 { path: '/:pathMatch(.*)*', component: () => import('@views/error/404.vue'), meta: { title: 'page__error-notfound' } }, ...patchRoutes ] const router = createRouter({ history: createWebHistory(), routes }) // 全局钩子拦截 router.beforeEach((to, from, next) => { // 开启加载提示 loading({ text: 'Loading...', background: 'rgba(70, 255, 170, .1)' }) const store = appStore() if(to?.meta?.isAuth && !store.isLogged) { loginWin() loading.close() }else if(!hasPermission(store.roles, to?.meta?.roles)) { // 路由鉴权 appWindow?.show() next('/error/forbidden') loading.close() Notify({ title: '访问限制!', description: `当前登录角色 ${store.roles} 没有操作权限,请联系管理员授权后再操作。`, type: 'danger', icon: 've-icon-unlock', time: 10 }) }else { appWindow?.show() next() } }) router.afterEach(() => { loading.close() }) router.onError(error => { loading.close() console.warn('Router Error》》', error.message); }) export default router
状态管理pinia
vue3项目,推荐使用pinia状态管理,当然使用vuex也是可以的。
/** * 状态管理 Pinia util * @author YXY */ import { createPinia } from 'pinia' // 引入pinia本地持久化存储 import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' const pinia = createPinia() pinia.use(piniaPluginPersistedstate) export default pinia
tauri vite4国际化解决方案
tauri-admin采用vue-i18n
来处理多语言。
/** * 国际化配置 * @author YXY */ import { createI18n } from 'vue-i18n' import { appStore } from '@/pinia/modules/app' // 引入语言配置 import enUS from './en-US' import zhCN from './zh-CN' import zhTW from './zh-TW' // 默认语言 export const langVal = 'zh-CN' export default async (app) => { const store = appStore() const lang = store.lang || langVal const i18n = createI18n({ legacy: false, locale: lang, messages: { 'en': enUS, 'zh-CN': zhCN, 'zh-TW': zhTW } }) app.use(i18n) }
libs/index.js插件公共配置。
/** * 公共插件配置 * @author YXY */ // 引入ve-plus组件库 import veplus from 've-plus' import 've-plus/dist/ve-plus.css' // 引入国际化 import i18n from './i18n' // 引入控制按钮 import TitleBar from '@/components/titlebar/index.vue' import Control from '@/components/titlebar/control.vue' // 引入指令 import Permisstion from '@/directives/permission' const Libs = async app => { app.use(veplus) app.use(i18n) // 注册公共组件 app.component('TitleBar', TitleBar) app.component('Control', Control) // 注册指令 app.directive('permission', Permisstion) } export default Libs
基于tauri vue3 rust webview跨端后台管理系统就分享到这里。
来源: https://mp.weixin.qq.com/s/ojsJrvOBpdZtCJj7HjogLw
转载请注明:拈花古佛 » Tauri-vue3-admin后台管理exe程序模板