微信搜尋【大奇測試開】,關注這個堅持分享測試開發乾貨的傢伙。

開篇說個小討論,一個群裡聊天聊到關於更新篇章的長度,是小篇幅多次,還是每次按照一個小完整的功能,我個人的是按照後種來的,主要的思考就是希望集中的時間段去實踐,這樣效率高且有每次會有一個小小的成就感,另一種當然有它的好處,更能持續輸出,看的內容少,且很有助於閱讀量。因此做個個小小的互動,歡迎留言,看看大家的想法~

本篇內容思維導

服務應用管理,主要是前端的知識點,學習一種新的前端控制元件作為新增修改基層頁,再重點掌握下表單資料提交的時候校驗,這裡不限於非空、格式等。對於後端的沒有新增的知識點,可以參照專案產品分類管理的程式碼分別寫新增和修改兩個介面,也可按照這次我將兩個介面合併成一個介面,其實就是之前有一章節留過的一個思考題“如何實現兩個介面的合併”不知道還有沒印象,總之本篇內容不是很多,加油~

知識點學習

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

  • 以上資料字元長度暫無限制

功能實現(步驟)虛擬碼

  1. Python Flask 編寫一個介面同時實現新增和修改資料功能

  2. 建立抽屜控制元件,內嵌form,實現原型中的各控制元件繫結

  3. 控制元件紅色*標記的規則配置,觸發方式trigger: 'blur'即點選提交統一校驗,

  4. 頁面修改和新增使用同一個Drawer 標題根據上一步操作動態顯示 “應用新增” / “應用編輯”

  5. 應用編輯的自增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

堅持原創,堅持實踐,堅持乾貨,如果你覺得有用,請點選推薦,也歡迎關注我部落格園和微信公眾號。