在前面隨筆《基於SqlSugar的開發框架循序漸進介紹(12)-- 拆分頁面模組內容為元件,實現分而治之的處理》中我們已經介紹過,對於相關的業務表的介面程式碼,我們已經儘可能把不同的業務邏輯封裝在不同的頁面元件中,隔離變化的差異,因此介面元件化後,就可以利用程式碼生成工具進行統一的介面程式碼的生成了,而且由於變化的隔離處理,我們實際上維護的程式碼變得更加方便維護了。本篇隨筆介紹在整合程式碼生成工具進行前端介面的生成的一些思路和實際的介面程式碼的生成。
在前面隨筆《基於SqlSugar的開發框架循序漸進介紹(12)-- 拆分頁面模組內容為元件,實現分而治之的處理》中我們已經介紹過,常規頁面包含有列表介面,新增、編輯、檢視、匯入等介面,除了列表頁面,其他內容以彈出層對話方塊的方式進行處理,如下介面示意圖所示。
因此在index.vue頁面中,我們整合了幾個元件頁面即可,如下所示。
<template> <div class="main"> <!--條件及列表展示--> <Search ref="searchRef" @show-import="showImport" @show-add="showAdd" @show-view="showView" @show-edit="showEdit" /> <!--檢視詳細元件介面--> <view-data ref="viewRef" /> <!--新增、編輯元件介面--> <edit-data ref="editRef" @submit="refreshData" /> <!--模板匯入資訊--> <import-data ref="importRef" @finish="finishImport" /> </div> </template> <script setup lang="ts"> import { reactive, ref, onMounted } from 'vue'; import Search from './search.vue'; import ViewData from './view.vue'; import EditData from './edit.vue'; import ImportData from './import.vue';
1)檢視檢視頁面
我們先以view.vue檢視頁面為例進行介紹,它是一個檢視明細的介面,因此也是一個彈出對話方塊頁面,我們把它的程式碼處理如下所示。
<template> <el-dialog v-if="isVisible" v-model="isVisible" title="檢視資訊" append-to-body @close="closeDialog"> <el-form ref="viewRef" :model="viewForm" label-width="100px"> <el-tabs type="border-card"> <el-tab-pane label="基本資訊"> <el-descriptions title="" :column="2" border> <el-descriptions-item label="顯示名稱"> {{ viewForm.name }} </el-descriptions-item> <el-descriptions-item label="Web地址"> {{ viewForm.url }} </el-descriptions-item> <el-descriptions-item label="Web圖示"> <!-- {{ viewForm.webIcon }} --> <icon :icon="viewForm.webIcon" /> </el-descriptions-item> <el-descriptions-item label="排序"> {{ viewForm.seq }} </el-descriptions-item> <el-descriptions-item label="可見"> <el-tag v-if="viewForm.visible" type="success" effect="dark">可見</el-tag> <el-tag v-else type="danger" effect="dark">隱藏</el-tag> </el-descriptions-item> <el-descriptions-item label="展開"> <el-tag v-if="viewForm.expand" type="success" effect="dark">展開</el-tag> <el-tag v-else type="" effect="dark">收縮</el-tag> </el-descriptions-item> <el-descriptions-item label="建立時間"> <el-date-picker v-model="viewForm.createTime" align="right" type="datetime" placeholder="選擇日期" value-format="YYYY-MM-DD HH:mm" disabled /> </el-descriptions-item> <el-descriptions-item label="特殊標籤"> {{ viewForm.tag }} </el-descriptions-item> </el-descriptions> </el-tab-pane> </el-tabs> </el-form> <template #footer> <span class="dialog-footer"> <el-button @click="closeDialog">關閉</el-button> </span> </template> </el-dialog> </template>
其他的js程式碼採用tyepscript語法,我們把它放在
<script setup lang="ts"> //邏輯程式碼 </script>
然後我們在js程式碼中丟擲show的方法,便於父元件的呼叫。
//顯示視窗 const show = (id: string | number) => { if (!$u.test.isNullOrUnDef(id)) { menu.Get(id).then((data) => { Object.assign(viewForm, data); isVisible.value = true; //顯示對話方塊 }); } }; //暴露元件屬性和方法 defineExpose({ show, });
同時在頁面裡面,也定義一個表單的物件參照,便於上面模板元件的顯示。
const viewRef = ref<FormInstance>(); //表單參照 // 表單屬性定義 let viewForm = reactive({ iD: '', pid: '', name: '', icon: '', seq: '', functionId: '', visible: 0, expand: 0, winformType: '', url: '', webIcon: '', creator: '', createTime: '', tag: '', });
如果是檢視詳細的檢視中有樹形列表,我們還可以在onMounted的處理中,新增獲取樹列表的資料即可,如下程式碼所示。
//掛載的時候初始化資料 onMounted(() => { // 設定預設值 getTree(); }); // 初始化樹列表 let treedata = ref([]); const getTree = () => { // 樹列表資料獲取 menu.GetAll().then((data) => { treedata.value = []; // 樹列表清空 var list = data?.items; if (list) { var newTreedata = $u.util.getJsonTree(list, { id: 'id', pid: 'pid', label: 'name', children: 'children', }); treedata.value = newTreedata; } }); };
而檢視檢視的觸發,往往在列表的操作按鈕中,或者雙擊表格行進行觸發,介面如下所示。
介面如下程式碼所示。
而呼叫檢視詳細頁面的事件,傳遞對應的id並呼叫元件範例丟擲的方法即可。如下程式碼所示。
// 顯示檢視對話方塊處理 const viewRef = ref<InstanceType<typeof ViewData>>(); function showView(id) { viewRef.value.show(id); }
至此,一個獨立的檢視頁面元件,以及如何觸發呼叫就完成了,檢視頁面單獨維護,便於程式碼的管理,同時也隔離了複雜的頁面邏輯。
檢視頁面效果如下所示。
2)新增編輯檢視頁面
在常規的處理中,往往編輯和新增的介面是差不多的,差異不同的地方,我們可以通過條件 if 的方式進行處理即可。因此可以把兩者放在一個元件中實現對話方塊內容和邏輯處理。
剛才我們提到了Index.vue頁面,是對幾個元件的統籌處理,如下程式碼所示。
<template> <div class="main"> <!--條件及列表展示--> <Search ref="searchRef" @show-import="showImport" @show-add="showAdd" @show-view="showView" @show-edit="showEdit" /> <!--檢視詳細元件介面--> <view-data ref="viewRef" /> <!--新增、編輯元件介面--> <edit-data ref="editRef" @submit="refreshData" /> <!--模板匯入資訊--> <import-data ref="importRef" @finish="finishImport" /> </div> </template>
從上面程式碼我們看到,在HTML程式碼中,我們引入對應的元件,並在主查詢頁面中觸發事件即可,如下所示。
其中showAdd和ShowEdit類似,都是呼叫編輯/新增的對話方塊,不同的是,通過傳遞id來辨別是否為新增,如果需要傳入pid的父節點資訊,那麼我們也可以建立一個showAdd的方法。
//新增、編輯表單參照 const editRef = ref<InstanceType<typeof EditData>>(); //顯示新增對話方塊 function showAdd(pid?: string | number) { editRef.value.showAdd(pid); } // 顯示編輯對話方塊 function showEdit(id) { editRef.value.show(id); } //新增/更新後重新整理 function refreshData() { searchRef.value.getlist(); }
編輯業務資料的對話方塊和檢視詳細的類似,不過這裡是需要使用輸入控制元件進行內容編輯修改處理的。
對於一些複雜控制元件,我們可以自定義元件來簡化在介面上的使用,儘可能的快捷、簡單。
我們在元件中定義showAdd和show的方法,便於父元件的呼叫即可,如果傳遞了id值,我們根據業務物件的get方法獲取詳細的資料,賦值到表單物件上就可以正常顯示了。
//預設標題為[編輯資訊],當show傳入id為空的時候,為[新建資訊] let title = ref('編輯資訊'); let isAdd = ref(false); //是否新增狀態 //顯示視窗(編輯/新建) const showAdd = async (pid?: string | number) => { title.value = '新建資訊'; isAdd.value = true; resetFields(); //清空表單 editForm.pid = pid + ''; isVisible.value = true; //顯示對話方塊 }; const show = async (id?: string | number) => { if (!$u.test.isNullOrUnDef(id)) { title.value = '編輯資訊'; isAdd.value = false; await menu.Get(id).then((data) => { Object.assign(editForm, data); }); } else { title.value = '新建資訊'; isAdd.value = true; resetFields(); //清空表單 } isVisible.value = true; //顯示對話方塊 };
丟擲這兩個範例的方法,供外面呼叫。
//暴露元件屬性和方法 defineExpose({ show, showAdd, });
為了承載表單的資料模型,我們建立相關的業務物件
const editRef = ref<FormInstance>(); //表單參照 // 表單屬性定義(初始化) let editForm = reactive({ id: '', pid: '', name: '', icon: '', functionId: '', winformType: '', url: '', seq: '001', isTop: false, expand: 1, visible: 1, webIcon: '', tag: 'web', // Web專用 });
儲存資料的時候,我們判斷表單的rules規則,如果符合通過,那麼提交資料並提示使用者即可。
// 儲存資料處理 async function submitData() { var formEl = editRef.value; if (!formEl) return; await formEl.validate(async (valid) => { if (valid) { //驗證成功,執行下面方法 var result = false; if (isAdd.value) { result = await menu.Create(editForm); //新增儲存 } else { result = await menu.Update(editForm); //編輯儲存 } if (result) { $u.success('操作成功!'); // 提示資訊 emit('submit'); // 提示重新整理資料 closeDialog(); // 重置視窗狀態 } else { $u.error('操作失敗'); } } }); }
編輯介面的效果如下所示。
3)匯入介面的處理
匯入介面,一般我們分為幾個步驟,一個是提供匯入模板下載,然後上傳檔案並顯示資料,然後確認提交即可。
由於匯入資料的邏輯上大致類似,不同的是他們的業務資料和驗證規則,因此我們通過自定義元件的方式,來簡化相關的處理。
我通過改造ele-import 的第三方元件,讓它支援Vue3+Typescript語法,實現對業務資料的上傳操作。
<template> <div class="main"> <!--條件及列表展示--> <Search ref="searchRef" @show-import="showImport" @show-add="showAdd" @show-view="showView" @show-edit="showEdit" /> <import-data ref="importRef" @finish="finishImport" /> </div> </template>
而在import.vue頁面裡面,我們的程式碼是使用ele-import來處理即可。
<template> <div> <!-- 模板匯入資訊 --> <ele-import :fields="importForm.fields" :filepath="importForm.filepath" :append="importForm.append" :formatter="importForm.formatter" :rules="importForm.rules" :tips="importForm.tips" :title="importForm.title" :visible="isVisible" :request-fn="saveImport" @close="close" @finish="finishImport" /> </div> </template>
通過傳入對應的資料,如匯入欄位,以及規則,以及下載檔案等相關引數,就可以實現了檔案的上傳處理了。
// 請求伺服器端處理上傳資料,返回一個Promise物件 const saveImport = async (data) => { // console.log(data); const result = await menu.SaveImport(data); // console.log(result); if (result) { return Promise.resolve(); } else { return Promise.reject(); } };
同時,這也是一個彈出視窗,因此也需要暴露show方法給外部呼叫。
//顯示視窗 const show = () => { isVisible.value = true; //顯示對話方塊 }; //暴露元件屬性和方法 defineExpose({ show, });
而這個元件的相關資料資訊,定義在importForm中,我們來看看對應的資料格式。
const importForm = reactive({ // Excel 模板匯入資料 // 彈出層標題 title: '功能選單匯入', // 提示資訊 tips: [], // ['商品編號 必填', '產品型別 必填', '商品名稱 必填'], // 欄位名稱參照表 fields: { // 欄位根據需要裁剪 pid: '父ID', name: '顯示名稱', icon: '圖示', seq: '排序', url: 'Url地址', webIcon: '選單圖示', systemType_ID: '系統編號', tag: '特殊標籤', },// 附加資料, 在每條記錄上都會加這兩個欄位和值 append: { // company: '廣州愛奇迪', // leader: '伍華聰' }, // 引數校檢, 和 element-ui 中 form表單中傳遞的rules一樣, 都是使用的 async-validator 庫 // https://element.eleme.cn/#/zh-CN/component/form#biao-dan-yan-zheng rules: { pid: { type: 'string', required: true, message: '父ID必填' }, name: { type: 'string', required: true, message: '顯示名稱必填' }, url: { type: 'string', required: true, message: 'Url地址必填' }, webIcon: { type: 'string', required: true, message: '選單圖示必填' }, systemType_ID: { type: 'string', required: true, message: '系統編號必填' }, tag: { type: 'string', required: true, message: '特殊標籤必填' }, }, // Excel模板下載地址。注意, 只能是.xlsx的檔案, .xls或者.cvs都會報錯 filepath: 'http://localhost:5043/UploadFiles/template/功能選單.xlsx', });
整個匯入模組,會通過這個物件的資料格式,進行不同的顯示和校驗處理等操作。介面效果如下所示。
其中第一步提示資訊,並提供模板檔案下載
第二步提供檔案上傳處理。
第三步確認資料並完成處理。
這種統一的操作,我們通過封裝,隔離了邏輯步驟的協調處理,只需要在業務元件中生成相關的資料即可,便於使用。
通過上面的介紹,我們瞭解到整個頁面的元件程式碼結構,因此可以利用它們和資料表之間的關係,生成對應的頁面元件,利用程式碼生成工具Database2Sharp強大的資料庫後設資料和模板引擎,我們構建了對應的框架程式碼生成規則,因此統一生成即可,提高了程式碼開發的效能,同時也統一了程式碼的結構,便於大專案的維護。
對於SQLSugar的專案框架,我們為了方便,分別單獨提供後端程式碼和Web API程式碼的生成、Winform介面程式碼的生成,以及前面介紹到的Vue3+TypeScript+ElementPlus的程式碼生成操作。
程式碼生成工具的介面效果如下所示,通過入口選單,可以實現不同部分的程式碼快速生成。
通過隔離頁面元件的內容變化,實現變化不同通過資料庫表關係生成,固定部分採用規定模板預置內容,實現了程式碼的快速生成操作。
系列文章:
《基於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)-- 拆分頁面模組內容為元件,實現分而治之的處理》
《基於SqlSugar的開發框架循序漸進介紹(13)-- 基於ElementPlus的上傳元件進行封裝,便於專案使用》
《基於SqlSugar的開發框架循序漸進介紹(14)-- 基於Vue3+TypeScript的全域性物件的注入和使用》