堅持原創,堅持實踐,堅持乾貨,如果你覺得有用,請點擊推薦,也歡迎關注我博客園和微信公眾號。
測試開發【提測平台】分享10-Element UI抽屜和表單校驗&增改接口合併實現應用管理
微信搜索【大奇測試開】,關注這個堅持分享測試開發乾貨的傢伙。
開篇說個小討論,一個群里聊天聊到關於更新篇章的長度,是小篇幅多次,還是每次按照一個小完整的功能,我個人的是按照後種來的,主要的思考就是希望集中的時間段去實踐,這樣效率高且有每次會有一個小小的成就感,另一種當然有它的好處,更能持續輸出,看的內容少,且很有助於閱讀量。因此做個個小小的互動,歡迎留言,看看大家的想法~
本篇內容思維導
服務應用管理,主要是前端的知識點,學習一種新的前端控件作為新增修改基層頁,再重點掌握下表單數據提交的時候校驗,這裡不限於非空、格式等。對於後端的沒有新增的知識點,可以參照項目產品分類管理的代碼分別寫新增和修改兩個接口,也可按照這次我將兩個接口合併成一個接口,其實就是之前有一章節留過的一個思考題「如何實現兩個接口的合併」不知道還有沒印象,總之本篇內容不是很多,加油~
知識點學習
Drawer 抽屜
之前產品修改和添加是使用Dialog組件實現的,但這個組件有時候並不滿足我們的需求, 比如表單很長, 亦或是你需要臨時展示一些文檔, Drawer 是可以從側面彈出的一個層,可以容納更多的控件,優化交互體驗。基本用法
<el-drawer title="我是從右到左側展示的抽屜" :visible.sync="drawer" direction="rtl"> 這裡可組合放其他組件Body部分 </el-drawer> <!..script部分省略..>
顯示和隱藏通過 visible 屬性,類型是 boolean,當為 true 時顯示 Drawer。Drawer 分為兩個部分:title 和 body,title 可省略, direction為設置打開方向, Drawer 默認是從右往左打開,其他方向包括ltr(從左到右)、ttb(從上到下)、btt(從下往上),更多屬性事件參考官方[註解1]
Form 表單驗證
在之前的產品添加和修改功能都是直接提交的,一些驗證是在後端做的處理,正常情況下,前端提交數據的時候就要進行一些如非空校驗、是否為字符串、是否符合正則規則等,這裡Form 組件是直接提供了表單驗證的功能,只需要通過 rules 屬性傳入約定的驗證規則,支持默認屬性綁定和自定義校驗。更多參考[註解2],示例代碼:
<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> <el-form-item label="綁定規則校驗對應prop屬性" prop="name"> <el-input v-model="ruleForm.name"></el-input> </el-form-item> <el-form-item label="密碼自定義校驗" prop="pass"> <el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm('ruleForm')">提交事件校驗</el-button> <el-button @click="resetForm('ruleForm')">重置</el-button> </el-form-item> </el-form> <script> export default { data() { var validatePass = (rule, value, callback) => { if (value === '') { callback(new Error('請輸入密碼')); } else { if (this.ruleForm.checkPass !== '') { this.$refs.ruleForm.validateField('checkPass'); } callback(); } }, return { ruleForm: { name: '', checkPass:'' }, rules: { name: [ { required: true, message: '請輸入活動名稱', trigger: 'blur' }, { min: 3, max: 5, message: '長度在 3 到 5 個字符', trigger: 'blur' } ], pass: [ { validator: validatePass, trigger: 'blur' } ] } }; }, methods: { submitForm(formName) { // 這裡是提交前觸發校驗 this.$refs[formName].validate((valid) => { if (valid) { alert('submit!'); } else { console.log('error submit!!'); return false; } }); }, resetForm(formName) { // 清除所有校驗提示 this.$refs[formName].resetFields(); } } } </script>
1)表單通過 :rules=”rules” ref=”ruleForm”進行數據和屬性綁定
2)行項目中 prop=””去綁定規則對應的key,這裡最好數據和驗證的key保持一致
3)基本屬性配置包括是否必須,字符的長短等,詳細參考規則async-validator
4) 自定義規則是一些較為複雜的校驗通過回調進行邏輯自定義,參考例子第二個form-item
5)上述被定義required: true規則的控件在會自動增加 紅色*號,trigger 定義什麼時候觸發校驗
項目實戰應用
按慣例,看完新知識點後,繼續參照之前的產品原型和需求實現本期項目開發內容,即應用管理中的增加和修改功能原型和需求
此頁面 添加/修改 功能需求說明:
-
點擊添加/編輯彈抽屜,紅色 * 為必填選項
-
分類來源歸屬分類,外鍵關聯
-
應用名稱有重名校驗,創建後不可以修改
-
默認必須有測試、研發和產品負責人,多人郵件用;分隔
-
目前要求必須填寫代碼地址,以便測試人員了解信息,編寫測試code
-
以上數據字符長度暫無限制
功能實現(步驟)偽代碼
-
Python Flask 編寫一個接口同時實現添加和修改數據功能
-
創建抽屜控件,內嵌form,實現原型中的各控件綁定
-
控件紅色*標記的規則配置,觸發方式trigger: ‘blur’即點擊提交統一校驗,
-
頁面修改和添加使用同一個Drawer 標題根據上一步操作動態顯示 「應用添加」 / 「應用編輯」
-
應用編輯的自增ID不需要顯示,應用ID不可編輯
實踐參考(本章)實現
1. 應用增改接口實現
這個合併接口的實現核心的邏輯點就是根據前端是否傳了數據庫id主鍵,如果有便認為是歷史數據,走修改操作,否則走添加邏輯,完整代碼和說明見代碼:
@app_application.route("/api/application/update",methods=['POST']) def product_update(): # 獲取傳遞的數據,並轉換成JSON body = request.get_data() body = json.loads(body) # 定義默認返回體 resp_success = format.resp_format_success resp_failed = format.resp_format_failed # 判斷必填參數 if 'appId' not in body: resp_failed.message = '應用不能為空' return resp_failed elif 'tester' not in body: resp_failed.message = '測試負責人不能為空' return resp_failed elif 'developer' not in body: resp_failed.message = '測試負責人不能為空' return resp_failed elif 'producer' not in body: resp_failed.message = '產品負責人不能為空' return # 使用連接池鏈接數據庫 connection = pool.connection() # 判斷增加或是修改邏輯 with connection: # 如果傳的值有ID,那麼進行修改操作,否則為新增數據 if 'id' in body and body['id'] != '': with connection.cursor() as cursor: # 拼接修改語句,由於應用名不可修改,不需要做重複校驗appId sql = "UPDATE `apps` SET `productId`=%s, `note`=%s,`tester`=%s,`developer`=%s,`producer`=%s,`cCEmail`=%s, " \ "`gitCode`=%s, `wiki`=%s, `more`=%s, `creteUser`=%s, `updateUser`=%s, `updateDate`= NOW() WHERE id=%s" cursor.execute(sql, (body["productId"], body["note"], body["tester"], body["developer"], body['producer'], body["cCEmail"], body["gitCode"], body["wiki"], body["more"], body["creteUser"], body["updateUser"], body["id"])) # 提交執行保存更新數據 connection.commit() else: # 新增需要判斷appId是否重複 with connection.cursor() as cursor: select = "SELECT * FROM `apps` WHERE `appId`=%s AND `status`=0" cursor.execute(select, (body["appId"],)) result = cursor.fetchall() # 有數據說明存在相同值,封裝提示直接返回 if len(result) > 0: resp_failed["code"] = 20001 resp_failed["message"] = "唯一編碼keyCode已存在" return resp_failed with connection.cursor() as cursor: # 拼接插入語句,並用參數化%s構造防止基本的SQL注入 # 其中id為自增,插入數據默認數據設置的當前時間 sql = "INSERT INTO `apps` (`appId`,`productId`,`note`,`tester`,`developer`,`producer`,`cCEmail`,`gitCode`" \ ",`wiki`,`more`,`creteUser`,`updateUser`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)" cursor.execute(sql, (body["appId"],body["productId"], body["note"], body["tester"], body["developer"], body['producer'],body["cCEmail"], body["gitCode"],body["wiki"],body["more"],body["creteUser"],body["updateUser"])) # 提交執行保存新增數據 connection.commit() return resp_success
2. 組合表單的抽屜控件實現
在app.vue 代碼文件<script></script> 添加綁定數據和基本規則
1)不要忘記登錄人的變量導入
2)規則和請求變量的key一定確保一致
3)除了選擇框為改變時候觸發校驗,其他都使用提交時候再做統一校驗
data() { return { // 獲得登錄的名字 op_user: store.getters.name, // 定義動作 appAction: 'ADD', // 控制抽屜顯示隱藏 drawerVisible: false, // 添加/修改綁定的數據 appInfo: { id: '', appId: '', productId: '', note: '', tester: '', developer: '', producer: '', cCEmail: '', gitCode: '', wiki: '', more: '', creteUser: '', updateUser: '' }, // 規則設定 rules: { appId: [ { required: true, message: '請輸應用名稱', trigger: 'blur' } ], productId: [ { required: true, message: '請選擇所屬範圍', trigger: 'change' } ], tester: [ { required: true, message: '請輸入測試負責人', trigger: 'blur' } ], developer: [ { required: true, message: '請輸入開發負責人', trigger: 'blur' } ], producer: [ { required: true, message: '請輸入產品負責人', trigger: 'blur' } ] } } }
在app.vue 代碼文件 <div class=”app-container”> </div>內編寫組合控件
1)標題和appId是否可編輯根據 appAction 判斷根據
2)歸屬分類沿用搜索里的下拉實現,也可以使用基本方式
3)實現規則一定注意el-form-item 中 prop 的定義和一致性
<el-drawer :title="appAction==='ADD'? '添加應用': '修改應用'" :visible.sync="drawerVisible" size="45%" direction="rtl"> <div> <el-form :model="appInfo" :rules="rules" ref="appInfo" label-width="120px"> <el-form-item label="應用ID" prop="appId" > <el-input v-model="appInfo.appId" :disabled="appAction==='ADD'? false : true" style="width: 300px"/> </el-form-item> <el-form-item label="歸屬分類" prop="productId"> <el-select v-model="appInfo.productId" style="width: 300px"> <el-option v-for="item in options" :key="item.id" :label="item.title" :value="item.id"> <span style="float: left">{{ item.keyCode }}</span> <span style="float: right; color: #8492a6; font-size: 13px">{{ item.title }}</span> </el-option> </el-select> </el-form-item> <el-form-item label="應用描述"> <el-input v-model="appInfo.note" style="width: 300px"/> </el-form-item> <el-form-item label="測試負責" prop="tester"> <el-input v-model="appInfo.tester" style="width: 300px"/> </el-form-item> <el-form-item label="研發負責" prop="developer"> <el-input v-model="appInfo.developer" style="width: 300px"/> </el-form-item> <el-form-item label="產品負責" prop="producer"> <el-input v-model="appInfo.producer" style="width: 300px"/> </el-form-item> <el-form-item label="默認抄送"> <el-input v-model="appInfo.cCEmail" style="width: 300px"/> </el-form-item> <el-form-item label="代碼地址"> <el-input v-model="appInfo.gitCode" style="width: 300px"/> </el-form-item> <el-form-item label="相關wiki"> <el-input v-model="appInfo.wiki" style="width: 300px"/> </el-form-item> <el-form-item label="更多信息"> <el-input v-model="appInfo.more" style="width: 300px"/> </el-form-item> <el-form-item> <span class="dialog-footer"> <el-button @click="drawerVisible=false">取 消</el-button> <el-button type="primary" @click="commitApp('appInfo')">提 交</el-button> </span> </el-form-item> </el-form> </div> </el-drawer>
3. 實現接口請求
在app.js 定義/api/application/update接口模版請求
// 調用應用增加/修改統一接口 export function apiAppsCommit(requestBody) { return request({ url: '/api/application/update', method: 'post', data: requestBody }) }
在app.vue 代碼文件<script></script> 實現添加和修改請求方法
1)addApp上節的佔位的方法體,這裡要實現信息清空和動作定義
2)updateApp 同樣,實現選擇的數據反填和遺留信息清空基本操作
3)請求後端接口要在所以規則校驗通過後才進行真正的提交
addApp() { // 定義動作,以抽屜做判斷 this.appAction = 'ADD' // 添加數據初始化 this.appInfo.id = '' this.appInfo.appId = '' this.appInfo.productId = '' this.appInfo.note = '' this.appInfo.tester = '' this.appInfo.developer = '' this.appInfo.producer = '' this.appInfo.cCEmail = '' this.appInfo.gitCode = '' this.appInfo.wiki = '' this.appInfo.more = '' this.appInfo.creteUser = this.op_user this.appInfo.updateUser = this.op_user // 初始化完成後顯示抽屜 this.drawerVisible = true // 如果有遺留驗證清空 this.$nextTick(() => { this.$refs['appInfo'].resetFields() }) }, updateApp(row) { // 定義動作,以抽屜做判斷 this.appAction = 'UPDATE' // 初始化完成後顯示抽屜 this.drawerVisible = true // 如果有遺留驗證清空 this.$nextTick(() => { this.$refs['appInfo'].resetFields() }) // 選擇數據反填抽屜表單中 this.appInfo.id = row.id this.appInfo.appId = row.appId this.appInfo.productId = row.productId this.appInfo.note = row.note this.appInfo.tester = row.tester this.appInfo.developer = row.developer this.appInfo.producer = row.producer this.appInfo.cCEmail = row.cCEmail this.appInfo.gitCode = row.gitCode this.appInfo.wiki = row.wiki this.appInfo.more = row.more this.appInfo.creteUser = '' this.appInfo.updateUser = row.updateUser }, commitApp() { // 上邊form定義ref,驗證通過if valid的方式判斷 this.$refs['appInfo'].validate((valid) => { if (valid) { this.appInfo.updateUser = this.op_user apiAppsCommit(this.appInfo).then(response => { // 如果request.js沒有攔截即表示成功,給出對應提示和操作 this.$notify({ title: '成功', message: this.appAction === 'ADD' ? '應用添加成功' : '應用修改成功', type: 'success' }) // 關閉對話框 this.drawerVisible = false // 重新查詢刷新數據顯示 this.getProductList() }) } else { return false } }) }
4. 聯調前後端運行
分別運行前後端,解決掉運行中的錯誤後,做兩條測試驗證功能是否OK
1)添加操作,默認為空數據,提交不完整信息是否有校驗提示阻止提交
2)編輯操作,數據是否正常反填,修改後提交是否正常更新落庫
以上為本篇全部內容,目前應用管理的方面開發全部開發完了,後邊將進入提測的主流程階段。
設計開發中會遇到各種各樣的問題,這些文章有我在寫的時候都需要半天,有時候需要幾天,因為總會有困難點和調試的問題,我相信大家在實踐中更是如此,就即使你是完全複製粘貼的代碼,但有問題我覺得是好事,這能讓我們可以知其然,知其所以然,以及逐漸了解到解決問題方式。大家有什麼問題可以留言交流或和關注公眾號發私信,看到我會儘可能幫忙解答。
問題集錦
1. Form表單中的驗證無效
本篇在開發整理中遇到了,form表單驗證怎麼也不生效的問題,搞了好久,最終是由於綁定的數據的方式弄混了,將 :mode 習慣的用了v-mode,另外也涉及了:ref定義一致性問題,如果你也遇到規則不生效請檢查這些方面。
2.規則驗證重置resetFields報錯
在添加和修改的方法中,為了清除掉之前可能遺留的驗證提示,使用了resetFields,但卻忽略了它是需要依賴控件加載完成後才能調用,所以需要調在抽屜顯示之後才調用,另外還需要使用到 this.$nextTick 回調延遲到下次DOM更新循環之後執行。
【代碼更新】
- 地址://github.com/mrzcode/TestProjectManagement
- TAG:TPMShare10
【註解&參考】
-
[註解1] //element.eleme.io/#/zh-CN/component/drawer
-
[註解2] //element.eleme.io/#/zh-CN/component/form#biao-dan-yan-zheng