微信搜尋【大奇測試開】,關注這個堅持分享測試開發乾貨的傢伙。
開篇說個小討論,一個群裡聊天聊到關於更新篇章的長度,是小篇幅多次,還是每次按照一個小完整的功能,我個人的是按照後種來的,主要的思考就是希望集中的時間段去實踐,這樣效率高且有每次會有一個小小的成就感,另一種當然有它的好處,更能持續輸出,看的內容少,且很有助於閱讀量。因此做個個小小的互動,歡迎留言,看看大家的想法~
本篇內容思維導
服務應用管理,主要是前端的知識點,學習一種新的前端控制元件作為新增修改基層頁,再重點掌握下表單資料提交的時候校驗,這裡不限於非空、格式等。對於後端的沒有新增的知識點,可以參照專案產品分類管理的程式碼分別寫新增和修改兩個介面,也可按照這次我將兩個介面合併成一個介面,其實就是之前有一章節留過的一個思考題“如何實現兩個介面的合併”不知道還有沒印象,總之本篇內容不是很多,加油~
知識點學習
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更新迴圈之後執行。
【程式碼更新】
- 地址:https://github.com/mrzcode/TestProjectManagement
- TAG:TPMShare10
【註解&參考】
-
[註解1] https://element.eleme.io/#/zh-CN/component/drawer
-
[註解2] https://element.eleme.io/#/zh-CN/component/form#biao-dan-yan-zheng
堅持原創,堅持實踐,堅持乾貨,如果你覺得有用,請點選推薦,也歡迎關注我部落格園和微信公眾號。