微信搜索【大奇测试开】,关注这个坚持分享测试开发干货的家伙。javascript
学习建议仍是要多动手作,用一首歌的时间看,用半小时去实际实现,才能事半功倍!css
本篇掌握功能点:html
- 后端python实现数据库更新逻辑接口
- 前端<el-link>文字连接组件实现表菜单操做
- 前端slot-scope插件槽获取Table的行数据
- 前端控件v-if 和:实现动态判断
- 后端删除软和硬两种实现方法
- 前端掌握$confirm执行前的确认组件
更新接口实现能够直接参考上节的添加操做,只是将数据库insert变成根据id条件update操做,更新的时候也须要进行重复的校验,代码以下前端
# [POST方法]实现新建数据的数据库插入 @app_product.route("/api/product/update",methods=['POST']) def product_update(): # 按返回模版格式进行json结果返回 resp_data = { "code": 20000, "message": "success", "data": [] } # 获取请求传递json body = request.get_data() body = json.loads(body) # 初始化数据库连接 connection = connectDB() with connection: with connection.cursor() as cursor: select = "SELECT * FROM `products` WHERE `keyCode`=%s" cursor.execute(select, (body["keyCode"],)) result = cursor.fetchall() # 有数据而且不等于自己则为重复,封装提示直接返回 if len(result) > 0 and result[0]["id"] != body["id"]: resp_data["code"] = 20001 resp_data["message"] = "惟一编码keyCode已存在" return resp_data # 若是没有重复,定义新的连接,进行更新操做 with connection.cursor() as cursor: # 拼接更新语句,并用参数化%s构造防止基本的SQL注入 # 条件为id,更新时间用数据库NOW()获取当前时间 sql = "UPDATE `products` SET `keyCode`=%s, `title`=%s,`desc`=%s,`operator`=%s, `update`= NOW() WHERE id=%s" cursor.execute(sql, (body["keyCode"], body["title"], body["desc"], body["operator"], body['id'])) # 提交执行保存更新数据 connection.commit() return resp_data
优化对话框表单 修改操做的页面因为以前添加的时候都进行过el-dialog绑定,这的修改对话框能够共用的,只须要定义个状态变量,而后标题经过对属性前加:冒号,以及组件的显示和隐藏经过组件中使用v-if进行判断显示和隐藏,这两种的做用跟语法的if 是一个道理;vue
: 是vue中v-bind的语法糖缩写,做用可使标签动态绑定java
v-if 是判断语句,它还能够和v-else-if ,v-else 配合使用python
须要修改的点nginx
表格中操做菜单 表格控件中增长一列,列里增长一个编辑按钮,使用组件 Link 文字连接,并带个icongit
基本语法:<el-link icon="el-icon-edit"></el-link>github
另外咱们在修改操做的时候是对本行进行操做的,要想获取本行的数据,并透传给调用方法,须要使用vue里一个叫插件槽的东西
基本语法:<template slot-scope="scope"></template>
几个要掌握的关键点已经大体说完,剩下我直接给api和方法的代码
product.js 增长更新请求接口
export function apiProductUpdate(requestBody) { return request({ url: '/api/product/update', method: 'post', data: requestBody }) }
product.vue中js 增长方法引用和状态变量
// <script>...</script> 头部追加 import { apiProductList, apiProductCreate, apiProductUpdate } from '@/api/product' // data() { return {...} } 内添加 dialogProductStatus: 'ADD',
methods:{中实现dialogProductUpdate()}
// 获取当前编辑行数数据并赋值给product dialogProductUpdate(row) { // 添加先初始化空状态 this.product.id = row.id this.product.keyCode = row.keyCode this.product.title = row.title this.product.desc = row.desc this.product.operator = this.op_user // 标记弹窗是修改操做 this.dialogProductStatus = 'UPDATE' // 弹出对话框设置为true this.dialogProductShow = true },
methods:{ 实现 pUpdate() }
pUpdate() { apiProductUpdate(this.product).then(res => { this.$notify({ title: '成功', message: '项目或产品修改为功', type: 'success' }) // 关闭对话框 this.dialogProductShow = false // 从新查询刷新数据显示 this.getProductList() }) }
先后端从新启动,运行查看效果以下:
须要进行一下简单的测试:
CASE1: 修更名称和备注 - 验证保存成功
CASE2: 修改惟一编号其余项目存在 - 验证提示已经存在不保存
按照标准的RefAPI,经过定义methods = delete方法定义请求接口,参数只须要对应数据的id便可,这里并增长一个请求是否传了id的参数校验,这个接口是真正的数据删除,即所谓的硬删除,这个实现当中额外增长一个参数校验的逻辑,具体的实现代码以下:
# [DELETE方法]根据id实际删除项目信息 @app_product.route("/api/product/delete", methods=['DELETE']) def product_delete(): # 返回的reponse resp_data = { "code": 20000, "message": "success", "data": [] } # 方式1:经过params 获取id ID = request.args.get('id') # 作个参数必填校验 if ID is None: resp_data["code"] = 20002 resp_data["message"] = "请求id参数为空" return resp_data # 从新连接数据库 connection = connectDB() with connection.cursor() as cursor: sql = "DELETE from `products` where id=%s" cursor.execute(sql, ID) connection.commit() return resp_data
其实一个好的后端接口是须要增长各类校验的,保证代码的健壮性,能够每一个方法本身写,也能够采用统一的异常处理形式。
2.前端实现删除功能
按照以前修改,咱们在产品项目管理的菜单处增长一个删除的el-link并给定一个待实现的方法 pHardRemove(),其中scope.row.id表所在行数据的ID值
<el-link icon="el-icon-delete" @click="pHardRemove(scope.row.id)">删除</el-link>
接着继续按照规定模式js实现接口请求定义,vue删除方引用和实现
src/api/product.js 增长代码
// 调用真实删除数据库接口 export function apiProductDelete(id) { return request({ url: '/api/product/delete', method: 'delete', params: { 'id': id } }) }
在 src/view/product/product.vue 的methods{ 实现pHarRemove }
最早不要忘记接口方法引用
import { apiProductDelete } from '@/api/product'
在这里的删除逻辑里通常要给个二次确认是否进行操做,使用的是组件 MessageBox 弹框 中 确认消息 功能是提示用户确认其已经触发的动做,并询问是否进行此操做,确认继续执行或者取消此操做,调用的是$confirm
对应可设置type
字段代表消息类型,能够为 success
,error
,info
和 warning
更多定制属性可直接参考官方,详细代码和说明以下(methods):
pHardRemove(id) { // 对应的参数是 (提示内容,标题 {自定义肯定按钮文案,自定义取消按钮文案, 对话框类型} this.$confirm('此操做将永久删除该项目, 是否继续?', '提示', { confirmButtonText: '肯定', cancelButtonText: '取消', type: 'warning' // then 点击confirmButton后执行的方法,不然是不执行关闭对话框 }).then(() => { // vue click时候传d的id须要定义参数 apiProductDelete(id).then(res => { this.$message({ type: 'success', message: '删除成功!' }) // 从新查询刷新数据显示 this.getProductList() }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }) }) }
后端IDE运行或者运行命令 # TPMServer路径下
$ python3 app.py
前端IDE运营或者运行命令 # TPMWeb 路径下
$ npm run dev
点击"删除"后的界面以下
进行用例测试
CASE1 : 选择任意行点删除,对话框选择取消,验证取消成功数据未删除
CASE2: 添加一行数据,再选择删除-肯定,验证查看新增的数据已删除 ,同步需确认数据库表中是否真删除
在一般的业务操做中数据都不是真的删除的,尤为像产品/项目这种会有下游依赖的数据,通常作法都是表数据增长对应的状态字段,用数字或者字符表示状态,所须要作的操做就是“删除”触发的是更新操做,这里咱们叫“停用”更为合适一些,这也就是所谓的软删除,仅标记状态不作实际数据删除。
须要对TPMStore数据中products表增长字段status,其中默认数字 0 为有效数据,数字 1 为已停用数据
alter table products add status int default 0 not null comment '状态有效0,无效0' after `desc`;优化查询接口
参考产品修改接口实现对应的以下代码,注意同上边同样,须要增长个参数校验逻辑
# [POST方法]根据id更新状态项目状态,作软删除 @app_product.route("/api/product/remove", methods=['POST']) def product_remove(): # 返回的reponse resp_data = { "code": 20000, "message": "success", "data": [] } ID = request.args.get('id') # 作个参数必填校验 if ID is None: resp_data["code"] = 20002 resp_data["message"] = "请求id参数为空" return resp_data # 从新连接数据库 connection = connectDB() with connection.cursor() as cursor: # 状态默认正常状态为0,删除状态为1 # alter table products add status int default 0 not null comment '状态有效0,无效0' after `desc`; sql = "UPDATE `products` SET `status`=1 WHERE id=%s" cursor.execute(sql, ID) connection.commit() return resp_data
因为表增长了一个标记状态字段,其余的已实现的接口咱们须要作下优化处理,其中 查询接口须要修改查询语句增长条件过滤 status = 0 即只返回有效的数据
# 查询产品信息表-按更新时间新旧排序 且 状态为0有效 sql = "SELECT * FROM `products` WHERE `status`=0 ORDER BY `update` DESC"
在新增product_create和更新接口方法 product_update() 中的 查重语句增长状态条件有效,即已停用的keycode不该该算做重复(这里前提业务需求是停用不可恢复)
# 查询须要过滤状态为有效的 且 状态为0有效 select = "SELECT * FROM `products` WHERE `keyCode`=%s AND `status`=0"
页面参考上边的流程和编码,分别是增长新的 el-link 动做按钮、接口请求定义、vue实现删除,这里不在多赘述,稍做改动,代码以下:
product.js部分
// 软删除,更改数据状态 export function apiProductRemove(id) { return request({ url: '/api/product/remove', method: 'post', params: { 'id': id } }) }
product.vue <template> 部分
<el-link icon="el-icon-delete" @click="pSoftRemove(scope.row.id)">停用</el-link>
product.vue js部分
import { apiProductRemove } from '@/api/product'
pSoftRemove(id) { this.$confirm('此操做将停用不显示, 是否继续?', '提示', { confirmButtonText: '肯定', cancelButtonText: '取消', type: 'warning' }).then(() => { apiProductRemove(id).then(res => { this.$message({ type: 'success', message: '删除成功!' }) // 从新查询刷新数据显示 this.getProductList() }) }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }) }) }
从新运行先后端,即可看到最终实现界面
一样写完程序要进行必要测试
CASE1 : 选择任意行点停用,对话框选择取消,验证取消成功数据未删除
CASE2: 选择任意数据删除-肯定,验证页面刷新正常和删除数据不显示 ,同步需确认数据库表中数据并未删除,只是标记status为1
CASE3: 新增和修改的填写已删除数据的keyCode,验证添加和更新正常
【代码更新】
地址:https://github.com/mrzcode/TestProjectManagement
TAG:TPMShare6
【官方文档参考】
【系列前要阅读】
原创不易,通过实践的总结分享更不易,若是你以为有用,请点击推荐,也欢迎关注我博客园和微信公众号。