tauri-vue3-admin後台管理exe程式模板

tauri-vue3-admin後台管理exe程式模板

基於tauri+vue3+pinia2+veplus跨桌面端通用後台管理系統應用模板TauriAdmin。

最後更新 2023/7/27 下午10:14
前端加油栈
預計閱讀 9 分鐘
分類
前端
標籤
Vue Tauri

介紹

基於 tauri+vue3+pinia2+veplus 跨平台、桌面端通用後台管理系統應用模板 TauriAdmin

tauri-admin 採用跨端技術 Tauri Rust 整合 vite4.x 建置電腦端後台系統程式 exe 模板。

支援多開視窗管理、國際化多語言、路由鑑權驗證/路由快取、常用業務功能模組。

技術棧

  • 編輯器:VScode
  • 技術框架:tauri+vite4+vue3+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-cli 腳手架建置 vue3 專案,如果大家對建立專案模板及多開視窗感興趣,可以去看看之前的分享文章。

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

tauri vue3 封裝多開視窗

在 multiwins 目錄下新建一個 index.js 檔案,用於 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, // 隱藏視窗
};

透過 tauri 提供的 WebviewWindow 方法建立新視窗實例。由於 label 是視窗唯一標識,當需要切換設定為主視窗時,需要設定 label 包含 main 關鍵詞。後續會檢索是否有 main 關鍵詞判斷是否為主視窗。

/**
 * @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();
    });

    // ...
  }
}

主模板版面配置

專案中內建了三種常用的模板版面配置樣式。分別為傳統分欄、菜單式、水平菜單式。

<script setup>
    import { computed } from 'vue'
    import { appStore } from '@/pinia/modules/app'

    // 引入版面配置模板
    import Columns from './template/columns/index.vue'
    import Vertical from './template/vertical/index.vue'
    import Transverse from './template/transverse/index.vue'

    const store = appStore()
    const config = computed(() => store.config)

    const LayoutConfig = {
        columns: Columns,
        vertical: Vertical,
        transverse: Transverse
    }
</script>

<template>
    <div class="veadmin__container">
        <component :is="LayoutConfig[config.layout]" />
    </div>
</template>

路由配置

tauri 專案中使用 vue-router 進行路由跳轉管理。

/**
 * 路由配置 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: `<span style="color: #999;">當前登入角色 ${store.roles} 沒有操作權限,請聯繫管理員授權後再操作。</div>`,
      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
 * @author YXY
 */

import { createPinia } from "pinia";
// 引入pinia本地持久化儲存
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";

const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);

export default pinia;

本地持久化儲存則是使用 pinia 插件 pinia-plugin-persistedstate 進行實現功能。

vue-i18n 國際化解決方案

tauri-admin 支援中英文/繁體三種語言配置。

/**
 * 國際化配置 VueI18n
 * @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);
};

tauri.conf.json 配置

{
  "build": {
    "beforeDevCommand": "yarn dev",
    "beforeBuildCommand": "yarn build",
    "devPath": "http://localhost:1420",
    "distDir": "../dist",
    "withGlobalTauri": false
  },
  "package": {
    "productName": "tauri-admin",
    "version": "0.0.0"
  },
  "tauri": {
    "allowlist": {
      "all": true,
      "shell": {
        "all": false,
        "open": true
      }
    },
    "bundle": {
      "active": true,
      "targets": "all",
      "identifier": "com.tauri.admin",
      "icon": [
        "icons/32x32.png",
        "icons/128x128.png",
        "icons/128x128@2x.png",
        "icons/icon.icns",
        "icons/icon.ico"
      ]
    },
    "security": {
      "csp": null
    },
    "windows": [
      {
        "fullscreen": false,
        "resizable": true,
        "title": "tauri-admin",
        "width": 1000,
        "height": 640,
        "center": true,
        "decorations": false,
        "fileDropEnabled": false,
        "visible": false
      }
    ],
    "systemTray": {
      "iconPath": "icons/icon.ico",
      "iconAsTemplate": true,
      "menuOnLeftClick": false
    }
  }
}

OK,以上就是 tauri+vue3+pinia 實現客戶端後台管理系統模板實例的一些分享。

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2023/10/16

.NET工具箱:開源、免費的純前端工具網站,帶你探索10大工具分類和73個實時在線小工具

Dotnet工具箱是一個純前端的、開源和免費的工具網站,週末我參考了開源專案it-tools,對網站界面文字進行了中文化,並重新部署了網站。該網站共有10大工具分類,提供了73個實時在線小工具。使用Vue3開發的Dotnet工具箱具有獨特的特色,本文詳細介紹了其中一些特色工具,並簡單分享了如何部署自己的工具網站。如果你對工具網站感興趣,不妨來了解一下Dotnet工具箱吧!

繼續閱讀