AI智能
改变未来

测试开发【提测平台】分享10-Element UI抽屉和表单校验&增改接口合并实现应用管理

微信搜索【大奇测试开】,关注这个坚持分享测试开发干货的家伙。

开篇说个小讨论,一个群里聊天聊到关于更新篇章的长度,是小篇幅多次,还是每次按照一个小完整的功能,我个人的是按照后种来的,主要的思考就是希望集中的时间段去实践,这样效率高且有每次会有一个小小的成就感,另一种当然有它的好处,更能持续输出,看的内容少,且很有助于阅读量。因此做个个小小的互动,欢迎留言,看看大家的想法~

本篇内容思维导

服务应用管理,主要是前端的知识点,学习一种新的前端控件作为新增修改基层页,再重点掌握下表单数据提交的时候校验,这里不限于非空、格式等。对于后端的没有新增的知识点,可以参照项目产品分类管理的代码分别写新增和修改两个接口,也可按照这次我将两个接口合并成一个接口,其实就是之前有一章节留过的一个思考题“如何实现两个接口的合并”不知道还有没印象,总之本篇内容不是很多,加油~

知识点学习

Drawer 抽屉

之前产品修改和添加是使用Dialog组件实现的,但这个组件有时候并不满足我们的需求, 比如表单很长, 亦或是你需要临时展示一些文档, Drawer 是可以从侧面弹出的一个层,可以容纳更多的控件,优化交互体验。基本用法

<el-drawertitle=\"我是从右到左侧展示的抽屉\":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():# 获取传递的数据,并转换成JSONbody = request.get_data()body = json.loads(body)# 定义默认返回体resp_success = format.resp_format_successresp_failed = format.resp_format_failed# 判断必填参数if \'appId\' not in body:resp_failed.message = \'应用不能为空\'return resp_failedelif \'tester\' not in body:resp_failed.message = \'测试负责人不能为空\'return resp_failedelif \'developer\' not in body:resp_failed.message = \'测试负责人不能为空\'return resp_failedelif \'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:# 拼接修改语句,由于应用名不可修改,不需要做重复校验appIdsql = \"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\"] = 20001resp_failed[\"message\"] = \"唯一编码keyCode已存在\"return resp_failedwith 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-optionv-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_userthis.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.idthis.appInfo.appId = row.appIdthis.appInfo.productId = row.productIdthis.appInfo.note = row.notethis.appInfo.tester = row.testerthis.appInfo.developer = row.developerthis.appInfo.producer = row.producerthis.appInfo.cCEmail = row.cCEmailthis.appInfo.gitCode = row.gitCodethis.appInfo.wiki = row.wikithis.appInfo.more = row.morethis.appInfo.creteUser = \'\'this.appInfo.updateUser = row.updateUser},commitApp() {      // 上边form定义ref,验证通过if valid的方式判断this.$refs[\'appInfo\'].validate((valid) => {if (valid) {this.appInfo.updateUser = this.op_userapiAppsCommit(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

坚持原创,坚持实践,坚持干货,如果你觉得有用,请点击推荐,也欢迎关注我博客园和微信公众号。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 测试开发【提测平台】分享10-Element UI抽屉和表单校验&增改接口合并实现应用管理