猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是问题。想要一起实战吗?关注公号,获取基础代码,动手实战吧。
上几个章节,猿人君教会了你实现了属性/属性值和后台类目的绑定关系,今天,猿人君就带你来实现前台类目。
为什么会有前台类目
为了方便运营,在电商系统中,类目分为前台类目和后台类目。如果你经常网购,你会发现一个比较有意思的事情。鼠标移动到一级类目,会展示二级类目,点击一级二级类目,会跳转到对应的频道页面(不过做得大了都是分站,我们先考虑业务),点击三级类目会出发搜索的功能。
这些在之前的设计文章猿设计5——真电商之颠覆你的类目认知中已经讲述过了,这里就不再赘述了。
功能概览
前台类目,从某种程度上说,肩负了部分站点的导航以及内容组织的职责,要完成这一职责,我们可以先来看看需要实现的功能。
在前台类目模块中,系统体现了前台类目的层级关系,每一级类目都有对应的列表、新增/编辑功能。在一级类目中可以维护广告牌、在三级类目中,重点维护前后台类目的关系(以上本章节暂不讨论)。
数据库设计
根据之前的前台类目设计文章,我们很清楚的获知了前台类目的一些特征,我们根据之前的设计,将这些设计落地为数据库的物理设计,大家可以看一下(本章节仅讲述前台类目的实现)。
就类目而言,类目就像是一棵树,每一级类目都有可能有下一级类目,像这种特性,在数据库的设计上,是一种典型的自关联结构。但是类目用于检索时,往往伴随着层级关系的查找,比如提取某一级类目的信息。所以,我们在设计时,给予了一个level字段,用于方便提取固定层级的信息。
由于每一级维护的信息可能不同,所以在数据库设计上,我们做了一个整合,每一条行记录的信息是一二三级所有信息的集合,事实上,不同的层级只涉及部分字段内容,这种设计,也是一种常见的设计。
前台类目整体前端
类目的层级维护,从功能上讲,依然是一种整体和部分的关系,出于业务的考虑,在规模不是特别庞大的情况下,三级已经足够支撑你的运营。我们可以参考下之前的实现思路——将一级类目、二级类目、三级类目分别定义成小的组件。最后,由一个view来组织和整合它们就好了。
<template>
<div id="fnCategoryDiv">
<div v-if="oneCategoryShow">
<frontDeskCategoryOneSearch ref="frontDeskCategoryOneSearch" @lookSubordinate="lookOneSubordinate" />
</div>
<div v-if="twoCategoryShow">
<frontDeskCategoryTwoSearch ref="frontDeskCategoryTwoSearch" :pid="parentId" :pname="parentName" @lookSubordinate="lookTwoSubordinate" @returnBack="returnTwoBack" />
</div>
<div v-if="threeCategoryShow">
<frontDeskCategoryThreeSearch ref="frontDeskCategoryThreeSearch" :pid="parentId" :pname="parentName" @returnBack="returnThreeBack" />
</div>
</div>
</template>
<script>
import frontDeskCategoryOneSearch from '@/components/productManage/frontDeskCategoryOneSearch'
import frontDeskCategoryTwoSearch from '@/components/productManage/frontDeskCategoryTwoSearch'
import frontDeskCategoryThreeSearch from '@/components/productManage/frontDeskCategoryThreeSearch'
export default {
components: {
frontDeskCategoryOneSearch,
frontDeskCategoryTwoSearch,
frontDeskCategoryThreeSearch
},
data() {
return {
// 一级类目
oneCategoryShow: false,
// 二级类目
twoCategoryShow: false,
// 三级类目
threeCategoryShow: false,
parentId: 0,
parentName: '',
catOneId: 0
}
},
created() {
// 显示一级类目
this.oneCategoryShow = true
},
methods: {
// 二级回退
returnTwoBack() {
// 一级二级三级类目显示设置
this.oneCategoryShow = true
this.twoCategoryShow = false
this.threeCategoryShow = false
},
// 三级回退
returnThreeBack(pid, pname) {
// 一级二级三级类目显示设置
this.oneCategoryShow = false
this.twoCategoryShow = true
this.threeCategoryShow = false
this.parentId = this.catOneId
this.parentName = pname
console.log(this.parentId)
},
// 一级查看下级类目
lookOneSubordinate(row) {
// 一级二级三级类目显示设置
this.oneCategoryShow = false
this.twoCategoryShow = true
this.threeCategoryShow = false
this.parentId = row.fnCategoryId
this.parentName = row.fnCategoryName
this.catOneId = row.fnCategoryId
},
// 二级查看下级类目
lookTwoSubordinate(row) {
// 一级二级三级类目显示设置
this.oneCategoryShow = false
this.twoCategoryShow = false
this.threeCategoryShow = true
this.parentId = row.fnCategoryId
this.parentName = row.fnCategoryName
}
}
}
</script>
<style scoped>
</style>
值得注意的是,在查看下级和返回上级种,涉及组件之间的参数传递。您需要将,本级类目的ID作为父ID传入下级,而在下级返回上级的操作种,您需要将上上级的id作为父ID传入上一级列表页面(二级除外)。
关于父子组件之间的通信问题,在之前的文章中已经讲述过很多了,这里就不再赘述了。
前台类目后端实现
其实就前台类目的普通功能而言,目前来说相对简单,最主要的是建立父子关联这样一个自关联的概念。
由于之前已经给出了我们自己定义的代码生成器,属性组的实现也相对简单,考虑到篇幅问题,这一部分我们给出Controller层面的功能实现,service、和dao,还是希望你自行实现,在初学时期,多谢代码,对你熟悉掌握代码编写的技巧,是一个必不可少的环节。
/**
* Copyright(c) 2004-2020 pangzi
* com.pz.basic.mall.controller.product.fncategory.MallFnCategoryController.java
*/
package com.pz.basic.mall.controller.product.fncategory;
import com.pz.basic.mall.domain.base.Result;
import com.pz.basic.mall.domain.product.category.query.QueryMallCategory;
import com.pz.basic.mall.domain.product.category.vo.MallCategoryVo;
import com.pz.basic.mall.domain.product.fncategory.MallFnBgCategoryRel;
import com.pz.basic.mall.domain.product.fncategory.MallFnCategory;
import com.pz.basic.mall.domain.product.fncategory.query.QueryMallFnBgCategoryRel;
import com.pz.basic.mall.domain.product.fncategory.query.QueryMallFnCategory;
import com.pz.basic.mall.service.product.category.MallCategoryService;
import com.pz.basic.mall.service.product.fncategory.MallFnBgCategoryRelService;
import com.pz.basic.mall.service.product.fncategory.MallFnCategoryService;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
*
* @author pangzi
* @date 2020-06-22 20:47:27
*
*
*/
@RestController
@RequestMapping("/fncategory")
public class MallFnCategoryController {
private MallFnCategoryService mallFnCategoryService;
public void setMallFnCategoryService(MallFnCategoryService mallFnCategoryService) {
this.mallFnCategoryService = mallFnCategoryService;
}
/**
* 新增类目
* @param mallFnCategory
* @return
*/
@RequestMapping("/addMallFnCategory")
public Result<MallFnCategory> addMallFnCategory(@RequestBody MallFnCategory mallFnCategory){
try{
return mallFnCategoryService.addMallFnCategory(mallFnCategory);
}catch(Exception e){
e.printStackTrace();
return new Result(false);
}
}
/**
* 根据ID查找类目
* @param id
* @return
*/
@RequestMapping("/findMallFnCategoryById")
public Result<MallFnCategory> findMallFnCategoryById(Long id){
return mallFnCategoryService.getMallFnCategoryById(id.intValue());
}
/**
* 修改类目
* @param mallFnCategory
* @return
*/
@RequestMapping("/updateMallFnCategory")
public Result updateMallFnCategory(@RequestBody MallFnCategory mallFnCategory){
try{
return mallFnCategoryService.updateMallFnCategoryById(mallFnCategory);
}catch(Exception e){
e.printStackTrace();
return new Result(false);
}
}
/**
* 分页返回类目列表
* @param queryMallFnCategory
* @return
*/
@RequestMapping("/findByPage")
public Result<List<MallFnCategory>> findByPage(@RequestBody QueryMallFnCategory queryMallFnCategory){
return mallFnCategoryService.getMallFnCategorysByPage(queryMallFnCategory);
}
}
后台类目前端实现
聊完了后端数据接口的事情,我们一起来看看前端实现的问题,考虑到大部分朋友前端并不是很熟悉,我们再讲讲后台类目前端API组件的封装。
我们先封装访问后端的数据接口:
// 前台类目
export function fetchFnCategoryList(query) {
return request({
url: '/fncategory/findByPage',
method: 'post',
data: query
})
}
export function createMallFnCategory(data) {
return request({
url: '/fncategory/addMallFnCategory',
method: 'post',
data
})
}
export function updateMallFnCategory(data) {
return request({
url: '/fncategory/updateMallFnCategory',
method: 'post',
data
})
}
考虑到之前有朋友说页面编写起来实在困难,在这里, 为了让你更好的掌握前台类目的内容,这次将一二三级的前台页面都给到你。不过猿人君还是希望你尽量自己编码。不然,你真的很难掌握开发技巧。
一级前台类目
<template>
<div id="frontDeskCategoryOneSearchDiv">
<div>
<el-form ref="listQuery" :model="listQuery" :inline="true">
<el-form-item label="类目名称:" prop="fnCategoryNameLike">
<el-input v-model="listQuery.fnCategoryNameLike" placeholder="请输入类目名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="fetchData()">查询</el-button>
<el-button type="primary" icon="el-icon-edit" style="float:right;margin-bottom:20px;" @click="addDate()">新增一级</el-button>
</el-form-item>
</el-form>
</div>
<div>
<el-table
ref="table"
v-loading="listLoading"
:data="list"
style="width: 100%"
border
>
<el-table-column label="类目ID">
<template slot-scope="scope">{
{ scope.row.fnCatego