人的資源中部台湾プロジェクト (day12)

機能権限の適用

目標: 機能権限の適用を実装する

機能的権限に関する統制された考え方

前のセクションでは、モジュールとページのアクセス権限がある場合、ユーザーはページ内で特定の機能を使用できる場合と、使用できない場合があります。これが機能権限です。

これは、クエリされたデータの最後のセクションですpoints

例えば、従業員管理の削除機能を許可したい場合はどうすればよいでしょうか。

まず、従業員管理の権限ポイントの下に削除権限ポイントを追加し、有効にする必要があります。

私たちがしなければならないのは、ユーザーがpoint-user-deleteポイントを持っているかどうかを確認することです。持っている場合は削除を使用でき、持っていない場合は非表示にするか無効にすることができます。

Mixinテクノロジーを使用したチェックメソッドの注入

したがって、新しいテクノロジーmixin (ミックスイン)を使用して、すべてのコンポーネントにパブリック メソッドを持たせることができます。

src/mixin/checkPermission.js

'@/store' からストアをインポートします。
エクスポート デフォルト {
  メソッド: { 
    checkPermission(key) { 
      const { userInfo } = store.state.user 
      if (userInfo.roles.points && userInfo.roles.points.length) { 
        return userInfo.roles .points.some(item => item === key) 
      } 
      false を返します
    } 
  } 
}

main.jsインポート登録ミックスイン

// mixin をインポート
import checkPermission from '@/mixin/checkPermission' 
Vue.mixin(checkPermission)

従業員コンポーネントの権限ポイントを確認する

<el-button :disabled="!checkPermission('POINT-USER-UPDATE')" type="text" size="small" @click="$router.push(`/employees/detail/${obj.row) .id}`)">查看
</el-button>

この時点で、アクセス許可を構成することで、アクセス許可が利用可能かどうかを確認できます。

コードを送信する

完全なモジュールの統合

目標: 他のビジネス モジュール コードをこのプロジェクトに統合する

これまでのところ、基本的なプロジェクト フレームワーク + 組織構造 + 会社 + 従業員 + 権限のビジネス共同デバッグが完了しました。時間の制約があるため、すべてのビジネスを記述することはできません。ここに残りのモジュールの統合コードを示します。最終的な目標は、誰もが完成したビジネス モジュールを入手できるようにすることです

給与モジュール、社会保障モジュール、勤怠モジュール、承認モジュールなどを統合するモジュール事業

私たちが提供するリソース統合モジュールでは、路由// *の 4 つのモジュールを提供します。以下のパスに従ってコピーするだけです页面api

ルーティング =>src/router/modules

ページ =>src/views

API =>src/api

さらに、router/modules/user.jsこのモジュールはすべてのモジュールからアクセスできるため、静的ルートにインポートする必要があります。

最終的には、比較的完成度の高いシステムビジネスが得られます。

ホームページのページ構成

目标: システムホームページのページ構造を実現します。

現時点では、私たちのページにはまだホームページがあり、ここで図に示すような構造を実装できます。

ホームページの構造、src/views/dashboard/index.vue

<template> 
  <div class="dashboard-container"> 
    <!-- 头部内容 --> 
    <el-card class="header-card"> 
      <div> 
        <div class="fl headL"> 
          <div class ="headImg"> 
            <img src="@/assets/common/head.jpg"> 
          </div> 
          <div class="headInfoTip"> 
            <p class="firstChild">おはようございます、管理者様、楽しい一日をお過ごしください。</p> 
            <p class="lastChild">おはようございます、管理者様、楽しい一日をお過ごしください。</p> 
          </div> 
        </div> 
        <div class="fr" /> 
      </div> 
    </el-card> 
    <!-- メインコンテンツ--> 
    < el-row type="flex" justify="space-between">  
      <!-- left content -->
      <el-col :span="13" style="padding-right:26px">スパン="13" スタイル="パディング右:26px">スパン="13" スタイル="パディング右:26px">
        <!-- 仕事カレンダー--> 
        <el-card class="box-card"> 
          <div slot="header" class="header"> 
            <span>仕事カレンダー</span> 
          </div> 
        <!- - カレンダーコンポーネントを配置します --> 
        </el-card> 
        <!-- お知らせ --> 
        <el-card class="box-card"> 
          <div class="advContent"> 
            <div class="title"> お知らせ</div> 
            <div class="contentItem"> 
              <ul class ="noticeList"> 
                <li> 
                  <div class="item"> 
                    <img src="@/assets/common/img.jpeg" alt="">  
                    <div>
                      <p><span class="col">朱吉劉< /span> リリース、第 1 回「伝志講堂」インタラクティブ ディスカッションの受賞者発表</p>jpeg" alt=""> <p><span class="col">Zhu Jiliu</span> が第 1 回「伝志講堂」インタラクティブ ディスカッションの受賞者リストを発表</p>jpeg" alt=""> <p><span class="col">Zhu Jiliu</span> が第 1 回「伝志講堂」インタラクティブ ディスカッションの受賞者リストを発表</p> 
                      < /p> 
                    </div> 
                  </div> 
                </li> 
                <li> 
                  <div class="item"> 
                    <img src="@/assets/common/img.jpeg" alt=""> 
                    <div> 
                      < p><span class="col">Zhu Jiliu</span> は、第 2 回「伝志講堂」インタラクティブ ディスカッションの受賞者リストを発表しました。</p> <p>2018-07-21 
                      15:21:38</p> 
                    </div> 
                  </div> 
                </li> 
                <li> 
                  <div class="item">
                    <img src="@/assets/common/img.jpeg" alt="">  
                    <div>
                      <p><span class="col">Zhu Jiliu</span> が第 3 回インタラクティブ ディスカッション「伝志講堂」をリリース、受賞リストの発表</p> 
                      <p>2018-07-21 15:21:38</p> 
                    </div> 
                  </div> 
                </li> 
              </ul> 
            </div> 
          </div> 
        < /el -card> 
      </el-col> 
      <!-- 右側のコンテンツ --> 
      <el-col :scan="11"> 
        <el-card class="box-card"> 
          <div class="header headTit"> 
            <span>流程申请</span> 
          </div> 
          <div class="sideNav"> 
            <el-button class="sideBtn">残業を辞任する</el-button> 
            <el-button class="sideBtn">休暇を申請する</el-button>
            <el-button class="sideBtn">承認リスト</el-button> 
            <el-button class="sideBtn">個人情報</el-button> 
          </div> 
        </el-card> 
<
        ! --パフォーマンス インデックス--> 
        <el-card class="box-card"> 
          <div slot="header" class="header"> 
            <span>パフォーマンス インデックス</span> 
          </div> 
        <!-- レーダー チャートを配置します--> 
        </el-card> 
        <!-- ヘルプ リンク --> 
        <el-card class="box-card"> 
          <div class="header headTit"> 
            <span>ヘルプ リンク</span> 
          </div> 
          <div class="sideLink"> 
                <a href="#"> 
            <エル行>
              <el-col :span="8"> 
                  <span class="icon iconGuide" /> 
                  <p>スタートガイド</p> 
                </a> 
              </el-col> 
              <el-col :span="8 " > 
                <a href="#"> 
                  <span class="icon iconHelp" /> 
                  <p>オンライン ヘルプ マニュアル</p> 
                </a> 
              </el-col> 
              <el-col :scan="8"> 
                <a href="#"> 
                  <span class="icon iconTechnology" /> 
                  <p>テクニカル サポートにお問い合わせください</p> 
                </a> 
              </el-col> 
            </el-row> 
          </div> 
        </el-card>
      </el-col>100%; 
      高さ: 100%; 
    </el-row> 
  </div>
</template> 
<script>
 
import {mapGetters } from 'vuex'export 
default
{ 
  name: 'Dashboard', 
  computed: { 
    ...mapGetters([ 
      'name' 
    ]) 
  } 
} 
</script> 
<
style lang ="scss" スコープ> 
.dashboard-container { 
  margin: 10px; 
  li {
    リストスタイル: なし; 
  .headImg 
  {
    浮動小数点: 左; 
    幅: 100ピクセル; 
    高さ: 100ピクセル; 
    境界半径: 50%; 
    背景: #999; 
          img {
      幅: 100%; 50%; 
    }
      境界半径: 50%; 
  } 
.headInfoTip
  {
    パディング: 25px 0 0; 
    マージン左: 120px; 
    p {
      パディング: 0 0 15px; 
      マージン: 0; 
      &.firstChild { 
        font-size: 24px; 
      } 
      &.lastChild { 
        font-size: 20px; 
        色: #7f8c8d; 
.box
-card {
パディング
    : 
      5px 
  10px 
  ; 
  マージントップ: 20px; 
  .header {
    スパン {
      カラー: #2c3e50; 
      フォントサイズ: 24px; 
    .item {
    色
      : #97a8be;
      浮動小数点: 右; 
      パディング: 3px 0; 
    }
  .headTit {
    スパン { border 
  - 
      : 4px ソリッド #8a97f8; 
      パディングボトム: 10px; 
.header 
-card{
  位置:
    相対
  ; 
  .header {
    位置: 絶対; 
    右: 20ピクセル; 
    上: 15ピクセル; 
    z インデックス: 1; 
  } 
} 
.advContent
{
  背景: #fff; 
  境界半径: 5px 5px 0px 0px; 
  .title {
    フォントサイズ: 16px; 
    パディング: 20px; 
    フォントの太さ: 太字; 
    ボーダーボトム: 実線 1px #ccc; 
  }
  .contentItem { 
    パディング: 0 30px; 
    最小高さ: 350px;
    .item {
      表示: フレックス; 
      パディング:18px 0 10px; 
      ボーダーボトム: 実線 1px #ccc; 
      .col {
        色: #8a97f8; 
      } 
      img {
        幅: 56px; 
        高さ: 56ピクセル; 
        境界半径: 50%; 
        右マージン: 10px; 
      } 
      p{
        パディング: 0 0 8px; 
      .noticeList 
{
    マージン
  : 
  0 
; 
  パディング: 0; 
.sideNav 
, 
.sideLink {
  パディング: 30px 0 12px; 
  .sideBtn {
    パディング: 16px 26px;
    フォントサイズ:16px; 
    マージン: 10px 5px; 
  }
.sideLink 
{ 
  text-align: center; 
  .icon {
    表示: インラインブロック; 
    幅: 76ピクセル; 
    高さ: 76ピクセル; 
    背景: url('./../../assets/common/icon.png') 繰り返しなし; 
  .iconGuide 
  {
    背景位置: 0 0; 
  .iconHelp 
  {
    背景位置: -224px 0; 
  .iconTechnology {
    背景位置: -460px 0 
  ; 
  } 
} 
</スタイル>

上記のコードにより、次のページが得られます

ご覧のとおり、工作日历绩效指数2 つのコンポーネントが予約されており、後続のコンポーネントで開発します。

コードを送信する

ホームページのユーザー情報表示

:目标ホームページ上の情報を実際のユーザー プロファイルに置き換えます

Vuex のユーザー プロファイルを直接取得するだけです

<script> 
import { createNamespacedHelpers } from 'vuex' 
const { mapState } = createNamespacedHelpers('user') 
export default { 
  name: 'Dashboard', 
  data() { 
    return { 
      defaultImg: require('@/assets/common/head. jpg'), 
    } 
  }、
  計算結果: { 
    ...mapState(['userInfo']) 
  } 
} 
</script>

Vueビューでバインドする

<div class="fl headL"> 
          <div class="headImg"> 
            <img :src="userInfo.staffPhoto"> 
          </div> 
          <div class="headInfoTip"> 
            <p class="firstChild">おはようございます, { 
  
  { userInfo.username }}, 幸せな一日をお祈りします。</p> 
            <p class="lastChild">{ 
  
  { userInfo.username }} | {
   
  { userInfo.companyName }}-{
   
  { userInfo.DepartmentName }}</p> 
          </div> 
        </div>

また、画像の読み込みに失敗した場合、画像アドレスは存在するが表示できない場合は、以前カプセル化した画像エラーコマンドを適用することができます。

<img :src="userInfo.staffPhoto" v-imageerror="defaultImg">

勤務カレンダーコンポーネントパッケージ

目标勤務カレンダーコンポーネントをカプセル化し、ホームページに表示します。

新しい勤務カレンダーのコンポーネント構造

作業カレンダーの要件は非常にシンプルで、各月の日付を表示し、日付の範囲を設定できます。

Element コンポーネントel-calendarに基づいてカプセル化できます。

コードは以下のように表示されますsrc/views/dashboard/components/work-calendar.vue

<template> 
  <div> 
    <el-row type="flex" justify="end"> 
      <el-select v-model="currentyear" size="small" style="width: 120px" @change="dateChange" > 
        <el-option v-for="yearList の項目" :key="item" :label="item" :value="item">{ { item } 
  
  }</el-option> 
      </el-select> 
      <el-select v-model="currentMonth" size="small" style="width: 120px;margin-left:10px" @change="dateChange"> <el-option v-for="item in 12" 
        : key="アイテム" :label="アイテム" :value="item">{ 
  
  { item }}</el-option> 
      </el-select> 
    </el-row> 
    <el-calendar v-model="currentDate"> 
      <template v-slot:dateCell=" { 日付、データ }" class="content">
        <div class="date-content">  
          <スパンクラス="テキスト"> {
  
  { データ.日 | getDay }}</span> 
          <span v-if="isWeek(date)" class="rest">休</span> 
        </div> 
      </template> 
    </el-calendar> 
  </div> 
</ template> 
<script>
 
export default { 
  props: { 
    startDate: { 
      type: Date, 
      default: () => new Date() 
    } 
  }, 
  data() { 
    return { 
      currentMonth: null, //当前月份
      current Year: null, //当番份
      currentDate: null, 
      yearList:
<style lang="scss" スコープ>
    マージン左: 10px;
    高さ: 自動; 
  } 
  ::v-deep .el-calendar-table__row td, 
  ::v-deep .el-calendar-table tr td:first-child, 
  ::v-deep .el-calendar-table__row td.prev { 
    border: none ; 
  .date-content {
    さ: 40px; 
    テキスト整列: 中央; 
    行の高さ: 40px; 
    フォントサイズ: 14px; 
  .date 
  -content .rest { 
    color: #fff; 
    境界半径: 50%; 
    背景: rgb(250, 124, 77); 
    幅: 20ピクセル; 
    高さ: 20ピクセル; 
    行の高さ: 20px; 
    表示: インラインブロック; 
    フォントサイズ: 12px; 
  .date 
  -content .text {
    幅: 20ピクセル; 
    高さ: 20ピクセル; 
    行の高さ: 20px; 
    表示: インラインブロック; 
  :: 
  v-deep .el-calendar-table td.is-selected .text {
    背景: #409eff; 
    色: #fff; 
    境界半径: 50%; 
  :: 
  v-deep .el-calendar__header {
    表示: なし; 
  } 
</スタイル>

勤務カレンダーロジックを実装する

デフォルトのエクスポート {
  フィルター: { 
    getDay(value) { 
      const day = value.split('-')[2] 
      return day.startsWith('0') ? day.substr(1) : day 
    } 
  }、
  props: { 
    startDate : { 
      type: Date, 
      default: () => new Date() 
    } 
  }, 
  data() { 
    return { 
      currentMonth: null, // 現在の月
      current Year: null, // 現在の年
      currentDate: null, 
      yearList: [] 
    } 
  }, 
  // イベントを初期化します
  created() { 
    // 開始時刻を処理します
    // コンポーネントでは、開始時刻が月曜日から始まる月である必要がありますthis.current Year 
    this.currentMonth = this.startDate.getMonth() + 1
    = this.startDate.getFull Year()
    // 現在の年に基づいてオプションの年を生成し、その前後 5 年を追加します
    this.yearList = Array.from(Array(11), (value,index) => this.currentyear +index - 5 ) 
    //今年の最初の月 月曜日に 4 週間後の月を加えた月
    this.dateChange() 
  }, 
  messages: { 
    // 休日かどうか
    isWeek(value) { 
      return value.getDay() === 6 || value .getDay() === 0 
    }, 
    // 
    dateChange() { 
      const year = this.currentyear 
      const month = this.currentMonth 
      this.currentDate = new Date(`${年}-${月}-1`) / / 当月の 1 日から開始します
    } 
  } 
}

ホームページから申し込む

// 
WorkCalendar を './components/work-calendar' からインポートします
  コンポーネント: { 
    WorkCalendar // 登録
  }、
  <!-- カレンダー コンポーネントを配置する --> 
  <work-calendar />

コードを送信する

パッケージのレーダーチャートがホームページに表示されます

目标: レーダー チャートを echarts にカプセル化し、ホームページ上でパフォーマンス インデックスの位置を表示します。

レーダーチャートを理解する

レーダー チャート プラグインをカプセル化する

ホームページには、レーダー チャートを配置する必要があるパフォーマンス インデックスもあります。パッケージ化には Baidu の echart を使用できます。

最初のステップは、echarts チャートをインストールすることです

$ npm i echarts

echarts は多くのグラフィックスを含む大きなパッケージであり、レーダー チャートのみを使用すると仮定すると、オンデマンドでロードできます。

2 番目のステップは、新しいレーダー チャート コンポーネントを作成することです。src/views/dashboard/components/radar.vue

<template> 
  <!-- レーダー チャートには高さと幅を指定する必要があります --> 
  <div ref="myDiv" class="radar-echart" /> 
</template> 
<script>
 
// 読み込みプロセスを完了します
// var echarts = require('echarts') 
var echarts = require('echarts/lib/echarts') // echarts メイン モジュールをインポート
require('echarts/lib/chart/radar') // レーダー チャートをインポート
// プロンプト ボックスをインポートタイトルコンポーネント
require('echarts/lib/component/tooltip') 
require('echarts/lib/component/title') 
require
('echarts/lib/component/legend') 
export
default { 
  // ページレンダリング完了イベント
  がマウントされる() { 
    const myChart = echarts.init(this.$refs.myDiv) // チャート インスタンス
    myChart を取得します。setOption({
      タイトル: { 
      }, 
        text: '基本的なレーダー チャート'
      ツールヒント: {}、
      凡例: {
        データ: ['割り当てられた予算', '実際の支出'] } 
      、
      レーダー: { 
        // 形状: '円'、
        名前: { 
          textStyle: { 
            color: '#fff'、
            backgroundColor: ' #999', 
            borderRadius: 3, 
            padding: [3, 5] 
          } 
        }, //
        各領域の最高値
        インジケーター: [ 
          { name: '作業効率', max: 100 }, 
          { name: '出席率', max : 100 }, 
          { 名前: 'アクティビティ', 最大: 100 }, 
          { 名前: '同僚を助ける', 最大: 100 },「正しいレート」、最大: 100 } 
        ]
          { 名前: '自己学習'、最大: 100 },400ピクセル;  
</スタイル>
      }, 
      series: [{ 
        name: '予算 vs 支出 (予算 vs 支出)', 
        type: 'radar', 
        // areaStyle: {normal: {}}, 
        data: [ 
          { 
            value: [10, 1, 100, 5 , 100, 0],
            名前: '張三' 
          }, 
          {
            値: [50, 50, 50, 50, 50, 10],
            名前: '李四' 
          } 
        ] 
      }] 
    }) 
  } 
} 
</script>
 
<スタイル> 
.radar-echart {
    幅: 600px;
    高さ: 400px;

レーダー チャートを取得してパフォーマンス指標をカウントします

注意: 関連するデータが欠落しているため、ここではシミュレートされたデータを実行しています

ホームページでの紹介・活用

「./components/radar」からレーダーをインポートします
  コンポーネント: {
    レーダー // レジスタ
  }、
  <!-- コンポーネントの配置 --> 
  <radar />

稟議業務の基礎入門

承認プロセスとは何ですか

離職届を提出する

目标: 退職届を提出し、事業譲渡を完了する

諦め層

    <!-- ポップアップレイヤー--> 
    <el-dialog :visible="showDialog" title="退職申請" @close="btnCancel"> 
      <el-form 
        ref="ruleForm" 
        :model="ruleForm" 
        status -icon 
        label-width="110px" 
        :rules="rules" 
      > 
        <!--resignation form--> 
        <el-form-item label="resignation time" prop="end_time"> 
          <el-date-picker 
            v -model ="ruleForm.excelTime" 
            type="datetime" 
            value-format="yyyy-MM-dd HH:mm:ss" 
            placeholder="日付と時刻を選択" 
          /> 
        </el-form-item> 
        <el-form-item label="退職理由" prop="reason"> 
          <el-input
            v-model="ruleForm.reason" 
            type="textarea" 
            :autosize="{ minRows: 3, maxRows: 8}" 
            style="width: 70%;" 
            placeholder="请输入内容" 
          /> 
        </el-form-item> 
      </el-form> 
      <el-row slot="footer" type="flex" justify="center"> 
        <el-col :

ポップアップレイヤーを表示

<el-button class="sideBtn" @click="showDialog = true">時間外退職</el-button>

残業データと検証

      showDialog: false, 
      ruleForm: {
        例外時間: '',
        理由: '', 
        processKey: 'process_dimission', // 特定の承認
        processName: 'resignation' 
      }, 
      rules: {
        例外時間: [{ required: true, message: 'resignation時間を空にすることはできません' }]、
        理由: [{ 必須: true、メッセージ: '退会理由を空にすることはできません' }] 
      }

承認ロジックを送信する

import { startProcess } '@/api/approvals'
  
メソッドから: { 
    btnOK() { 
      this.$refs.ruleForm.validate(async validate => { 
        if (validate) { 
          const data = { ...this.ruleForm, userId : this.userInfo.userId } 
          await startProcess(data) 
          this.$message.success('提交流程成功') 
          this.btnCancel() 
        } 
      }) 
    }, 
    btnCancel() { 
      this.showDialog = false 
      this.$refs.ruleForm .resetFields() 
      this.ruleForm = {
        例外時間: '',
        理由: '', 
        processKey: 'process_dimission', // 特定の承認
        プロセス名:'退職'
      } 
  } 
    }

承認リストのナビゲーションを構成する

<el-button class="sideBtn" @click="$router.push('/users/approvals')">承認リスト</el-button> 
 <el-button class="sideBtn" @click="$router .push('/users/info')">私の情報</el-button>

プロセスの承認と転送を完了する

注: 承認インターフェイスの同意インターフェイスにはいくつかの問題があり、送信/取り消し、拒否などの操作をテストできます。

提交代码

フルスクリーンプラグインへのリファレンス

目標: ページの全画面表示機能の実現

プラグインを使用すると全画面機能を実現できます

最初のステップは、グローバル プラグインをスクリーンフルにインストールすることです

$ npm i スクリーンフル

2 番目のステップは、全画面表示用にプラグインをカプセル化することです。src/components/ScreenFull/index.vue

<template> 
  <!-- アイコンを配置 --> 
  <div> 
    <!-- SVG アイコンを配置 --> 
    <svg-icon icon-class="fullscreen" style="color:#fff; width: 20px ; height: 20px" @click="changeScreen" /> 
  </div> 
</template> 
<script>
 
import ScreenFull from 'screenfull' 
exportdefault { 
  methods: { 
    // フルスクリーンを変更します
    changeScreen() { 
      if (!ScreenFull.isEnabled ) { 
        // 現時点では全画面表示は利用できません
        this.$message.warning('現時点では全画面コンポーネントは利用できません') 
        return 
      } 
      // document.documentElement。requestFullscreen() ネイティブ js 呼び出し
      // 利用可能な場合は全画面
      ScreenFull.toggle() 
    } 
  }
</script> 
<
スタイル> 
</スタイル>

3 番目のステップは、コンポーネントをグローバルに登録することです。src/components/index.js

import ScreenFull from './ScreenFull' 
Vue.component('ScreenFull', ScreenFull) // フルスクリーンコンポーネントを登録

layout/navbar.vue4番目のステップ、

<screen-full class="right-menu-item" />
.right-menu-item { 
   vertical-align: middle; /* 中央に変更 */ 
}

コードを送信する

本节任务: ページの全画面機能を実現します

動的テーマの設定

目标: 動的なテーマ設定を実装します。

ページ上の色をリアルタイムで切り替えたいのですが、このとき、ページのテーマは設定された色で変更できます

その原理を簡単に説明します: element-ui バージョン 2.0 以降、すべてのスタイルは SCSS に基づいて記述され、すべての色はいくつかの基本的な色変数 まず、package.jsonを通じて取得した element-ui のバージョン番号を取得し、そのバージョン番号に応じて対応するスタイルをリクエストする必要があります。スタイルを取得したら、定期的なマッチングと置換によってカラー変数を必要なものに置き換え、style元の CSS スタイルをカバーするタグを動的に追加します。

最初のステップは、色選択コンポーネントのThemePickerコード アドレス@/components/ThemePickerをカプセル化することです。

注: この章では統合に重点を置いているため、内部置き換えのトピックは現時点では無視してかまいません。

実装コードsrc/ThemePicker/index.vue

<テンプレート> 
  <el-color-picker 
    v-model="テーマ" 
    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2' , '#6959CD', '#f5222d', ]" 
    class="テーマピッカー" 
    Popper-class="テーマピッカードロップダウン" 
  /> 
</template>
 
<script>
 
const version = require('element- ui/package.json').version //node_modules からの要素 ui バージョン
const ORIGINAL_THEME = '#409EFF' // デフォルトの色
エクスポートデフォルト { 
  data() { 
    return { 
      chalk: '', // テーマチョークの内容 css
      テーマ:'' 
    } 
  }、
  計算: { 
    defaultTheme() {
      return this.$store.state.settings.theme 
    } 
  }、
  watch: { 
    defaultTheme: { 
      handler: function(val, oldVal) { 
        this.theme = val 
      }、
      immediate: true 
    }、
    async theme(val) { 
      const oldVal =これ、チョーク?this.theme : ORIGINAL_THEME 
      if (typeof val !== 'string') return 
      const themeCluster = this.getThemeCluster(val.replace('#', '')) 
      constoriginalCluster = this.getThemeCluster(oldVal.replace('#' , '')) 
      console.log(themeCluster,originalCluster) 
      const $message = this.$message({ 
        message: ' テーマをコンパイルしています',
        CustomClass: 'theme-message'、
        type: 'success'、
        duration: 0、
        iconClass: 'el-icon-loading' 
      }) 
      const getHandler = (variable, id) => { 
        return () => { 
          constoriginalCluster = this .getThemeCluster(ORIGINAL_THEME.replace('#', '')) 
          const newStyle = this.updateStyle(this[variable],originalCluster,themeCluster) 
          let styleTag = document.getElementById(id) 
          if (!styleTag) { 
            styleTag = document. createElement('style') 
            styleTag.setAttribute('id', id) 
            document.head.appendChild(styleTag) 
          }
          styleTag.innerText = newStyle 
        } 
      } 
      if (!this.chalk) { 
        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css` 
        await this.getCSSString (url, 'チョーク') 
      } 
      const chalkHandler = getHandler('チョーク', 'チョークスタイル') 
      ChalkHandler() 
      conststyles = [].slice.call(document.querySelectorAll('style')) 
        .filter(style = > { 
          const text = style.innerText 
          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text) 
        }) 
      styles.forEach(style => { 
        const { innerText } = style
        if (typeof innerText !== 'string') return 
        style.innerText = this.updateStyle(innerText,originalCluster,themeCluster) 
      }) 
      this.$emit('change', val) 
      $message.close() 
    } 
  }、
  メソッド: { 
    updateStyle(style, oldCluster, newCluster) { 
      let newStyle = style 
      oldCluster.forEach((color,index) => { 
        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index]) } 
      ) 
      return newStyle 
    }, 
    getCSSString(url, variable) { 
      return new Promise(resolve => { 
        const xhr = new XMLHttpRequest()
        xhr.onreadystatechange = () => { 
          if (xhr.readyState === 4 && xhr.status === 200) { 
            this[variable] = xhr.responseText.replace(/@font-face{[^}]+ }/, '') 
            solve() 
          } 
        } 
        xhr.open('GET', url) 
        xhr.send() 
      }) 
    }, 
    getThemeCluster(theme) { 
      const tinyColor = (color, tiny) => { 
        let red = parseInt (color.slice(0, 2), 16) 
        let green = parseInt(color.slice(2, 4), 16) 
        let blue = parseInt(color.slice(4, 6), 16) 
        if (tint === 0) { // 原色が RGB 空間にある場合
          return [red, green, blue].join(',')
        } else {
          赤 += Math.round(ティント * (255 - 赤))
          緑 += Math.round(ティント * (255 - 緑))
          青 += Math.round(ティント * (255 - 青))
          赤 = red.toString(16) 
          green = green.toString(16) 
          blue = blue.toString(16) 
          return `#${red}${green}${blue}` 
        } 
      } 
      const shadeColor = (色, シェード) => { 
        let red = parseInt(color.slice(0, 2), 16) 
        let green = parseInt(color.slice(2, 4), 16) 
        let blue = parseInt(color.slice(4, 6), 16) 
        red = Math.round((1 - 陰影) * 赤)
        緑 = Math.round((1 - 陰影) * 緑)
        blue = Math.round((1 - shade) * blue) 
        red = red.toString(16) 
        green = green.toString(16) 
        blue = blue.toString(16) 
        return `#${red}${green}$ {blue}` 
      } 
      const クラスター = [テーマ] 
      for (let i = 0; i <= 9; i++) { 
        Clusters.push(tintColor(theme, Number((i / 10).toFixed(2)))) 
      }
      クラスター.push(shadeColor(theme, 0.1))
      クラスターを返します
    } 
  } 
} 
</script> 
<style>
 
.theme-message, 
.theme-picker-dropdown { 
  z-index: 99999 !重要; 
.theme 
-picker .el-color-picker__trigger {
  高さ: 26px !重要; 
  幅: 26px !重要; 
  パディング: 2px; 
.theme-picker-dropdown .el-color-dropdown__link-btn {
表示
  : なし; 
.el 
-color-picker {
  高さ: 自動 !重要; 
} 
</スタイル>

登録コード

import ThemePicker from './ThemePicker' 
Vue.component('ThemePicker', ThemePicker)

2 番目のステップでは、次layout/navbar.vueの場所に置きます。

<!-- テーマ プラグインを配置します --> 
<theme-picker class="right-menu-item" />

コードを送信する

多言語実装

目标国際言語切り替えを実装する

多言語パッケージを初期化する

このプロジェクトは国際化 i18n スキームを使用します。vue-i18nによって実現されます。

最初のステップでは、まずパッケージを国際化する必要があります

$ npm および [email protected]

2 番目のステップでは、単一の多言語インスタンス化ファイルが必要ですsrc/lang/index.js

import Vue from 'vue' // Vue をインポート
import VueI18n from 'vue-i18n' // 国際パッケージをインポート
import Cookie from 'js-cookie' // Cookie パッケージをインポート
import elementEN from 'element-ui/lib/locale/ lang/ en' // Ele.me の英語パッケージを導入
import elementZH from 'element-ui/lib/locale/lang/zh-CN' // Ele.me の中国語パッケージを導入
Vue.use(VueI18n) // グローバル登録 国際化パッケージの
エクスポート デフォルトnew VueI18n({ 
  locale: Cookie.get(' language') || 'zh', // 言語タイプが Cookie から取得されない場合は、中国語のメッセージになります
  : { 
    en: { 
      ...elementEN // Ele を導入します.me の英語言語パック
    }, 
    zh: { 
      ...elementZH // Ele.me の中国語言語パックを紹介します
    } 
  } 
} 
)

上記のコードの機能は、Element の 2 つの言語をインポートすることです。

3 番目のステップは、i18n プラグインを main.js にマウントし、要素を現在の言語に設定することです。

import locale from 'element-ui/lib/locale/lang/en' // lang i18n // この文を削除
Vue.use(ElementUI, { locale }) // 以下のように修正します
import i18n from './lang' 
// 要素を現在の言語に設定します
Vue.use(ElementUI, { 
  i18n: (key, value) => i18n.t(key, value) 
}) 
new
Vue({ 
  el: ' #app'、
  ルーター、
  ストア、
  i18n、
  レンダリング: h => h(App) 
} 
)

カスタム言語パックをインポートする

この時点で、要素は zh、つまり中国語に変更されていますが、通常のコンテンツを現在の言語タイプに従って表示するにはどうすればよいでしょうか?

ここでは、英語と中国語用に 2 つの異なる言語パックを提供できます。src/lang/zh.js , src/lang/en.js

言語パック (リソース内ですでに提供されています)

4 番目のステップでは、index.js にも言語パックを導入します。

import customZH from './zh' // カスタムの中国語パッケージをインポート
import customEN from './en' // カスタムの英語パッケージをインポート
Vue.use(VueI18n) // グローバル登録国際化パッケージの
エクスポート デフォルト new VueI18n({ 
  locale : Cookie. get(' language') || 'zh', // 言語タイプが Cookie から取得されない場合は、中国語
  メッセージになります: { 
    en: { 
      ...elementEN, // Ele.me の英語言語パックを導入します
      ...customEN 
    }, 
    zh: { 
      ...elementZH, // Ele.me の中国語言語パックを
      ...customZHに導入します
    } 
  } 
})

左側のメニューで多言語パックを適用します

カスタム言語パックのコンテンツを使用するにはどうすればよいですか?

5番目のステップ、左側のメニューで適用します

i18n をグローバルに登録すると、各コンポーネントにメソッドが追加され$t、受信キーに応じて現在の言語のテキストが自動的に検索され、左側のメニューを多言語表示テキストに変えることができます。

layout/components/SidebarItem.vue

<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="$t('route.'+onlyOneChild.name)" />

注: テキストの値がネストされている場合、次$t(key1.key2.key3...)のようにして取得できます。

これで多言語アクセスが完了し、多言語間を切り替えるためのコンポーネントをカプセル化しました。

<span style="color:#fff;background-color:red"> ルーター/モジュールに関連するルーティング ファイル内の名前が定義されているかどうか、および言語パック内のキーと完全に一致しているかどうかを確認することに注意してください。矛盾しているため、正常に動作しません 質問を表示</span>

パッケージ多言語プラグイン

6 番目のステップは、多言語コンポーネントをカプセル化することです。 src/components/lang/index.vue

<template> 
  <el-dropdown trigger="click" @command="changeLanguage"> 
    <!-- 这里必须加一个div --> 
    <div> 
      <svg-icon style="color:#fff;font-size: 20px" icon-class="言語" /> 
    </div> 
    <el-dropdown-menu slot="dropdown"> 
      <el-dropdown-item command="zh" :disabled="'zh'=== $i18n .locale ">中文</el-dropdown-item> 
      <el-dropdown-item command="en" :disabled="'en'=== $i18n.locale ">en</el-dropdown-item> 
    </el-dropdown-menu> 
  </el-dropdown> 
</template> 
<script>
 
import Cookie from 'js-cookie' 
export default { 
  methods: { 
    changeLanguage( lang) { 
      Cookie.set(' language', lang) // 切换多语言
      this.$i18n.locale = lang // ローカル i18n プラグインに設定します
this 
      .$message.success('複数言語への切り替えに成功しました') 
    } 
  } 
</script>

// src/component/index.js に登録
import
lang from './lang' 
 Vue.component('lang', lang)

7 番目のステップは、Navbar コンポーネントに導入することです。

<!-- 複数の言語を配置して切り替える --> 
<lang class="right-menu-item" /> 
<!-- テーマを配置 --> 
<theme-picker class="right-menu-item" / > 
<! -- 全画面プラグインを配置します --> 
<screen-full class="right-menu-item" />

最終効果

コードを送信する

タブページの紹介を見る

目标:タブページでルートを開く機能を実現

現在ページを開いていて、あるページを見た後、別のページを閉じることになりますが、より効率的に表示するために、複数ページのタブコンポーネントを導入できます。

マルチタブコンポーネントのコードは複雑すぎるため、開発に実際に必要なのは統合して呼び出す機能であるため、開発したコンポーネントを現在の機能項目に統合するだけです。

リソースディレクトリでは、多页签そのディレクトリ下にコンポーネントとvuexモジュールが配置されます

最初のステップは、コンポーネントの TagsView ディレクトリを配置しsrc/components、それをグローバルに登録することです。

'./TagsView' から TagsView をインポートします
Vue.component('TagsView', TagsView)

2 番目のステップでは、tagsView.jsVuex モジュールを次の場所に配置します。src/store/modules

そしてモジュールをストアにインポートします

import tagsView from './modules/tagsView' 
const store = new Vuex.Store({ 
  modules: { 
    app, 
    settings, 
    user, 
    Permission, 
    tagsView 
  }, 
  getters 
})

3 番目のステップは、src/layout/Index.vueコンポーネントを導入することです。

<テンプレート> 
  <div :class="classObj" class="app-wrapper"> 
    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> 
    <sidebar class="sidebar-container" /> 
    <div class="main-container"> 
      <div :class="{'fixed-header':fixedHeader}"> 
        <navbar /> 
        <!-- タブビューを放置--> 
        <タグビュー /> 
      </div> 
      <アプリメイン /> 
    </div> 
  </div> 
</template>

効果は以下の通りです

提交代码

おすすめ

転載: blog.csdn.net/szw2377132528/article/details/124026954