tauri-vue3-admin バックエンド管理用 exe プログラムテンプレート

tauri-vue3-admin バックエンド管理用 exe プログラムテンプレート

tauri+vue3+pinia2+veplus を使用したクロスデスクトップ向け汎用バックエンド管理システムアプリケーションテンプレート TauriAdmin。

最終更新 2023/07/27 22:14
前端加油栈
読了目安 7 分
カテゴリ
フロントエンド
タグ
Vue Tauri

紹介

tauri+vue3+pinia2+veplus をベースにしたクロスプラットフォーム、デスクトップ向け汎用バックエンド管理システムアプリケーションテンプレート TauriAdmin

tauri-admin はクロスプラットフォーム技術 Tauri Rust と vite4.x を統合し、PC版バックエンドシステムプログラム exe テンプレートを構築します。

マルチウィンドウ管理、国際化多言語対応、ルート認証検証/ルートキャッシュ、よく使われる業務機能モジュールをサポート。

技術スタック

  • エディタ:VScode
  • 技術フレームワーク:tauri+vite4+vue3+pinia2+vue-router
  • UI コンポーネントライブラリ:ve-plus(vue3 ベースのPC向けUIコンポーネントライブラリ)
  • スタイル処理:sass^1.63.6
  • チャートコンポーネント:echarts^5.4.2
  • 国際化ソリューション:vue-i18n^9.2.2
  • エディタコンポーネント:wangeditor^4.7.15
  • ローカルキャッシュ:pinia-plugin-persistedstate^3.1.0

プロジェクトには3つのよく使われるレイアウトテンプレートスタイルが組み込まれており、好みに応じて自由に切り替えられます。お好みのテンプレートをカスタマイズすることも可能です。

プロジェクト構成ディレクトリ

プロジェクト全体は tauri-cli スキャフォールディングを使用して vue3 プロジェクトを構築しています。プロジェクトテンプレートの作成やマルチウィンドウに興味がある方は、以前の共有記事をご覧ください。

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

tauri vue3 によるマルチウィンドウのカプセル化

multiwins ディレクトリに新しい index.js ファイルを作成し、tauri のマルチウィンドウをカプセル化して管理します。

// ウィンドウ作成設定
export const windowConfig = {
  label: null, // ウィンドウのユニークなラベル
  title: "", // ウィンドウタイトル
  url: "", // ルートアドレスURL
  width: 1000, // ウィンドウ幅
  height: 640, // ウィンドウ高さ
  minWidth: null, // ウィンドウ最小幅
  minHeight: null, // ウィンドウ最小高さ
  x: null, // 画面左端からのX座標
  y: null, // 画面最上部からのY座標
  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, // ウィンドウのユニークなラベル
  title: "", // ウィンドウタイトル
  url: "", // ルートアドレスURL
  width: 1000, // ウィンドウ幅
  height: 640, // ウィンドウ高さ
  minWidth: null, // ウィンドウ最小幅
  minHeight: null, // ウィンドウ最小高さ
  x: null, // 画面左端からのX座標
  y: null, // 画面最上部からのY座標
  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();
    });

    // ...
  }
}

メインテンプレートレイアウト

プロジェクトには3つのよく使われるテンプレートレイアウトスタイルが組み込まれています。伝統的なカラム分割、メニュー型、水平メニュー型です。

<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";

// モジュールルートを一括インポート
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 ==> タブを固定するか(タブバーで閉じられない)
 * */
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 は中国語・英語・繁体字の3言語設定をサポートしています。

/**
 * 国際化設定 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
    }
  }
}

以上、tauri+vue3+pinia を使用してクライアントバックエンド管理システムテンプレートのインスタンスを実装する方法についての共有でした。

さらに探索

関連読書

その他の記事
同じタグ 2024/01/13

エレガント!もう一つの.NET Coreオープンソースフレームワークプロジェクト:意フレームワーク

ユーザーエクスペリエンスを重視した.NET 8 Webオープンソースフレームワーク。ABP vNextネイティブ版、Furion版をサポートし、フロントエンドとバックエンドはRuoYi Vue 3.0を統合。RBAC権限管理と現代的なコミュニティモジュールを内蔵し、すぐに使用できます。

続きを読む
同じタグ 2023/10/16

.NET工具箱:オープンソースで無料の純粋なフロントエンドツールサイト、10大ツールカテゴリと73のリアルタイムオンラインツールを探索

Dotnet工具箱は、純粋なフロントエンド、オープンソースで無料のツールサイトです。週末にオープンソースプロジェクトit-toolsを参考に、サイトのインターフェーステキストを中国語化し、サイトを再デプロイしました。このサイトには10大ツールカテゴリがあり、73のリアルタイムオンラインツールを提供しています。Vue3で開発されたDotnet工具箱は独自の特徴を持ち、この記事ではその中からいくつかの特色あるツールを詳しく紹介し、独自のツールサイトをデプロイする方法を簡単に共有します。ツールサイトに興味があれば、ぜひDotnet工具箱をご覧ください!

続きを読む