基於SqlSugar的開發框架循序漸進介紹(13)-- 基於ElementPlus的上傳元件進行封裝,便於專案使用

2022-07-25 18:00:42

在我們實際專案開發過程中,往往需要根據實際情況,對元件進行封裝,以更簡便的在介面程式碼中使用,在實際的前端應用中,適當的元件封裝,可以減少很多重複的介面程式碼,並且能夠非常簡便的使用,本篇隨筆介紹基於ElementPlus的上傳元件進行封裝。

1、El-Upload上傳元件的使用場景及資料庫設計

在官網地址https://element-plus.org/zh-CN/component/upload.html 上有關於該元件的詳細使用程式碼案例。

大概有個場景我需要根據需要展示檔案的,一個是檔案展示方式(非圖片格式)。

 一種是肖像方式處理。

  一種方式是圖片縮圖列表方式。

 還有就是支援拖動方式上傳。

我目前大概就是想到應用這幾種方式,細節的地方可以根據需要進行微調即可。

一般來說,我們附件資訊是單獨儲存在一個表裡面的,附件則是儲存在相應的檔案系統或者FTP目錄中。如果需要了解後端不同方式的檔案上傳方式,可以瞭解隨筆《基於SqlSugar的開發框架循序漸進介紹(7)-- 在檔案上傳模組中採用選項模式【Options】處理常規上傳和FTP檔案上傳

 而實際我們業務表裡面,只需要存在一個字串欄位,它是一串GUID的值,用於參照單個或者多個附件列表的AttahmentGUID值即可。

 在前端介面使用的的時候,我則希望自定義的元件使用的時候,儘量簡單,因此對於附件上傳的URL地址、Upload元件的相關設定,應該遮蔽在自定義元件即可,元件只需要提供一個v-model的繫結值和一些需要的屬性即可。

 

2、檔案上傳後端處理

在介紹前端上傳元件自定義前,我們需要提供一個上傳檔案的URL地址給前端,接收前端的檔案流,以及相關FormData裡面的引數值。

後端上傳處理的函數定義如下所示

        /// <summary>
        /// 多檔案上傳處理(自動根據組態檔選擇合適的上傳方式)
        /// </summary>
        /// <param name="guid">附件組GUID</param>
        /// <param name="folder">指定的上傳目錄</param>
        /// <returns></returns>
        [RequestSizeLimit(100000000)] //請求正文最大大小100M
        [HttpPost]
        [Route("postupload")]
        public async Task<List<ResponseFileInfo>> PostUpload()

其中 ResponseFileInfo 是我們定義一個返回給前端使用的物件,記錄檔案的名稱、URL,id資訊。

    /// <summary>
    /// 上傳後檔案返回的結果資訊
    /// </summary>
    public class ResponseFileInfo
    {
        /// <summary>
        /// 預設建構函式
        /// </summary>
        public ResponseFileInfo() { }

        /// <summary>
        /// 引數化建構函式
        /// </summary>
        /// <param name="id"></param>
        /// <param name="name"></param>
        /// <param name="url"></param>
        public ResponseFileInfo(string id, string name, string url) 
        {
            this.Id = id;
            this.Name = name;
            this.Url = url;
        }


        /// <summary>
        /// 記錄ID
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 檔名稱
        /// </summary>

        public string Name { get; set; }

        /// <summary>
        /// 檔案路徑
        /// </summary>
        public string Url { get; set; }
    }

在後端上傳處理中,我們可以通過HTTP上下文獲得傳過來的對應引數和檔案列表資訊,如下程式碼所示。

        public async Task<List<ResponseFileInfo>> PostUpload()
        {
            var httpContext = this.HttpContext;
            string guid = httpContext.Request.Form["guid"];//input.guid;
            string folder = httpContext.Request.Form["folder"];//input.folder;
            var files = httpContext.Request.Form.Files;

最後根據檔案資訊和相關引數,構建附件資料庫資訊,以及儲存檔案就可以了,如下程式碼所示。

  

3、檔案上傳元件的前端封裝和處理

對於編輯狀態下的前端處理,我們只需要繫結v-model的值,以及指定的一些引數就可以了。

 如果是禁止上傳的詳細展示,可以設定disabled屬性為true就可以了

<el-form-item label="資料檔案">
     <my-upload v-model="viewForm.attachGUID" :data="{ guid: viewForm.attachGUID, folder: '使用者圖片' }"   disabled />
 </el-form-item>

使用者介面展示如下所示。

 通過簡單的封裝,我們就可以在極少程式碼的基礎上客製化自己的功能介面了。易於閱讀和維護,同時也有助於我們後面通過程式碼生成工具的方式快速生成相關的程式碼。

 自定義元件,我們根據需要定義一些屬性,並對它設定預設值,如下所示程式碼。

<script setup lang="ts">
import { reactive,  ref,  onMounted,  watch,  computed, getCurrentInstance} from "vue";

import { ElMessage, ElMessageBox } from "element-plus";
import type { UploadInstance, UploadProps, UploadUserFile } from "element-plus";
import { Plus, UploadFilled } from "@element-plus/icons-vue";
import { isNullOrUnDef, isEmpty } from "/@/utils/is";
import fileupload from "/@/api/fileupload";

defineOptions({ name: "MyUpload" });

//宣告Props的介面型別
interface Props {
  modelValue?: string; // 接受外部v-model傳入的值,記錄的AttachGUID值
  data?: Record<string, any>; //上傳時附帶的額外引數: {a:b}
  headers?: Headers | Record<string, any>; //設定上傳的請求頭部
  listType?: "text" | "picture" | "picture-card"; //檔案列表的型別

  disabled?: boolean; // 是否禁用
  multiple?: boolean; // 是否支援多選檔案
  limit?: number; // 最大允許上傳個數
  fileSize?: number; // 大小限制(MB)
  fileType?: Array<string>; // 檔案型別, 例如['png', 'jpg', 'jpeg']
  isShowTip?: boolean; // 是否顯示提示
  showFileList?: boolean; //是否顯示檔案列表
  withCredentials?: boolean; //支援傳送 cookie 憑證資訊
  isAvatarUpload?: boolean; // 是否是頭像上傳
  drag?: boolean; //是否啟用拖拽上傳
  buttonText?: string; //按鈕文字
}
//使用預設值定義Props
const props = withDefaults(defineProps<Props>(), {
  modelValue: "", //對應自定義元件的v-model的值
  data: () => {
    return null;
  },
  headers: () => {
    //用於上傳檔案的身份認證
    return { Authorization: "Bearer " + getAccessToken() };
  },
  listType: "text", //"text" | "picture" | "picture-card"

  disabled: false,
  multiple: false,
  // limit: 10,
  fileSize: 2, //MB
  fileType: () => {
    return ["png", "jpg", "jpeg", "gif"];
  },
  isShowTip: true,
  showFileList: true,
  withCredentials: true, //支援傳送 cookie 憑證資訊
  isAvatarUpload: false, //頭像上傳方式
  drag: false, //是否啟用拖拽上傳
  buttonText: "單擊上傳",

});
//定義觸發事件
const emit = defineEmits(["error", "success", "remove", "change"]);

在我們展示元件的時候,我們根據v-model繫結的modelValue值進行載入附件列表或者圖片資訊,

//掛載的時候初始化資料
onMounted(async () => {
  if (!isEmpty(props.modelValue)) {
    // 使用字典型別,從伺服器請求資料
    await fileupload.GetByAttachGUID(props.modelValue).then(data => {
      // console.log(data);
      if (data.length > 0) {
        var list: Array<UploadUserFile> = [];
        data.map(item => {
          let url = getUrl(item);
          let { id, fileName, fileExtend } = item; // 結構物件屬性
          list.push({
            name: fileName,
            url: url,
            uid: id
          });
        });

        fileList.value = list;
        //如果是頭像上傳模式,顯示最後一個圖片
        if (props.isAvatarUpload) {
          avatarImageUrl.value = list[0]?.url;
        }
      }
    });
  }
});

在預覽檔案的時候,我們判斷,如果是圖片檔案,就開啟視窗展示圖片,否則就下載附件即可。

//預覽檔案
const handlePreview: UploadProps["onPreview"] = uploadFile => {
  // console.log(uploadFile);
  // 當格式為圖片就預覽圖片,否則下載檔案
  let filename = uploadFile.name;
  let fileurl = uploadFile.url;
  let fileExtension = "";

  // 校檢檔案型別
  var imageTypes = ["png", "jpg", "jpeg", "gif"];
  if (filename.lastIndexOf(".") > -1) {
    fileExtension = filename.slice(filename.lastIndexOf(".") + 1);
  }
  const isTypeOk = imageTypes.some(type => {
    if (fileExtension && fileExtension.indexOf(type) > -1) return true;
    return false;
  });

  if (isTypeOk) {
    //預覽圖片
    dialogImageUrl.value = fileurl;
    dialogTitle.value = filename;
    dialogVisible.value = true;
  } else {
    //下載檔案
    dialogVisible.value = false;
    // openWindow(fileurl, { target: "_self" });
    window.open(fileurl, "_self");
  }
};

移除檔案的時候,我們根據檔案的id,在資料庫後端進行刪除附件和附件資訊。

//移除檔案前操作
const beforeRemove: UploadProps["beforeRemove"] = (uploadFile, uploadFiles) => {
  // console.log(uploadFile);
  //${uploadFile.name}
  return ElMessageBox.confirm(`確認刪除該檔案嗎?`).then(
    async () => {
      var result = false;
      var id = uploadFile.uid;
      if (!isEmpty(id)) {
        result = await fileupload.Delete(id);
      }
      return result;
    },
    () => false
  );
};

 

系列文章:

基於SqlSugar的開發框架的循序漸進介紹(1)--框架基礎類的設計和使用

基於SqlSugar的開發框架循序漸進介紹(2)-- 基於中間表的查詢處理

基於SqlSugar的開發框架循序漸進介紹(3)-- 實現程式碼生成工具Database2Sharp的整合開發

基於SqlSugar的開發框架循序漸進介紹(4)-- 在資料存取基礎類別中對GUID主鍵進行自動賦值處理 

基於SqlSugar的開發框架循序漸進介紹(5)-- 在服務層使用介面注入方式實現IOC控制反轉

基於SqlSugar的開發框架循序漸進介紹(6)-- 在基礎類別介面中注入使用者身份資訊介面 

基於SqlSugar的開發框架循序漸進介紹(7)-- 在檔案上傳模組中採用選項模式【Options】處理常規上傳和FTP檔案上傳

 《基於SqlSugar的開發框架循序漸進介紹(8)-- 在基礎類別函數封裝實現使用者操作紀錄檔記錄

基於SqlSugar的開發框架循序漸進介紹(9)-- 結合Winform控制元件實現欄位的許可權控制

基於SqlSugar的開發框架循序漸進介紹(10)-- 利用axios元件的封裝,實現對後端API資料的存取和基礎類別的統一封裝處理

基於SqlSugar的開發框架循序漸進介紹(11)-- 使用TypeScript和Vue3的Setup語法糖編寫頁面和元件的總結

基於SqlSugar的開發框架循序漸進介紹(12)-- 拆分頁面模組內容為元件,實現分而治之的處理