测试开发【提测平台】分享13-远程搜索和路由$route使用实现新建提测需求
微信搜索【大奇测试开】,关注这个坚持分享测试开发干货的家伙。
本篇继续提测平台开发,按惯例先给出学习的思维导图,以便快速了解学习知识和平台功能实现的重点。
基本知识点学习
远程搜索
显示的数据通过输入关键词,从服务器搜索并返回,一般主要用于数据很多服务全部获取显示的,常用selected组件中,比如一个增改操作要指定一个公司的联系人场景,在element-vue 选择组件中主要是通过 :remote-method 调一个方法来实现的,而这个方式实现就是一个接口请求,即输入关键立马请求接口,接口根据关键字返回数据回填,说白了就是多次请求。
在Element Input组件中也有这个能力,是使用 :fetch-suggestions 场景是用于输入信息给填写建议。这个远程搜索功能在很多可组件上自己利用判断绑定的值的改变,调方法做相应的操作,这块具体可以参考后边功能开发例子。
vue中$router路由
在之前的页面功能如添加/修改的实现上都是通过抽屉或者弹对话框实现的,其实有些场景涉及到需要一个新的页面来实现,那么这个就要用到this.$router.push()来实现,基本一些使用方法如下:
1. 跳转页面对象 参数传的是菜单路由的定义的页面名称,比如我想点击某个按钮跳转到提测系统的app管理页面,在按钮出发点事件方法中使用
this.$router('apps')
// 或
this.$router({name: 'apps'}
2. 跳转通过路径 同样为菜单设置的path 相对应
this.$router.push({path: '/login});
3.带参数跳转
this.$router({name: 'app', params: { appId: 101 }})
// 上边是以params隐藏传递过去的,下边是在URL显式参数传的
this.$router.push({path: '/login?url=' + this.$route.path});
4. 跳转过来的新页获取传过来的值
// 获取通过params的参数
this.$route.params.appId
// 获取URL中的参数
this.$route.query.appId
5. 返回上一页
this.$router.go(-1)
以上这些是一些基本的vue router的用法,接着将在新建提测需求这个功能得到部分应用。
需求功能实现
按照之前的需求文档,由于提测需要提交的信息很多,所以通过点击新按钮会跳转到一个新的vue页面进行操作,先实现python后端的需求添加接口,之前的需求中写过好多类似的了,插入接口的代码直接上了。
提测添加接口
@test_manager.route("/api/test/create",methods=['POST'])
def createReqeust():
# 获取传递的数据,并转换成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'] = 'appId 提测应用不能为空'
return resp_failed
elif 'tester' not in body:
resp_failed['message'] = 'tester 测试人员不能为空'
return resp_failed
elif 'developer' not in body:
resp_failed['message'] = 'developer 提测人不能为空'
return resp_failed
elif 'title' not in body:
resp_failed['message'] = 'title提测标题不能为空'
return resp_failed # 使用连接池链接数据库
connection = pool.connection() # 判断增加或是修改逻辑
with connection:
try:
with connection.cursor() as cursor:
# 拼接插入语句,并用参数化%s构造防止基本的SQL注入
# 其中id为自增,插入数据默认数据设置的当前时间
sqlInsert = "INSERT INTO request (title,appId,developer,tester,CcMail,verison,`type`,scope,gitCode,wiki,`more`,`status`,createUser,updateUser) " \
"VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
cursor.execute(sqlInsert, (
body["title"], body["appId"], body["developer"], body["tester"], body["CcMail"], body["version"],
body['type'],
body["scope"], body["gitCode"], body["wiki"], body["more"], '1', body["createUser"],
body["updateUser"]))
# 提交执行保存新增数据
id = cursor.lastrowid
connection.commit() return resp_success
except Exception as err:
resp_failed['message'] = '提测失败了:' + err
return resp_failed
然后重新启动下服务,来做个接口测试,看插入有没有问题,接下来需要重点看下是这部分代码逻辑,关于如果用户勾选了发邮件,则在需要提交数据进行邮件发送,这就用到之前讲解到的邮件工具那边文章了,如果还没练习的可以先看下 学习Python邮件发送方法&落地有邮件工具类-测试开发【提测平台】分享11 ,实现就在commit()后进行逻辑判断,并且特别注意的是之前还预留个是否发送成功的字段,也就是还需要判断邮件是否发送成功了,再对插入的数据立马进行一次更新操作。
if body['isEmail'] == 'true':
# 新建成功发送Email
if body['type'] == '1':
version = '功能测试'
elif body['type'] == '2':
version = '性能测试'
elif body['type'] == '3':
version = '安全测试' receivers = body["tester"].split(',') + body["developer"].split(',')
if not body["CcMail"] is None:
receivers = receivers + body["CcMail"].split(',') subject = '【提测】' + body['title']
reuslt = sendEmail(receivers, subject, [
'<strong>[提测应用]</strong>',
body['appName'],
'<strong>[提测人]</strong>',
body['developer'],
'<strong>[提测版本]</strong>',
body['version'],
'<strong>[提测类型]</strong>',
version,
'<strong>[测试内容]</strong>',
body['scope'],
'<strong>[相关文档]</strong>',
body['wiki'],
'<strong>[补充信息]</strong>',
body['more']
])
if reuslt:
sendOk = 1
else:
sendOk = 2
with connection.cursor() as cursor:
# 更新Emai是否发送成功1-成功 2-失败
updateEmail = "UPDATE request SET sendEmail=%s, updateUser=%s,`updateDate`= NOW() WHERE id=%s"
cursor.execute(updateEmail, (sendOk, body["updateUser"], id))
# 提交修改邮件是否发送成功
connection.commit()
else:
print('不发送邮件!')
两代码合并后再次运行进行下测试,这里其实是有个性能问题,因为是阻塞需要等待邮件的结果,所以接口的相应会有些慢,大家可以理由异步调用进行优化的,查查资料看怎么实现,体现学习能力的时候到了。
远程应用搜索接口
还有一个接口,在这里一并先实现了,就是需要为应用的远程搜索单独写个按照条件查询接口,此接口有个和之前条件查询特别的需求,是需要同时支持appid或者描述的任意条件的查询,具体实现请看代码(application.py):
@app_application.route("/api/application/options", methods=['GET'])
def getOptionsForSelected(): value = request.args.get('value', '')
response = format.resp_format_success connection = pool.connection() with connection.cursor() as cursor: # 先按appid模糊搜索,没有数据再按note搜索
sqlByAppId = "SELECT * FROM apps WHERE appId LIKE '%"+value+"%'"
cursor.execute(sqlByAppId)
dataByppId = cursor.fetchall()
if len(dataByppId) > 0 :
response['data'] = dataByppId
else:
sqlByNote = "SELECT * FROM apps WHERE note LIKE '%" + value + "%'"
cursor.execute(sqlByNote)
dataByNote = cursor.fetchall()
response['data'] = dataByNote return response
一个笨方法就先默认按照appId查询,没有再按照note条件查询,如果你有更好的实践方法,欢迎提交流,启动服务对接口进行测试(永远不要忘了测试)
到此后端的内容就这些,完整的代码在新的接口文件 testmanager.py 可以在github对照查看。
前端提测需求新建实现
自实现步骤步骤为
1)实现上次的添加按钮功能,利用 this.$router.push 实现
2)跳转的时候需要带个动作标记参数,主要为了区分是添加操作还,后续实现的修改操作
3)自行在element ui官方查询 “header页头” 的组件的使用,并实现 <- 按钮的点击跳回上一页面
4)按照产品原型实现form表单各项控件
5)应用下拉框实现远程关键词搜索,并且还要实现在选择对应的应用后,需要应用配置的时候一些默认信息,反填到其他相关的输入框中
6)实现添加和取消按钮的逻辑功能
7)添加成功后跳回列表并让列表列感知刷新最新数据
下边是我的实现参考
1. 新建按钮跳转
创建一个空的提测页面,叫commit.vue,并设置好个不显示的在菜单上的路由,配置好path和name以及跳转地址
{
path: 'commit',
name: 'commit',
hidden: true,
component: () => import('@/views/test/manger/commit'),
meta: { title: '需求提测', icon: 'dashboard' }
},
然后就是编写提测列表页面的新建按钮的点击触发方法逻辑
doCommit() {
this.$router.push({ name: 'commit', params: { action: 'ADD' }})
},
2. 实现提测form表单
这里是个全新的页面,我就不再分解了,直接给出上边3-6的实现代码,必要的注解都已经代码了,可以参照对比自己的实现代码,如果部分不是很完成,还是去下载最新的代码去查看
Template模块代码
重点关注selected远程搜索的处理方法和Header组件的如何使用
<template>
<div class="app-container">
<el-header>
<el-page-header @back="goBack" content="提测"/>
</el-header>
<el-main>
<el-form :model="requestForm" :rules="requestRules" ref="ruleForm" label-width="100px" >
<el-form-item label="提测标题" prop="title">
<el-input v-model="requestForm.title" placeholder="提测标题" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="服务应用" prop="appId">
<el-select
v-model="requestForm.appId"
filterable
remote
reserve-keyword
placeholder="请输入关键词(远程搜索)"
:remote-method="remoteMethod"
:loading="appIdloading"
@change="appSelected"
style="width: 300px">
<el-option
v-for="item in appIdList"
:key="item.id"
:label="item.appId"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="提测RD" prop="developer">
<el-input v-model="requestForm.developer" placeholder="提测人研发" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="测试QA" prop="tester">
<el-input v-model="requestForm.tester" placeholder="测试人" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="关系人" prop="CcMail">
<el-input v-model="requestForm.CcMail" placeholder="邮件抄送人" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="提测版本" prop="version">
<el-input v-model="requestForm.version" placeholder="部署版本号/分支/Tag" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="提测类型" prop="type">
<el-select v-model="requestForm.type" clearable placeholder="请选择..." style="width: 300px">
<el-option
v-for="item in opsType"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="测试范围" prop="scope">
<el-input v-model="requestForm.scope" type="textarea" :rows="3" placeholder="1.功能点 \n 2.测试点 \n 3.回归点" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="代码地址" prop="gitCode">
<el-input v-model="requestForm.gitCode" placeholder="git代码地址" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="产品文档" prop="wiki">
<el-input v-model="requestForm.wiki" placeholder="文档说明地址" style="width: 350px"></el-input>
</el-form-item>
<el-form-item label="更多信息" prop="more">
<el-input v-model="requestForm.more" type="textarea" :rows="3" placeholder="其他补充信息" style="width: 350px"></el-input>
</el-form-item>
<el-form-item>
<el-checkbox v-model="requestForm.isEmail" true-label="true">发送邮件</el-checkbox>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
<el-button @click="onCancel">取 消</el-button>
</el-form-item>
</el-form>
</el-main>
</div>
</template>
Javacript模块代码
这部分代码逻辑中重点关注
1)mounted 页面初始化时候获取上级页面的传参值;
2)表单规则名称增加一个字符多少的校验;
3)选择应用后数据的反填特殊处理,即如果用户已经手写改过之后,就不能将其覆盖填写其默认值
4)头返回和取消返回分别使用两种方法
5)提交添加成功后也有个跳转到列表的处理,列表需要同样用判断是否有回传的方式,处理是否需要立即刷新最新列表数据
<script>
import { apiAppsIds } from '@/api/apps'
import { reqCreate } from '@/api/test'
import store from '@/store' export default {
name: 'Commit',
data() {
return {
op_user: store.getters.name,
testAction: '',
appIdloading: false,
requestForm: {
id: undefined,
title: '',
appId: '',
appName: '',
developer: '',
tester: '',
CcMail: '',
version: '',
type: '',
scope: '',
gitCode: '',
wiki: '',
more: '',
isEmail: 'true',
createUser: '',
updateUser: ''
},
requestRules: {
title: [
{ required: true, message: '请输入活动名称', trigger: 'blur' },
{ min: 3, message: '长度在大于3个字符', trigger: 'blur' }
],
appId: [
{ required: true, message: '请选择对应的服务应用', trigger: 'change' }
],
developer: [
{ required: true, message: '请填写提测人RD', trigger: 'change' }
],
tester: [
{ required: true, message: '请填写对应的测试人Tester', trigger: 'change' }
] },
opsType: [
{ label: '功能测试', value: '1' },
{ label: '性能测试', value: '2' },
{ label: '安全测试', value: '3' }
],
appIdList: []
}
},
mounted() {
if (this.$route.params.action) {
this.testAction = this.$route.params.action
}
},
methods: {
goBack() {
this.$router.go(-1)
},
remoteMethod(query) {
if (query !== '') {
this.appIdloading = true
setTimeout(() => {
apiAppsIds(query).then(resp => {
this.appIdList = resp.data
})
this.appIdloading = false
}, 200)
} else {
this.appIdList = []
}
},
appSelected() {
// 判断获取选择应用的其他信息
for (var it in this.appIdList) {
if (this.appIdList[it].id === this.requestForm.appId) {
// 以下判断为在字符为空的情况下添加,即认为没有人工再输入,快捷反填已知道信息
if (!this.requestForm.developer) {
this.requestForm.developer = this.appIdList[it].developer
}
if (!this.requestForm.tester) {
this.requestForm.tester = this.appIdList[it].tester
}
if (!this.requestForm.CcMail) {
this.requestForm.CcMail = this.appIdList[it].CcEmail
}
if (!this.requestForm.wiki) {
this.requestForm.wiki = this.appIdList[it].wiki
}
if (!this.requestForm.gitCode) {
this.requestForm.gitCode = this.appIdList[it].gitCode
}
// 填写appName信息,用于邮件发送不再额外查询
this.requestForm.appName = this.appIdList[it].appId
}
}
},
onSubmit() {
this.$refs['ruleForm'].validate((valid) => {
if (valid) {
if (this.testAction === 'ADD') {
this.requestForm.id = undefined
this.requestForm.type = '1'
this.requestForm.createUser = this.op_user
this.requestForm.updateUser = this.op_user
reqCreate(this.requestForm).then(response => {
// 如果request.js没有拦截即表示成功,给出对应提示和操作
this.$notify({
title: '成功',
message: this.testAction === 'ADD' ? '提测添加成功' : '提测修改成功',
type: 'success'
})
// 回到列表页面
this.$router.push({ name: 'test', params: { needUp: 'true' }})
})
}
} else {
return false
}
})
},
onCancel() {
this.$router.push('test')
}
}
}
</script>
3. 提测列表叶刷新代码
即需要对页面判断是否是有对应的回调参数,是否需要刷新,如果有则调用查询方法刷新最新数据。
mounted() {
if (this.$route.params.needUp && this.$route.params.needUp.needUp === 'true') {
this.searchClick()
}
},
【代码更新】
地址:https://github.com/mrzcode/TestProjectManagement
TAG:TPMShare13
坚持原创,坚持实践,坚持干货,如果你觉得有用,请点击推荐,也欢迎关注我博客园和微信公众号。
测试开发【提测平台】分享13-远程搜索和路由$route使用实现新建提测需求的更多相关文章
- 测试开发【提测平台】分享12-掌握日期组件&列表状态格式化最终实现提测管理多条件搜索展示功能
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 本章内容思维导图如下,由于需要各种状态下的菜单操作,所以需要先实现提测信息的列表基础页面,然后再推进其他需求开发 基本知识点学习 Date ...
- 测试开发【提测平台】分享9-DBUntils优化数据连接&实现应用搜索和分页功能
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 从本期开始知识点讲以思维导图的形式给出,内容点会按照讲解-应用-展示的形式体现,这样会更清晰些. DBUntils连接池 在项目中链接数据 ...
- 测试开发【提测平台】分享14-Vue图标Icon几种用法并利用其一优化菜单
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 回归主线更新,由于本次知识点只有一个,就不给思维导图了,在上系列测试平台开发实践中主要学习了页面直接的转跳方法和远程搜索的如何做,最终实现 ...
- 测试开发【提测平台】分享11-Python实现邮件发送的两种方法实践
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 按照开发安排,本篇本应该是关于提测页面的搜索和显示实现,怕相似内容疲劳,这期改下内容顺序,将邮件服务的相关的提前,在之前的产品需求和原型中 ...
- 测试开发【提测平台】分享3-正式开发产品需求&项目初始化
上两个分享主要是介绍和演示基本前后端所要使用的框架,接下来我们将正式进入到[提测平台的开发] 提要先给出依赖和内容点: 提测平台定义和产品原型需求说明 使用github创建代码仓库进行项目管理 Fla ...
- 测试开发【提测平台】分享10-Element UI抽屉和表单校验&增改接口合并实现应用管理
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 开篇说个小讨论,一个群里聊天聊到关于更新篇章的长度,是小篇幅多次,还是每次按照一个小完整的功能,我个人的是按照后种来的,主要的思考就是希望 ...
- Python Flask API实现方法-测试开发【提测平台】阶段小结(一)
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 本篇主要是对之前几次分享的阶阶段的总结,温故而知新,况且虽然看起来是一个小模块简单的增删改查操作,但其实涉及的内容点是非常的密集的,是非常 ...
- Element Vue 开箱即用框架如何使用-测试开发【提测平台】阶段小结(二)
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 上一篇总结了后端服务接口的开发,这篇我们主要来总结下前后端分离开发中的前端部分,主要是开箱即用的框架介绍和之前章节组件的梳理和部分的扩展内 ...
- 测试开发实战[提测平台]19-Echarts图表在项目的应用
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 在图表统计展示方面,笔者目前使用过的两种开源,分别是 Echats 和 G2Plot 组件,从个人使用上来讲前者应用更广.自定义开发更灵活 ...
随机推荐
- 深入学习Composer原理(一)
Composer作为PHP的包管理工具,为PHPer们提供了丰富的类库,并且让PHP重焕新生,避免被时代淘汰的悲剧.可以说,Composer和PHP7是现在PHP开发者的标配,如果你还没用过Compo ...
- Jmeter系列(19)- 常用配置文件
JMeter.properties :跟Jmeter配置相关的配置信息都在这边,比如:Jmeter GUI页面的语言.日志级别设置等 User.properties:用户自定义相关的所有变量,会复写J ...
- 写SQL的套路
定义问题 转化问题 如要解决的问题是:查出每门课程成绩都大于80分学生的姓名,可以转化为:只要学生最小分数的课程大于80分,就是所有课程成绩都大于80分. 查询同名同姓学生名单并统计同名人数--> ...
- MySQL修改root密码的多种方法, mysql 导出数据库(包含视图)
方法1: 用SET PASSWORD命令 mysql -u root mysql> SET PASSWORD FOR 'root'@'localhost' = PASSWORD('newpass ...
- centos7安装部署SVN
SVN介绍 SVN是个自由.开源的版本控制系统,绝大多数开源软件都使用SVN作为代码版本管理软件. SVN的官方网站http://subversion.apache.org/.目前SVN在开源社区 ...
- Ajax与Gson
1. ajax的底层操作方法: 代码get请求 Get请求 2. Post请求 $("#chufa").click(function () { var val = $(" ...
- 详细的vsftpd配置
环境:CentOS 5.0 操作系统一.安装:1.安装Vsftpd服务相关部件:[root@KcentOS5 ~]# yum install vsftpd*Dependencies Resolved= ...
- P4245-[模板]任意模数多项式乘法
正题 题目链接:https://www.luogu.com.cn/problem/P4245 题目大意 两个多项式,求它们的乘积模\(p\). 解题思路 方法好像挺多,我用的是最简单的一种就是,先定一 ...
- AT4996-[AGC034F]RNG and XOR【FWT,生成函数】
正题 题目链接:https://www.luogu.com.cn/problem/AT4996 题目大意 给出一个\(0\sim 2^n-1\)下标的数组\(p\),\(p_i\)表示有\(p_i\) ...
- ASP.NET Core 学习笔记 第二篇 依赖注入
前言 ASP.NET Core 应用在启动过程中会依赖各种组件提供服务,而这些组件会以接口的形式标准化,这些组件这就是我们所说的服务,ASP.NET Core框架建立在一个底层的依赖注入框架之上,它使 ...