文章目录
这两节的内容是开发商品分类的删除功能。
一,50-商品服务-API-三级分类-删除-逻辑删除
前端已经开发了删除按钮,后端要有对应的接口实现。
1,逻辑删除的配置
在工作中,所有的删除都应该是逻辑删除,不能用物理硬删除。
mybatis-plus支持逻辑删除的配置,配置步骤如下:
- ①配置全局的逻辑删除规则(可省略)
- ②配置逻辑删除Bean(可省略)
- ③Bean相应字段上加上注解@TableLogic
1.1 配置全局的逻辑删除规则(可省略)
mybatis-plus:
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
logic-delete-value: 1
这个配置项定义了当一个记录被逻辑删除时,其逻辑删除字段(通常是一个布尔型或整型字段)的值应该是多少。在这个例子中,如果一个记录的逻辑删除字段值为1,那么框架认为这个记录是被逻辑删除的。
logic-not-delete-value: 0
这个配置项定义了当一个记录未被逻辑删除时,其逻辑删除字段的值应该是多少。在这个例子中,如果一个记录的逻辑删除字段值为0,那么框架认为这个记录是有效的,没有被逻辑删除。
1.2 配置逻辑删除Bean(可省略)
在mybatis-plus3.1.1版本后,无需此步骤,我用的3.2,所以这步可以省略。
1.3 Bean相应字段上加上注解@TableLogic
商品分类表中用showStatus字段表示记录是否逻辑删除。
所以在对应的实体类CategoryEntity.java中showStatus字段上加上注解。
这里需要说明的是,如果表示逻辑删除的值和全局配置不一致,可以在注解上单独配置。
比如全局配置中1表示已删除
,而三级分类表1表示未删除
,产生了冲突,解决冲突的办法就是在注解上通过val和delVal
字段进行设置。
2,后台接口开发
2.1,Controller类中修改接口
@RequestMapping("/delete")
public R delete(@RequestBody Long[] catIds){
// categoryService.removeByIds(Arrays.asList(catIds));
categoryService.removeMenuByIds(Arrays.asList(catIds));
return R.ok();
}
removeMenuByIds是新实现的方法,逆向工程生成的方法removeByIds
缺少必要的校验,我们不用这个方法。
2.2,CategoryServiceImpl类中增加接口
@Override
public void removeMenuByIds(List<Long> ids) {
baseMapper.deleteBatchIds(ids);
}
2.3,postman验证
重启product服务,在postman中通过网关调用删除接口。
二,51-商品服务-API-三级分类-删除-删除效果细化
1,前端调用delete接口
在category.vue
模块中,remove
方法如下。
remove(node, data) {
var ids = [node.catId];
this.$confirm(
`确定对[id=${ids.join(",")}]进行[${id ? "删除" : "批量删除"}]操作?`,
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(ids, false),
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success",
duration: 1500,
onClose: () => {
console.log("删除成功,关闭消息提示");
this.getMenus();
},
});
} else {
this.$message.error(data.msg);
}
});
})
.catch(() => {});
},
在删除前弹窗提示是否确认删除,确认后,调用接口,把要删除的分类Id传递给后端,后端软删除对应分类记录。
2,模板代码配置
后续会频繁使用httpget和httppost请求,为了提高效率,可以配置到模板中。
"http-get 请求": {
"prefix": "httpget",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'get',",
"params: this.\\$http.adornParams({})",
"}).then(({data}) => {",
"})"
],
"description": "httpGET 请求"
},
"http-post 请求": {
"prefix": "httppost",
"body": [
"this.\\$http({",
"url: this.\\$http.adornUrl(''),",
"method: 'post',",
"data: this.\\$http.adornData(data, false)",
"}).then(({ data }) => { });"
],
"description": "httpPOST 请求"
}
这样只要输入httppost
和httpget
,vscode
就可以给出提示,确认后就可以自动插入模板代码,代替手敲,极大的提高编码效率。
3,验证
在页面上点击电子书
分类后的delete
按钮,弹出如下提示。
点击确定,提示删除成功。
在后台数据产看cat_id
为165
的数据,show_status=0
说明已经被逻辑删除。
4,细节优化
- ①在删除前弹窗提示是否确认删除,确认后,调用接口,把要删除的分类Id传递给后端,后端软删除对应分类记录。
- ②点击删除后,后端已经删除,但是前端未刷新,可以调用方法
this.getMenus();
重新查询分类数据刷新界面。 - ③删除成功后重新请求会导致已经展开的菜单,又收缩了,用户体验不好,最好的效果是只有被删除的分类消失,页面其他部分保持不变。实现这个需求需要用到
el-tree
组件的default-expanded-keys
,用来指定需要展开的节点的id。
第一步,在el-tree中给属性绑定一个数组,default-expanded-keys="expandedKeys"
。
第二步,在js脚本的data中声明这个数组,expandedKeys: []
。
第三步,删除成功,重启请求分类数据后,将要被删除的分类节点的父节点的catId赋值给数组,this.expandedKeys = node.parent.data.catId; // 重置展开节点
。
Category.vue完整代码。
<template>
<el-tree
node-key="catId"
:data="menus"
:props="defaultProps"
:expand-on-click-node="false"
show-checkbox
default-expanded-keys="expandedKeys"
>
<span class="custom-tree-node" slot-scope="{ node, data }">
<span>{{ node.label }}</span>
<span>
<el-button
v-if="node.level <= 2"
size="mini"
@click="() => append(data)"
>
Append
</el-button>
<el-button
v-if="node.childNodes.length == 0"
type="text"
size="mini"
@click="() => remove(node, data)"
>
Delete
</el-button>
</span>
</span>
</el-tree>
</template>
<script>
export default {
components: {},
props: {},
data() {
return {
menus: [],
expandedKeys: [],
defaultProps: {
children: "children",
label: "name",
},
};
},
methods: {
append(data) {
console.log(data);
},
remove(node, data) {
console.log(node, data);
var ids = [node.data.catId];
this.$confirm(
`确定对[id=${ids.join(",")}]进行[${ids.length == 1 ? "删除" : "批量删除"}]操作?`,
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
}
)
.then(() => {
this.$http({
url: this.$http.adornUrl("/product/category/delete"),
method: "post",
data: this.$http.adornData(ids, false),
}).then(({ data }) => {
if (data && data.code === 0) {
this.$message({
message: "操作成功",
type: "success",
duration: 1500,
onClose: () => {
console.log("删除成功,关闭消息提示");
this.getMenus(); // 重新获取数据
this.expandedKeys = node.parent.data.catId; // 重置展开节点
},
});
} else {
this.$message.error(data.msg);
}
});
})
.catch(() => {});
},
// 获取分类数据
getMenus() {
this.dataListLoading = true;
this.$http({
url: this.$http.adornUrl("/product/category/list/tree"),
method: "get",
}).then(({ data }) => {
console.log(data);
this.dataListLoading = false;
this.menus = data.data;
});
},
},
created() {
this.getMenus(); // 获取分类数据
},
};
</script>
<style scoped>
</style>