iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
Software Development

全端工程師團隊的養成計畫系列 第 23

Day23 Vue 模板改造實戰:使用者群組授權功能(一)

  • 分享至 

  • xImage
  •  

接下來兩天的重點依然是進行套版改造,需求與 Day17 的功能權限控管 有關。目標是讓管理人員能透過 使用者群組 (User Group) 授權機制,決定哪些功能介面可供使用。先回顧 Day17 的 User Group 授權模式(見圖 23-1),本次需要完成的功能如下:

  1. 群組功能設定:管理者建立群組後,需提供介面勾選該群組可使用的功能。
  2. 跨群組授權:允許同一功能被多個群組勾選,並將設定結果回寫至資料庫。
  3. 功能分類呈現:功能雖然屬於不同分類,但在介面上需依分類排列,例如圖 23-1 中的功能 A1 隸屬於功能群組 A,B1 則屬於功能群組 B。

圖23-1:管理人員設定 User Group 開放功能示意圖
圖23-1

從前端 Vue 專案開始著手

  1. 先透過套版的 full-version 選擇合適的樣板,下圖示範了適合用來呈現功能清單並支援勾選的套版。

圖23-2:將此套版改造為功能清單介面
圖23-2

  1. 開啟套版的 Vue 程式碼,檢視 script 區域以確認可改造的方式:
  • script 區域:原本使用 todos array 來列出勾選項目,可以沿用相同概念,將 todos array 替換為 TDO 物件,用來讀取各分類的功能清單並存放於 TDO 中,應能相對容易地實現。
<script setup lang="ts">
import { shallowRef } from 'vue';
const todos = shallowRef([
  {
    item: 'Check your Email',
    done: true
  },
  {
    item: 'Make YouTube Video',
    done: true
  },
  {
    item: 'Create Banner',
    done: true
  },
  {
    item: 'Upload Project',
    done: false
  },
  {
    item: 'Update Task',
    done: false
  },
  {
    item: 'Task Issue',
    done: false
  },
  {
    item: 'Deploy Project',
    done: false
  }
]);

</script>
  1. 檢視套版的 Vue 程式碼 template 區域:
  • 功能清單本身並不難,但因為存在多個功能群組,需要進行調整。換句話說,必須有多個 todos array 來渲染多個 Cards,類似 圖23-3 的樣子。
  • 因此,todos array 需要再往上新增一個「功能類別」層級,並透過多一層迴圈來繪製多個 Cards。
<template>
  <div class="pa-5">
    <div class="pb-0 todo-list" v-for="(todo, i) in todos" :key="i" :value="todo.item">
      <v-checkbox :model-value="todo.done" color="primary" density="compact" hide-details>
        <template v-slot:label>
          <div class="ms-2 text-darkText">
            {{ todo.item }}
          </div>
        </template>
      </v-checkbox>
    </div>
  </div>
</template>

圖23-3:將範本中的單一卡片 (Card) 改造成多張卡片 (Cards)
圖23-3

  1. 先設計前端 DTO 所需的結構。承接第 3 點的思維,我們可以在原本的 todos array 外,再增加一層 CategoryApps,形成以下結構。整合後的介面示意如圖23-4。
const CategoryAppsList: CategoryApps[] = [];
export interface CategoryApps {
    categoryID: string; //功能類別ID 
    categoryName: string; //功能類別名稱
    categoryApps: SysApp[]; // 功能清單
}
interface SysApp {
    appID: number; // 功能清單
    appName: string; // 功能名稱
    isSelected: boolean; // 是否被選取
} 

圖23-4:CategoryAppsList 與 SysApp 結構對應示意圖
圖23-4

  1. 新增 Vue 頁面 DialogEditGroupApp.vue,作為設定使用功能的介面:
  • 匯入套版元件 UiParentCard.vue,用來包覆功能清單中的 <v-checkbox-btn> 元素。
<script setup lang="ts">
import UiParentCard from '@/views/pages/Admin/GroupAppCard.vue';
</script>
<template>
<v-row>
 <v-col v-for="category in categoryAppsList" :key="category.categoryID" class="mb-4" cols="3">
        <UiParentCard :title="category.categoryName" :categoryID="category.categoryID">
              <div class="pb-0" v-for="(app, i) in category.categoryApps" :key="i" :value="app.appID" >
              <v-checkbox-btn color="success"  hide-details v-model="app.isSelected"  aria-label="checkbox">
                <template v-slot:label>
                  <div class="ms-2 text-darkText">
                    {{ app.appName }}
                  </div>
                </template>
              </v-checkbox-btn>
            </div>
        </UiParentCard>
   </v-col>
</v-row>
</template>
  1. UiParentCard.vue 中的 template 區域
  • UiParentCard.vue 本身屬於套版元件,原則上不需大幅調整,只需顯示功能類別名稱。
  • 但本次需求是在功能類別上提供「全選」功能,因此額外加入了一個 <v-checkbox-btn>
<script setup lang="ts">
import { ref } from 'vue';
const props = defineProps({
  title: String,
  categoryID: String
});

const isSelected = ref(false);
</script>
<template>
  <v-card variant="outlined" elevation="0" class="bg-surface" rounded="lg">
    <v-card-item class="pa-5">
      <div class="d-sm-flex align-center justify-space-between">
        <v-card-title class="text-subtitle-1" style="line-height: 1.57">
          <v-checkbox-btn color="success" hide-details aria-label="checkbox" v-model="isSelected" >
            <template v-slot:label>
              <div class="ms-2 text-darkText">
                {{ props.title }}
              </div>
            </template>
          </v-checkbox-btn>
        </v-card-title>
        <slot name="action"></slot>
      </div>
    </v-card-item>
    <v-divider></v-divider>
    <v-card-text>
      <slot />
    </v-card-text>
  </v-card>
</template>

後端負責撈出所有功能的清單

完成前端物件結構設計後,接下來進入後端部分。目標是從資料庫撈取功能分類資料,並依照前端設計的 DTO 結構進行彙整,最後將結果回傳至前端。

  1. 建立 ControllerDTO。建議 DTO 與前端結構保持一致,後端先行整理好資料,讓前端能夠無縫對應並專注於畫面顯示。
//回應給前端的Dto CategoryAppsDto.cs
namespace Core.Models.Dto
{
    public class CategoryAppsDto
    {
        public required string CategoryID { get; set; }
        public required string CategoryName { get; set; }
        public required List<SysApp> CategoryApps { get; set; }
    }
    public class SysApp {
        public required int AppID { get; set; }
        public required string AppName { get; set; }
        public required bool IsSelected { get; set; }   = false;
    }
}
  1. 新增後端 Controller,用來承接前端請求並回傳功能清單資料。
//Group_AppController.cs
  [HttpGet("CategoryApps")]
  [ProducesResponseType(typeof(List<CategoryAppsDto>), 200)]
  public  async Task<IActionResult> GetCategoryApp(int userGroupId)
  {
     //userGroupId 是因為有建立不同的User 群組,需要取得該群組下哪些功能已經被勾選
     List<CategoryAppsDto> queryResults = await _rightGroupAppService.GetGroupAppbyGroupId(userGroupId);
     if (queryResults == null)
       {
          return NotFound();
       }
       return Ok(queryResults);
   }

Ending Remark

本篇完成了前端的改造以及後端資料庫的資料擷取,接下來將在下一篇中進行前後端的整合,讓功能得以完整實現。


上一篇
Day22 Vue 模板改造實戰:動態功能列
下一篇
Day24 使用模板來進行改造範例:使用者群組功能授權實作(二)
系列文
全端工程師團隊的養成計畫26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言