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

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

本篇内容思维导

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

知识点学习

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

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

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

  1. vue2.0+Element UI 实现动态表单(点击按钮增删一排输入框)

    对于动态增减表单项,Element UI 官方文档表单那一节已经介绍得很清楚了,我之前没有看见,绕了很多弯路,这里针对点击按钮增删一排输入框的问题做一个总结. 效果图如下 存在一排必填的姓名与手机号, ...

  2. Element ui 中的表单提交按钮多次点击bug修复

  3. vue 使用 element ui动态添加表单

    html部分 <div class="hello"> <el-form :model="dynamicValidateForm" ref=&q ...

  4. 2019第一期《python测试开发》课程,10月13号开学

    2019第一期<python测试开发>课程,10月13号开学! 主讲老师:上海-悠悠 上课方式:QQ群视频在线教学,方便交流 本期上课时间:10月13号-12月8号,每周六.周日晚上20: ...

  5. 10个强大的Javascript表单验证插件推荐

    创建一个JavaScript表单验证插件,可以说是一个繁琐的过程,涉及到初期设计.开发与测试等等环节.实际上一个优秀的程序员不仅是技术高手,也应该是善假于外物的.本文介绍了10个不错的JavaScri ...

  6. 利用jquery.validate以及bootstrap的tooltip开发气泡式的表单校验组件

    表单校验是页面开发中非常常见的一类需求,相信每个前端开发人员都有这方面的经验.网上有很多成熟的表单校验框架,虽然按照它们默认的设计,用起来没有多大的问题,但是在实际工作中,表单校验有可能有比较复杂的个 ...

  7. vue+element表单校验功能

    要实现这个功能其实并不难,element组件直接用就可以, 但是我在使用过程中碰到了几个坑,就记录下来,分享给大家,避免落坑,话不多说,直接上过程...... 表单校验功能:   实现这个功能,总共分 ...

  8. js--吐血总结最近遇到的变态表单校验---element+原生+jq+easyUI(前端职业生涯见过的最烦的校验)

    最近写了无数各种形式的表单,记录下奇奇怪怪的校验规则~ 一:首先是element自带的rules校验规则: element作为常用框架,自带rules属性简单易懂,官方文档一目了然,不再赘述,应付常用 ...

  9. 10款精美的HTML5表单登录联系和搜索表单

    1.HTML5/CSS3仿Facebook登录表单 这款纯CSS3发光登录表单更是绚丽多彩.今天我们要分享一款仿Facebook的登录表单,无论从外观还是功能上说,这款登录表单还是挺接近Faceboo ...

随机推荐

  1. gRPC学习之三:初试GO版gRPC开发

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  2. Use Emacs as Personal Knowledge Base

    http://stackoverflow.com/questions/2014636/how-to-maintain-an-emacs-based-knowledge-base

  3. linux c语言学习笔记之守护进程

    哈尔滨理工大学软件工程专业08-7李万鹏原创作品,转载请标明出处 http://blog.csdn.net/woshixingaaa/archive/2010/06/06/5651095.aspx 守 ...

  4. Linux线程同步之读写锁(rwlock)

    读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 和 ...

  5. View epub and mobi File on Linux

    Calibre has stand-alone ebook viewer "ebook-viewer", start it in terminal: $ ebook-viewer ...

  6. Python对系统数据进行采集监控——psutil

    大家好,我是辰哥- 今天给大家介绍一个可以获取当前系统信息的库--psutil 利用psutil库可以获取系统的一些信息,如cpu,内存等使用率,从而可以查看当前系统的使用情况,实时采集这些信息可以达 ...

  7. XSS挑战20关

    第一关: 没有过滤,直接构造payload过关: http://127.0.0.1/xssgame/level1.php?name=test%3Cscript%3Ealert%28111%29%3C/ ...

  8. Django 模版语法 测试环境 ORM单表查询

    模版语法 传值 视图函数向前端html页面传值,基本上所有的数据类型都可以渲染在前端页面上. views.py from django.shortcuts import render, redirec ...

  9. 使用DOM方法来遍历一个文档

    问题 你有一个HTML文档要从中提取数据,并了解这个HTML文档的结构. 方法 将HTML解析成一个Document之后,就可以使用类似于DOM的方法进行操作.示例代码: File input = n ...

  10. 如何在 Go 中嵌入 Python

    如果你看一下 新的 Datadog Agent,你可能会注意到大部分代码库是用 Go 编写的,尽管我们用来收集指标的检查仍然是用 Python 编写的.这大概是因为 Datadog Agent 是一个 ...