目錄
一、總述
二、前端部分
2.1 改良前端獲取分組列表接口及其調用
2.2 添加關聯的一整套邏輯
三、后端部分
四、總結
一、總述
前端部分和之前的商品品牌添加分類差不多。
也是修改一下前端的分頁獲取列表的接口,還有就是加上關聯的那一套邏輯,包括基本構件的引入、數據域的增添、方法的修改等
后端部分的話和之前的也差不多:
分組本身:
1. 分組信息分頁模糊查詢接口(新的一種傳參方式-一個大的reques對象里面兩個dto對象)
2. 刪除分組接口
同樣這里關聯的屬性,所以也要將 分組-屬性關聯對應刪除
關聯相關接口(和之前品牌關聯分類差不多):
1. 查詢當前已關聯的關聯列表
2. 刪除關聯
3. 新增關聯
4. 查詢當前分組下可選的屬性列表
這個第四點是這里相較于之前添加品牌-分類關聯所特殊的,之前沒什么要求,直接給了你全部的分類,可以任意的選擇。但是現在的話,屬性并不是都可以選的,有許多的限制。
二、前端部分
2.1 改良前端獲取分組列表接口及其調用
1. 修改接口,在api中
// 查詢屬性分組列表
export function listGroup(groupParams,pageParams) {return request({url: '/product/group/pageList',method: 'post',data: {attrGroupDto: groupParams,pageParamsDto: pageParams}})
}
2. 填充接口所需參數,調用接口
/** 查詢屬性分組列表 */getList() {this.loading = true;let groupParams = {attrGroupName: this.queryParams.attrGroupName,sort: this.queryParams.sort,descript: this.queryParams.descript,icon: this.queryParams.icon,catelogId: this.queryParams.catelogId}let pageParams = {pageNum: this.queryParams.pageNum,pageSize: this.queryParams.pageSize}listGroup(groupParams,pageParams).then((response) => {this.groupList = response.rows;this.total = response.total;this.loading = false;});}
相信這里的調用邏輯很簡單了,(就是前端頁面一打開,就發送請求,獲得分組列表數據,然后渲染到表格中,通過數組進行綁定 ps:就是一段廢話)
為什么要寫成post?
有同學過于遵循規范,培訓班的規范,什么查詢接口要搞成get,其實這都不重要,其實get只適用于少的參數,當參數多的時候,url長度有限就不好放了。
之前發get,兩個參數,需要將其先轉成字符串,后端再使用Gson進行解析成對象。是因為前端不允許params有兩個及以上的對象參數,一個沒問題,多個字符串類型的參數也沒問題,就是兩個對象類型的參數就不行了。
那么現在發post,兩個對象參數,行不行呢?答案是當然行,因為post嘛,就是傳對象的。
但是這里得注意一下后端:不能使用兩個對象也就是兩個標注了@RequestBody進行接收,這樣會爆400錯誤的
2.2 添加關聯的一整套邏輯
和之前的品牌-分類關聯基本一致,這里主要的區別就是添加了一個分組下可選的屬性業務。
1. 先將構件添加進來,相關的組件、方法都導入進來
1.1 基礎組件
這里和之前我直接引入的彈窗不同,這里完全將關聯封裝成了一個組件:
<template><div><el-dialog :close-on-click-modal="false" :visible.sync="visible" @closed="dialogClose"><el-dialog width="40%" title="選擇屬性" :visible.sync="innerVisible" append-to-body><div><el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()"><el-form-item><el-input v-model="dataForm.key" placeholder="參數名" clearable></el-input></el-form-item><el-form-item><el-button @click="getDataList()">查詢</el-button></el-form-item></el-form><el-table:data="dataList"borderv-loading="dataListLoading"@selection-change="innerSelectionChangeHandle"style="width: 100%;"><el-table-column type="selection" header-align="center" align="center"></el-table-column><el-table-column prop="attrId" header-align="center" align="center" label="屬性id"></el-table-column><el-table-column prop="attrName" header-align="center" align="center" label="屬性名"></el-table-column><el-table-column prop="icon" header-align="center" align="center" label="屬性圖標"></el-table-column><el-table-column prop="valueSelect" header-align="center" align="center" label="可選值列表"></el-table-column></el-table><el-pagination@size-change="sizeChangeHandle"@current-change="currentChangeHandle":current-page="pageIndex":page-sizes="[10, 20, 50, 100]":page-size="pageSize":total="totalPage"layout="total, sizes, prev, pager, next, jumper"></el-pagination></div><div slot="footer" class="dialog-footer"><el-button @click="innerVisible = false">取 消</el-button><el-button type="primary" @click="submitAddRealtion">確認新增</el-button></div></el-dialog><el-row><el-col :span="24"><el-button type="primary" @click="addRelation">新建關聯</el-button><el-buttontype="danger"@click="batchDeleteRelation":disabled="dataListSelections.length <= 0">批量刪除</el-button><!-- --><el-table:data="relationAttrs"style="width: 100%"@selection-change="selectionChangeHandle"border><el-table-column type="selection" header-align="center" align="center" width="50"></el-table-column><el-table-column prop="attrId" label="#"></el-table-column><el-table-column prop="attrName" label="屬性名"></el-table-column><el-table-column prop="valueSelect" label="可選值"><template slot-scope="scope"><el-tooltip placement="top"><div slot="content"><span v-for="(i,index) in scope.row.valueSelect.split(';')" :key="index">{{i}}<br /></span></div><el-tag>{{scope.row.valueSelect.split(";")[0]+" ..."}}</el-tag></el-tooltip></template></el-table-column><el-table-column fixed="right" header-align="center" align="center" label="操作"><template slot-scope="scope"><el-button type="text" size="small" @click="relationRemove(scope.row.attrId)">移除</el-button></template></el-table-column></el-table></el-col></el-row></el-dialog></div>
</template><script>
//這里可以導入其他文件(比如:組件,工具js,第三方插件js,json文件,圖片文件等等)
//例如:import?《組件名稱》?from?'《組件路徑》';export default {//import引入的組件需要注入到對象中才能使用components: {},props: {},data() {//這里存放數據return {attrGroupId: 0,visible: false,innerVisible: false,relationAttrs: [],dataListSelections: [],dataForm: {key: ""},dataList: [],pageIndex: 1,pageSize: 10,totalPage: 0,dataListLoading: false,innerdataListSelections: []};},//計算屬性?類似于data概念computed: {},//監控data中的數據變化watch: {},//方法集合methods: {selectionChangeHandle(val) {this.dataListSelections = val;},innerSelectionChangeHandle(val) {this.innerdataListSelections = val;},addRelation() {this.getDataList();this.innerVisible = true;},batchDeleteRelation(val) {let postData = [];this.dataListSelections.forEach(item => {postData.push({ attrId: item.attrId, attrGroupId: this.attrGroupId });});this.$http({url: this.$http.adornUrl("/product/attrgroup/attr/relation/delete"),method: "post",data: this.$http.adornData(postData, false)}).then(({ data }) => {if (data.code == 0) {this.$message({ type: "success", message: "刪除成功" });this.init(this.attrGroupId);} else {this.$message({ type: "error", message: data.msg });}});},//移除關聯relationRemove(attrId) {let data = [];data.push({ attrId, attrGroupId: this.attrGroupId });this.$http({url: this.$http.adornUrl("/product/attrgroup/attr/relation/delete"),method: "post",data: this.$http.adornData(data, false)}).then(({ data }) => {if (data.code == 0) {this.$message({ type: "success", message: "刪除成功" });this.init(this.attrGroupId);} else {this.$message({ type: "error", message: data.msg });}});},submitAddRealtion() {this.innerVisible = false;//準備數據console.log("準備新增的數據", this.innerdataListSelections);if (this.innerdataListSelections.length > 0) {let postData = [];this.innerdataListSelections.forEach(item => {postData.push({ attrId: item.attrId, attrGroupId: this.attrGroupId });});this.$http({url: this.$http.adornUrl("/product/attrgroup/attr/relation"),method: "post",data: this.$http.adornData(postData, false)}).then(({ data }) => {if (data.code == 0) {this.$message({ type: "success", message: "新增關聯成功" });}this.$emit("refreshData");this.init(this.attrGroupId);});} else {}},init(id) {this.attrGroupId = id || 0;this.visible = true;this.$http({url: this.$http.adornUrl("/product/attrgroup/" + this.attrGroupId + "/attr/relation"),method: "get",params: this.$http.adornParams({})}).then(({ data }) => {this.relationAttrs = data.data;});},dialogClose() {},//========// 獲取數據列表getDataList() {this.dataListLoading = true;this.$http({url: this.$http.adornUrl("/product/attrgroup/" + this.attrGroupId + "/noattr/relation"),method: "get",params: this.$http.adornParams({page: this.pageIndex,limit: this.pageSize,key: this.dataForm.key})}).then(({ data }) => {if (data && data.code === 0) {this.dataList = data.page.list;this.totalPage = data.page.totalCount;} else {this.dataList = [];this.totalPage = 0;}this.dataListLoading = false;});},// 每頁數sizeChangeHandle(val) {this.pageSize = val;this.pageIndex = 1;this.getDataList();},// 當前頁currentChangeHandle(val) {this.pageIndex = val;this.getDataList();}}
};
</script>
<style?scoped>
</style>
?這是老師所給的代碼,等下主要就是對里面的方法進行修改
1.2 添加按鈕,使用組件
因為我其實是我使用的若依的逆向vue代碼包括之前的品牌也是,所以還是要自己手動添加上這些額外的功能組件。之后的話就不使用若依給的了,直接使用老師的,圖方便簡單。其實只要懂大致邏輯就行了,前端。
首先添加上關聯的按鈕:
<el-button type="text" size="mini" @click="relationHandle(scope.row.attrGroupId)">關聯</el-button>
然后使用上組件,只有這樣才會有效果
還是那三步(這是很基礎的操作,但是考慮到還是有不嚴謹的同學):
1. 抽取組件
上面已經說了
2. 導入組件
import RelationUpdate from "./attr-group-relation";
3. 使用組件?
先注冊:
components: { Category,RelationUpdate }
?然后使用:
<!-- 修改關聯關系 --><relation-update v-if="relationVisible" ref="relationUpdate" @refreshData="getDataList"></relation-update>
2. 查看其數據域
無非就是彈窗標志、數據屬性
這里的話若依的這個逆向的分組的組件,其基礎的數據都已經給好了。
但是因為這里引入了一個彈窗組件,勢必得通過布爾標識來決定是否展示,因此得放上這個:
屬性名在老師所給的組件中的v-if里面:relationVisible
而那個關聯彈窗組件的話,老師把所需的數據都寫好了,我們不需要再動了。?
3. 修改其方法(主要就是改一下請求,邏輯基本上不需要怎么動)
?分組組件中:
在分組組件中,點擊關聯觸發的事件:
<el-button type="text" size="mini" @click="relationHandle(scope.row.attrGroupId)">關聯</el-button>
這個relationHandle方法沒什么好說的,直接用老師的就行,因為它就是打開窗口。調用關聯組件的初始化方法。
//處理分組與屬性的關聯relationHandle(groupId) {this.relationVisible = true;this.$nextTick(() => {this.$refs.relationUpdate.init(groupId);});}
?當然像之前的分頁模糊方法已經寫好了,就不再贅述了。
其實這里只是新加了一個關聯功能,所以大體上其實就加上這個點擊按鈕事件方法就行了。
其他的話要不就是若依生成的已經修改過了的,在前面幾天..
關聯組件中:
其實重點在這里
其實吧,有了之前品牌-分類關聯的功能實現之后,其實這里就知道怎么寫了,因為都是關聯嘛,大致的邏輯都是一樣的。
無非就是:
1. 查詢到當前的關聯列表方法
先看一下這個方法返回值所綁定的組件上面的屬性,這樣便于我們理解這個方法到底是獲取哪里的數據。
很明顯知道這是 關聯的屬性列表。?
那么這個獲取邏輯是怎樣的呢?
其實就是當我們點擊了分組組件中的關聯按鈕之后,就會調用關聯組件中的init方法,為屬性列表拿到數據
分組組件中的調用init:
?
1. init方法解析
init(id) {this.attrGroupId = id || 0;this.visible = true;listRelation({attrGroupId: this.attrGroupId}).then((response)=>{this.relationAttrs = response.rows;this.total = response.total;this.loading = false;})}
邏輯基本不要動,就是改下這個請求
前端接口:
// 查詢屬性&屬性分組關聯列表
export function listRelation(query) {return request({url: '/product/attrAttrGroupRelation/list',method: 'get',params: query})
}
2. 新增關聯方法
新建關聯,肯定是先得有一個列表給我們看,然后我們再進行選擇,之前的那個品牌-分類關聯,因為一個品牌可以關聯任意的分類,不需要考慮這個分類是否已被其他品牌所關聯,因為是一個品牌可以對應多個分類,所以在那里分類是無腦直接全部顯示,然后我們去選擇的。
但是這里不同,我來說一下這里的業務,其實很簡單:
1. 屬性一定得是基本屬性,當然這是顯然的
2. 其次所選的屬性一定得是當前分組所對應的分類下的屬性,不是這一組的分類下的屬性拿來用沒意義
3. 然后就是不能選擇當前分組已經選好了的屬性,已經當前分組所屬分類下的其他分組已經選好的屬性,因為一個基本屬性只能對應一個分組,分組和屬性的關系是一對多的關系,一個分組下有多個屬性,但是一個屬性只能屬于一個分組
當然我在前端這里說了這個,其實這個業務,查詢的邏輯是后端實現的,但我還是要提前的說一下,先知道一下...
哈哈哈,現在還是新增方法呢。因為新增涉及到這個查詢所以就說了這些。
下面我還是直接貼新增方法的代碼:
由這個事件,點擊新增的這個事件:
新增方法:
?
submitAddRealtion() {this.innerVisible = false;//準備數據console.log("準備新增的數據", this.innerdataListSelections);if (this.innerdataListSelections.length > 0) {let postData = [];this.innerdataListSelections.forEach(item => {postData.push({ attrId: item.attrId, attrGroupId: this.attrGroupId });});batchAddRelation(postData).then((response) => {this.$modal.msgSuccess("新增關聯成功");this.$emit("refreshData");this.init(this.attrGroupId);});}else{this.$modal.confirm("未選擇屬性")}}
?講一下這個this.$emit("refreshData"):
就是更新可選屬性列表:
.emit是向父組件傳遞的一個名為:refreshData的事件,就會觸發父組件中的這個事件所綁定的方法
?
重回原先的新增,下面是新增接口
// 新增屬性&屬性分組關聯
export function addRelation(data) {return request({url: '/product/attrAttrGroupRelation',method: 'post',data: data})
}
?然后就到新增方法
3. 刪除關聯方法
移除以及批量刪除按鈕事件:
移除方法:
//移除關聯relationRemove(id) {delRelation(id).then((response)=>{this.$modal.msgSuccess("刪除關聯成功");this.init(this.attrGroupId);})}
?批量刪除方法:
batchDeleteRelation() {let postData = [];this.dataListSelections.forEach(item => {postData.push(item.id);});delRelation(postData).then((response)=>{this.$modal.msgSuccess("批量刪除關聯成功");this.init(this.attrGroupId);})}
還是老樣子,刪除之后記得重新刷新;
接口:
移除和批量刪除共用一個接口:
// 刪除屬性&屬性分組關聯
export function delRelation(id) {return request({url: '/product/attrAttrGroupRelation/' + id,method: 'delete'})
}
別看它是id,也可以傳遞id數組?
當然這里特殊的一點就是加了一個查詢當前分組下可選的屬性列表方法,因為業務需求。
4. 查詢當前分組下可選的屬性列表方法
為什么要有這個在新增那里已經就說了
綁定的數據或者是查詢按鈕:
方法:
// 獲取可選屬性列表getDataList() {this.dataListLoading = true;let pageParams = {page: this.pageIndex,limit: this.pageSize,key: this.dataForm.key};attrList(this.attrGroupId,pageParams).then((tableDataInfo) => {if (tableDataInfo) {this.dataList = tableDataInfo.rows;this.totalPage = tableDataInfo.total;} else {this.dataList = [];this.totalPage = 0;}this.dataListLoading = false;});}
?接口:
在attr.js里面:
// 查詢某個分組下可選的商品屬性列表
export function attrList(groupId,params) {return request({url: `/product/attr/attrList?groupId=${groupId}`,method: 'post',data: params})
}
三、后端部分
這里只說需要修改的,其他的接口直接使用逆向生成的就行了。
1. 分組本身
1. 分頁模糊查詢列表接口
這個沒什么好說的,之前就寫過。
接口:
/*** 查詢屬性分組列表*/@ApiOperation("查詢屬性分組列表")//@PreAuthorize("@ss.hasPermi('product:group:list')")@PostMapping("/pageList")public TableDataInfo list(@RequestBody GroupPageRequest groupPageRequest){TableDataInfo tableDataInfo = attrGroupService.pageList(groupPageRequest.getAttrGroupDto(),groupPageRequest.getPageParamsDto());return tableDataInfo;}
實現:
/*** 分頁查詢分組列表** @param attrGroupDto* @param pageParamsDto* @return*/@Overridepublic TableDataInfo pageList(AttrGroupDto attrGroupDto, PageParamsDto pageParamsDto) {LambdaQueryWrapper<AttrGroup> wrapper = new LambdaQueryWrapper<>();wrapper.like(StringUtils.hasText(attrGroupDto.getAttrGroupName()),AttrGroup::getAttrGroupName,attrGroupDto.getAttrGroupName());wrapper.eq(attrGroupDto.getSort()!=null,AttrGroup::getSort,attrGroupDto.getSort());wrapper.like(StringUtils.hasText(attrGroupDto.getDescript()),AttrGroup::getDescript,attrGroupDto.getDescript());wrapper.like(StringUtils.hasText(attrGroupDto.getIcon()),AttrGroup::getIcon,attrGroupDto.getIcon());wrapper.eq(attrGroupDto.getCatelogId()!=null,AttrGroup::getCatelogId,attrGroupDto.getCatelogId());Page<AttrGroup> page = new Page<>(pageParamsDto.getPageNum(), pageParamsDto.getPageSize());page(page,wrapper);return new TableDataInfo(page.getRecords(),(int)page.getTotal());}
也就是利用MP現成的分頁方法,然后按照若依的規范,封裝一下查詢數據即可。?
2. 刪除接口
因為這里涉及到關聯,因此也要刪除掉關聯
接口:
/*** 刪除屬性分組*/@ApiOperation("刪除屬性分組")//@PreAuthorize("@ss.hasPermi('product:group:remove')")@Log(title = "屬性分組", businessType = BusinessType.DELETE)@DeleteMapping("/{attrGroupIds}")public AjaxResult remove(@PathVariable Long[] attrGroupIds) {return toAjax(attrGroupService.removeMore(Arrays.asList(attrGroupIds)));}
實現:
/*** 刪除分組本身以及刪除分組所關聯的 分組-屬性關聯* @param list* @return*/@Override@Transactionalpublic boolean removeMore(List<Long> list) {//1. 刪除分組本身boolean remove = removeByIds(list);AtomicBoolean flag = new AtomicBoolean(true);//2. 刪除 分組-屬性關聯list.stream().forEach(item->{List<AttrAttrgroupRelation> relations = attrAttrgroupRelationService.list(new LambdaQueryWrapper<AttrAttrgroupRelation>().eq(AttrAttrgroupRelation::getAttrGroupId, item));relations.stream().forEach(item1->{boolean remove1 = attrAttrgroupRelationService.removeById(item1.getId());if (!remove1) {flag.set(false);}});});return remove&& flag.get();}
?給好處理結果就行了。因為這是增刪改操作,涉及到了多張表,記得加上@Transactional注解保證事務
2. 關聯相關的接口
1. 查詢關聯的屬性列表(不帶分頁模糊)
因為這里是關聯,想一想一個分組下面能有多少個屬性呢?只能有那么多,因此不需要分頁了,因為少,也沒必要模糊了
接口:
/*** 查詢屬性&屬性分組關聯列表*/@ApiOperation("查詢屬性&屬性分組關聯列表")//@PreAuthorize("@ss.hasPermi('product:relation:list')")@GetMapping("/list")public TableDataInfo list(AttrAttrgroupRelation attrAttrgroupRelation) {startPage();List<AttrAttrGroupRelationVo> list = attrAttrgroupRelationService.detailList(new QueryWrapper<AttrAttrgroupRelation>(attrAttrgroupRelation));return getDataTable(list);}
2. 查詢當前分組可選屬性列表
邏輯在前端那里說了,代碼上面也有注釋,其實很簡單的。
接口:
這個接口在屬性控制器里面,因為是查的屬性
/*** 獲取分組下可選的屬性*/@ApiOperation("查詢分組下可選的屬性列表")@PostMapping("/attrList")public TableDataInfo attrList(Long groupId,@RequestBody Map<String,Object> params){return attrService.attrList(groupId,params);}
和之前的分組列表接口不一樣,這里使用Map來接收分頁參數?
實現:
/*** 獲取分組下可選的屬性* @param groupId* @param params* @return*/@Overridepublic TableDataInfo attrList(Long groupId, Map<String, Object> params) {//1. 只需要這個分組同分類下的屬性AttrGroup group = groupService.getById(groupId);Long catId = group.getCatelogId();//2. 不能是這個分類下其他分組已經選過的屬性//2.1 當前分類下的其他分組List<AttrGroup> list = groupService.list(new LambdaQueryWrapper<AttrGroup>().eq(AttrGroup::getCatelogId, catId));//2.2 這些分組所關聯的屬性List<Long> listIds = new ArrayList<>();list.stream().forEach(item->{List<AttrAttrgroupRelation> list1 = attrAttrgroupRelationService.list(new LambdaQueryWrapper<AttrAttrgroupRelation>().eq(AttrAttrgroupRelation::getAttrGroupId, item.getAttrGroupId()));list1.stream().forEach(item1 -> listIds.add(item1.getAttrId()));});LambdaQueryWrapper<Attr> wrapper = new LambdaQueryWrapper<Attr>().eq(Attr::getCatelogId, catId).like(StringUtils.hasText((String) params.get("key")), Attr::getAttrName, (String) params.get("key"));if(listIds.size()!=0){wrapper.notIn(Attr::getAttrId, listIds);}//2.3 從當前分類下的屬性排除List<Attr> attrList = list(wrapper);//封裝分頁數據Integer page = (Integer) params.get("page");Integer limit = (Integer) params.get("limit");List<Attr> records = PageUtils.page(attrList, page, limit);return new TableDataInfo(records, attrList.size());}
3. 新增關聯接口
沒什么好說的,不涉及到表或者是其他字段,直接新增就行了
接口:
/*** 新增屬性&屬性分組關聯*/@ApiOperation("新增屬性&屬性分組關聯")//@PreAuthorize("@ss.hasPermi('product:relation:add')")@Log(title = "屬性&屬性分組關聯", businessType = BusinessType.INSERT)@PostMappingpublic AjaxResult add(@RequestBody AttrAttrgroupRelation attrAttrgroupRelation) {return toAjax(attrAttrgroupRelationService.save(attrAttrgroupRelation));}
4. 刪除關聯接口
同樣也是沒涉及到其他表,直接刪除就行
接口:
/*** 刪除屬性&屬性分組關聯*/@ApiOperation("刪除屬性&屬性分組關聯")//@PreAuthorize("@ss.hasPermi('product:relation:remove')")@Log(title = "屬性&屬性分組關聯", businessType = BusinessType.DELETE)@DeleteMapping("/{ids}")public AjaxResult remove(@PathVariable Long[] ids) {return toAjax(attrAttrgroupRelationService.removeByIds(Arrays.asList(ids)));}
四、總結
總的來說前端部分依舊比較繁瑣,其實不難就是繁瑣。
什么引入這些組件啊,達到基本樣式就有了啊
還有導入組件、方法啊
搞好數據域啊,
搞好方法啊。
而后端的話,也不難,還是常見的增刪改查接口
查詢分頁模糊查,新增刪除修改要有全局意識是否會設計到其他字段或者是其他表,所謂的全局意識其實就是按照業務來的。
像這里的話就這個 當前分組下可選的屬性列表這個查詢業務稍微復雜一點。
另外的話幾種前端傳參,后端接參的方式要掌握:
1. 純get,當有兩個對象參數的時候,前端需要注意一下,傳遞的是字符串了,后端解析一下
2. 一個get,一個data,這里的話前端沒什么要說的,后端也是
3. 純post,前端照樣傳,但是后端不允許兩個對象接收,得用一個對象,一個@RequestBody