part 1
part 2
part 3
part 4 本页
5.1 新增套餐
5.2 套餐信息分页查询
5.3 删除套餐
其他小功能都比较简单且类似,不再赘述
getDishTypeList() {
//通过category中的type = 1/2 查出对于的菜品分类或是套餐分类,显示到前端的下拉框中
//返回值中的data的类型是:List,赋值给了setMealList属性进行双向绑定
getCategoryList({ type: 2, page: 1, pageSize: 1000 }).then((res) => {
if (res.code === 1) {
this.setMealList = res.data.map((obj) => ({ ...obj, idType: obj.id }))
} else {
this.$message.error(res.msg || '操作失败')
}
})
},
// 添加菜品,之前有按钮点击事件绑定了这个函数
//+ 添加菜品
openAddDish() {
this.seachKey = ''
this.dialogVisible = true
//搜索条件清空,菜品重新查询,菜品类别选第一个重新查询
this.value = ''
this.keyInd = 0
//每个菜品对应有哪些菜,在dishList中循环显示出来
this.getDishList(this.dishType[0].id)
},
getDishList (id) {
queryDishList({categoryId: id}).then(res => {
if (res.code === 1) {
if (res.data.length == 0) {
this.dishAddList = []
return
}
let newArr = res.data;
newArr.forEach((n) => {
n.dishId = n.id
n.copies = 1
// n.dishCopies = 1
n.dishName = n.name
})
this.dishAddList = newArr
} else {
this.$message.error(res.msg)
}
})
},
其中queryDishList({categoryId: id})
发送ajax请求,根据categoryId获取dish(获取当前套餐分类下的菜)。dish表中有category_id(相当于是副键),也就是说,一个category对应很多的dish。
//提交表单,最主要的代码,把整体数据提交上去。
submitForm(formName, st) {
this.$refs[formName].validate((valid) => {
if (valid) {
let prams = { ...this.ruleForm }
prams.price *= 100
prams.setmealDishes = this.dishTable.map((obj) => ({
copies: obj.copies,
dishId: obj.dishId,
name: obj.name,
price: obj.price,
}))
prams.status = this.ruleForm ? 1 : 0
prams.categoryId = this.ruleForm.idType
if(prams.setmealDishes.length < 1){
this.$message.error('请选择菜品!')
return
}
if(!this.imageUrl){
this.$message.error('请上传套餐图片')
return
}
// delete prams.dishList
if (this.actionType == 'add') {
delete prams.id
//发送请求
addSetmeal(prams)
.then((res) => {
if (res.code === 1) {
this.$message.success('套餐添加成功!')
if (!st) {
this.goBack()
} else {
this.$refs.ruleForm.resetFields()
this.dishList = []
this.dishTable = []
this.ruleForm = {
name: '',
categoryId: '',
price: '',
code: '',
image: '',
description: '',
dishList: [],
status: true,
id: '',
idType: '',
}
this.imageUrl = ''
}
} else {
this.$message.error(res.msg || '操作失败')
}
})
.catch((err) => {
this.$message.error('请求出错了:' + err)
})
} else {
delete prams.updateTime
editSetmeal(prams)
.then((res) => {
if (res.code === 1) {
this.$message.success('套餐修改成功!')
this.goBack()
} else {
this.$message.error(res.msg || '操作失败')
}
})
.catch((err) => {
this.$message.error('请求出错了:' + err)
})
}
} else {
return false
}
})
},
其中调用的方法
// 新增数据接口
const addSetmeal = (params) => {
return $axios({
url: '/setmeal',
method: 'post',
data: { ...params }
})
}
/**
* 根据菜品分类查菜品比如: 川菜这个选项一点击,就通过这个controller返回一个list(元素就是各种川菜dish)
* @param dish 参数只有一个categoryId,
* @return
*/
@GetMapping("list/getDishByCategoryId.do")
public RetObj getDishByCategoryId(Dish dish){
LambdaQueryWrapper<Dish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(dish != null,Dish::getCategoryId,dish.getCategoryId())
.orderByDesc(Dish::getSort);
List<Dish> dishList = dishService.list(lambdaQueryWrapper);
return RetObj.success(dishList);
}
2. 对应菜品分类下的菜品查询到并显示到前端后,整体添加页面提交请求给后端,进行插入数据。这里 肯定需要操作来个表,因为新增套餐这个页面提交的数据就涉及来个表的数据,主要是套餐下有很多菜品。
分析前端发送过来的数据
{
"name": "二逼餐饮",
"categoryId": "1641061323236622337",
"price": 12300,
"code": "",
"image": "abfe28a3-35af-493d-a043-295189807847.jpg",
"description": "asdf",
"dishList": [],
"status": 1,
"idType": "1641061323236622337",
"setmealDishes": [
{
"copies": 1,
"dishId": "1645433949618958337",
"name": "二逼2",
"price": 32100
},
{
"copies": 1,
"dishId": "1413384757047271425",
"name": "王老吉",
"price": 500
},
{
"copies": 1,
"dishId": "1413385247889891330",
"name": "米饭",
"price": 200
},
{
"copies": 1,
"dishId": "1397860578738352129",
"name": "白切鸡",
"price": 6600
}
]
}
注意setmealDishes,这里面只有我们选中的菜品的信息,对setmeal_dish这个表进行操作的时候,肯定还需要setmeal_id,就是这个菜现在属于哪个套餐分类中,这个要自己加。
思路和之前类似,写一个MealDto,把meal的信息(名称、价格、图片等等存进去),还要报错对应的dish的信息,一次封装到MealDto
中。
@Data
public class SetMealDto extends Setmeal {
//名字一定要和前端一致,否则无法注入
List<SetmealDish> setmealDishes;
}
List
这个前端传来的数据中肯定没有这些菜品对应的套餐的setmeal_id,这个就需要我们重新构造一个list,把前端传来的那个list进行完善,添加setmeal_id的值。@Transactional
public void saveMealWithFlavor(SetMealDto setMealDto) {
this.save(setMealDto);
List<SetmealDish> setmealDishes = setMealDto.getSetmealDishes();
//setmealDishes中有一个字段:setmeal_id,这个字段在上面那个list中肯定是没有的!
// 只有每个菜品自己的信息,这个setmeal_id就是setMealDto中的id
List<SetmealDish> afterCompleteList = setmealDishes.stream().map(item -> {
SetmealDish setmealDish = new SetmealDish();
BeanUtils.copyProperties(item,setmealDish);
setmealDish.setSetmealId(setMealDto.getId().toString());
return setmealDish;
}).collect(Collectors.toList());
boolean res = setmealDishService.saveBatch(afterCompleteList);
if (res == false){
throw new RuntimeException("套餐中菜品导入失败!");
}
}
@PostMapping("/add/setmeal.do")
public RetObj setMealController(@RequestBody SetMealDto setMealDto){
setmealService.saveMealWithFlavor(setMealDto);
return RetObj.success("成功新增套餐!");
}
//状态更改
statusHandle (row) {
let params = {}
if (typeof row === 'string' ){
if (this.checkList.length == 0){
this.$message.error('批量操作,请先勾选操作菜品!')
return false
}
params.ids = this.checkList.join(',')
params.status = row
} else {
params.ids = row.id
params.status = row.status ? '0' : '1'
}
this.$confirm('确认更改该套餐状态?', '提示', {
'confirmButtonText': '确定',
'cancelButtonText': '取消',
'type': 'warning'
}).then(() => {
// 起售停售---批量起售停售接口
setmealStatusByStatus(params).then(res => {
if (res.code === 1) {
this.$message.success('套餐状态已经更改成功!')
this.handleQuery()
} else {
this.$message.error(res.msg || '操作失败')
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
})
},
如果是多个id,就发送多个id(对应是批量启售)
const setmealStatusByStatus = (params) => {
return $axios({
url: `/setmeal/status/${params.status}`,
method: 'post',
params: { ids: params.ids }
})
}
// 全部操作
handleSelectionChange (val){
let checkArr = []
val.forEach((n) => {
checkArr.push(n.id)
})
this.checkList = checkArr
},
handleSizeChange (val) {
this.pageSize = val
this.init()
},
handleCurrentChange (val) {
this.page = val
this.init()
}
this.tableData = res.data.records || [] ;this.counts = res.data.total
async init () {
const params = {
page: this.page,
pageSize: this.pageSize,
name: this.input ? this.input : undefined
}
await getSetmealPage(params).then(res => {
if (String(res.code) === '1') {
this.tableData = res.data.records || []
this.counts = res.data.total
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
},
//图片下载直接调用download的controller方法,注意传过去name,以得到对应的image
getImage (image) {
return `/common/download?name=${image}`
},
handleQuery() {
this.page = 1;
this.init();
},
@GetMapping("/list/page.do")
public RetObj getSetmealPageController(int page, int pageSize, String name){
LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
//要注意,如果前端没有给模糊查询的name,那就不应该查询,否则查到是的0条数据!
// select count(*) from setmeal where name=null =>查到0条数据
lambdaQueryWrapper.like(StringUtils.isNotBlank(name),Setmeal::getName,name)
.orderByDesc(Setmeal::getUpdateTime);//根据跟新时间拍个序,你漏掉的
Page<Setmeal> pageInfo = new Page<>(page,pageSize);
setmealService.page(pageInfo,lambdaQueryWrapper);
//解决两个表的问题,setmeal表只有category_id,而没有菜品对应的name,在setmeal_dish中才有。
//解决思路,在SetmealDto中加入Name这个成员变量,多查一次在category这个表中的name,进行赋值
//注意前端那里是categoryName,要的不是name!!
Page<SetMealDto> pageInfoWithName = new Page<>(page,pageSize);
BeanUtils.copyProperties(pageInfo,pageInfoWithName,"records");
List<SetMealDto> recordsWithName = pageInfo.getRecords().stream().map(item -> {
SetMealDto setMealDto = new SetMealDto();
Category category = categoryService.getById(item.getCategoryId());
if (category != null){//没考虑到的,防止出现空指针异常!!
setMealDto.setCategoryName(category.getName());
BeanUtils.copyProperties(item,setMealDto);
}
return setMealDto;
}).collect(Collectors.toList());
pageInfoWithName.setRecords(recordsWithName);
return RetObj.success(pageInfoWithName);
}
// 删除
deleteHandle (type, id) {
if (type === '批量' && id === null) {
if (this.checkList.length === 0) {
return this.$message.error('请选择删除对象')
}
}
this.$confirm('确定删除该套餐, 是否继续?', '确定删除', {
'confirmButtonText': '确定',
'cancelButtonText': '取消',
}).then(() => {
deleteSetmeal(type === '批量' ? this.checkList.join(',') : id).then(res => {
if (res.code === 1) {
this.$message.success('删除成功!')
this.handleQuery()
} else {
this.$message.error(res.msg || '操作失败')
}
}).catch(err => {
this.$message.error('请求出错了:' + err)
})
})
},
上面代码的checkList就是在勾选中对应套餐的时候,触发以下函数,将对应数据压入
handleSelectionChange (val){
let checkArr = []
val.forEach((n) => {
checkArr.push(n.id)
})
this.checkList = checkArr
},
删除操作deleteSetmeal,因为可能是一次删除多个,所以这里用ids,看上面的代码中分装好了多个ids,使用三木运算符判断是删除一个,还是一批。
const deleteSetmeal = (ids) => {
return $axios({
url: '/setmeal',
method: 'delete',
params: { ids }
})
}
先是接收参数,使用List接收,因为可能是多个ids,注意和名字对应上,使用@RequestParam
明确能不能删除(是不是售卖状态),如果不能删除,那就抛出异常
sql 设想: select count(*) from setmeal where id in (id1,id2,id3) and status = 1
注意不同表的id,主键和副键,在删除的时候removeByIds的时候多注意。
@Transactional
public void deleteBatchWithDish(@RequestParam List ids){
//查询套餐状态,确定是否可用删除,这个是要第一个确定的!!
LambdaQueryWrapper lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
lambdaQueryWrapper1.eq(Setmeal::getStatus,2);
lambdaQueryWrapper1.in(Setmeal::getId,ids);//这个需要重点学习,就不用遍历ids,比如下面删除dish的代码那样。
//this.remove(lambdaQueryWrapper1); 需要判断!判断能不能删除
if (this.count(lambdaQueryWrapper1) > 0){
//如果不能删除,抛出一个业务异常
throw new CustomException(“套餐正在售卖中,不能删除”);
}
//删除
this.removeBatchByIds(ids);
//错误代码!!setmealDishService的id是自己的id,是主键,应该根据副键删除!
//setmealDishService.removeBatchByIds(ids);
ids.forEach(item -> {
LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(ids!= null,SetmealDish::getSetmealId,item);
setmealDishService.remove(lambdaQueryWrapper);
});
}