1、前端
-
规格选项:点击规格选项,需要拼凑条件
-
点击不限,需要将对应条件移除
- "specList": {
- "机身颜色": "金色",
- "内存": "3GB"
- },
1.2、前端实现
-
1、修改 ~/pages/_cid.vue组件,给每一个选项绑定事件(含"不限")
- 参数:规格名称、选项的值、event(鼠标事件对象,用于回显)
-
2、编写specSearch函数,用于操作data查询条件,需要在searchMap添加specList条件
- 如果选项值不为Null,添加条件
- 如果选项值为Null,删除条件
- specSearch(specName, optionName, e) {
- //参数1:specName 规格名称
- //参数2:optionName 规格选项的值
- //1) 处理条件:选择值,如果存在添加条件,如果不存在删除条件
- if (optionName){
- //存在
- this.searchMap.specList[specName] = optionName;
- } else {
- //不存在
- delete this.searchMap.specList[specName];
- }
-
- //重新查询
- this.searchList();
-
- //方式1:jquery代码 处理回显
- //获得事件源 a 标签,再获得父标签<dd>,再添加用时
- $(e.target).parent().addClass("cur");
-
- //获得 a 标签父元素的所有,将样式移除
- $(e.target).parent().siblings().removeClass("cur");
-
- },
1.2.1、品牌查询
需要使用修改后的品牌进行查询
- brandSearch(bid) {
- //切换品牌
- this.searchMap.brandId = bid;
- //查询
- this.searchList();
- },
1.2.2、关键字查询
-
1、修改头部搜索的组件,添加keyword变量与文本框进行数据绑,给搜索按钮绑定事件
- data() {
- return {
- keyword: ""
- };
- }
-
2、操作vuex,将keyword保存到vuex中
-
注意:vuex中必须有对应的变量
-
sotre/index.js
- //state区域,相当于定义变量
- export const state = () => ({
- user: null,
- keyword: null
- })
- //mutations区域,用于修改数据
- export const mutations = {
- setData(state, obj) {
- state[obj.key] = obj.value
- }
- }
-
HeaderSearch.vue
-
-
3、修改列表页面,添加 watch 对 vuex 中keyword进行监控,如果数据发生改变进行查询
-
注意:在 watch 只能使用普通fuction,不能使用箭头函数
- watch: {
- "$store.state.keyword":
- function(newValue, oldValue) {
- //添加 keyword 查询条件
- this.searchMap.keyword = newValue;
- //查询
- this.searchList();
- }
- }
1.2.3、排序
-
价格的需求:
- 第一次点击时,按照价格升序进行排序
- 第一次之后,按照当前排序取反进行操作。
-
1、给排序的按钮绑定事件,传递唯一标识(xl、sj等)、点击后加上高亮
- <dl>
- <dt>排序:</dt>
- <dd :class="{'cur': searchMap.sortBy == 'xl'}">
- <a href @click.prevent="sortSearch('xl')">销量</a>
- </dd>
- <dd :class="{'cur': searchMap.sortBy == 'jg'}">
- <a href @click.prevent="sortSearch('jg')">
- 价格
- <!-- 升序:价格由低到高 -->
- <span v-if="searchMap.sortBy == 'jg' && searchMap.sortWay=='asc'">↑</span>
- <!-- 降序:价格由高到低 -->
- <span v-if="searchMap.sortBy == 'jg' && searchMap.sortWay=='desc'">↓</span>
- </a>
- </dd>
- <dd :class="{'cur': searchMap.sortBy == 'pl'}">
- <a href @click.prevent="sortSearch('pl')">评论数</a>
- </dd>
- <dd :class="{'cur': searchMap.sortBy == 'sj'}">
- <a href @click.prevent="sortSearch('sj')">上架时间</a>
- </dd>价格:
- <input
- type="number"
- v-model="searchMap.minPrice"
- style="width:100px"
- placeholder="¥"
- /> -
- <input type="number" v-model="searchMap.maxPrice" style="width:100px" placeholder="¥" />
- <input type="submit" value="搜索" @click.prevent="searchList()" />
- </dl>
-
2、编写排序函数 sortSearch,根据点击次数,修改升降序方法
- sortSearch(sortBy) {
- //第一次点击、之后切换排序方式
- if (this.searchMap.sortBy == sortBy) {
- //点击第二次切换排序方式
- this.searchMap.sortWay =
- this.searchMap.sortWay == "asc" ? "desc" : "asc";
- } else {
- //第一次默认升序
- this.searchMap.sortBy = sortBy;
- this.searchMap.sortWay = "asc";
- }
- this.searchList();
- }
1.2.4、价格区间
- <input type="text" style="width:80px" v-model="searchMap.minPrice" name="" id=""> -
- <input type="text" style="width:80px" v-model="searchMap.maxPrice" name="" id="">
- <input type="button" @click.prevent="searchList" value="搜索">
1.2.5、分页
-
1、拷贝分页组件
- <template>
- <div class="page mt20">
- <a href v-if="page > 1" @click.prevent="pageClick(1)">首页</a>
- <a href v-if="page > 1" @click.prevent="pageClick(page-1)">上一页</a>
- <a
- href
- v-for="n in pageRange"
- :key="n"
- @click.prevent="pageClick(n)"
- :class="{'cur': page == n}"
- >{{n}}</a>
- <a href v-if="page < totalPage" @click.prevent="pageClick(page+1)">下一页</a>
- <a href v-if="page < totalPage" @click.prevent="pageClick(totalPage)">尾页</a>
- <span>
- <em>
- 共{{totalPage}}页 到第
- <input type="text" class="page_num" v-model="goNum" /> 页
- </em>
- <a href class="skipsearch" @click.prevent="pageClick(goNum)">确定</a>
- </span>
- </div>
- </template>
- <script>
- export default {
- data() {
- return {
- page: 1, //当前第几页
- totalPage: 0, //总分页数
- goNum: 1 //跳转页面
- };
- },
- methods: {
- pageClick: function(n) {
- //修改当前页
- this.page = parseInt(n);
- //通知调用,修改数据
- this.$emit("page_changed", n);
- }
- },
- computed: {
- //计算属性
- pageRange: function() {
- //计算总分页数 -- 100/20 = 5 102/20 = 6
- if (this.total % this.page_size == 0) {
- //整除
- this.totalPage = this.total / this.page_size;
- } else {
- this.totalPage = parseInt(this.total / this.page_size) + 1;
- }
- //分页范围
- let star = Math.max(this.page - 5, 1); //范围开始:得到一个 >=1 的数字
- let end = Math.min(this.page + 4, this.totalPage); //范围结束:得到一个 <=end 的数字
- let arr = [];
- for (let i = star; i <= end; i++) {
- arr.push(i);
- }
- return arr;
- }
- },
- props: ["total", "page_size"] //总条数 , 每页显示个数
- };
- </script>
- <style>
- </style>
-
2、导入分页组件
-
3、使用分页组件,总条数、每页显示的个数、回调函数
- total属性:总条数 (查询结果)
- page_size:每页显示个数(查询条件)
- @page_changed :每一页需要执行函数
- <pagination
- :total="searchResult.count"
- :page_size="searchMap.pageSize"
- @page_changed="pageChanged">
- </pagination>
-
4、编写回调函数,处理页面切换
- pageChanged: function(pageNum) {
- //根据第几页查询数据
- this.searchMap.pageNum = pageNum;
- //查询
- this.searchList();
- }
2、后端
Controller
- package com.czxy.controller;
-
- import com.czxy.service.SkuSearchService;
- import com.czxy.vo.BaseResult;
- import com.czxy.vo.SearchVo;
- import org.springframework.web.bind.annotation.PostMapping;
- import org.springframework.web.bind.annotation.RequestBody;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
-
- import javax.annotation.Resource;
- import java.util.Map;
-
- /**
- * @author 庭前云落
- * @Date 2020/4/15 21:39
- * @description
- */
- @RestController
- @RequestMapping("/sku")
- public class SkuSearchController {
-
- @Resource
- private SkuSearchService skuSearchService;
-
- @PostMapping("/search")
- public BaseResult findSkus(@RequestBody SearchVo searchVo) {
- if (searchVo.getCatId() == null) {
- return BaseResult.error("分类不能为空");
- }
- Map search = skuSearchService.search(searchVo);
- System.out.println(search);
- return BaseResult.ok("查询成功", search);
- }
- }
-
Service
- package com.czxy.service.impl;
-
- import com.czxy.repository.SkuRepository;
- import com.czxy.service.SkuSearchService;
- import com.czxy.vo.ReturnSku;
- import com.czxy.vo.SearchSku;
- import com.czxy.vo.SearchVo;
- import org.apache.commons.lang.StringUtils;
- import org.elasticsearch.index.query.BoolQueryBuilder;
- import org.elasticsearch.index.query.QueryBuilders;
- import org.elasticsearch.search.sort.SortBuilders;
- import org.elasticsearch.search.sort.SortOrder;
- import org.springframework.data.domain.Page;
- import org.springframework.data.domain.PageRequest;
- import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
- import org.springframework.stereotype.Service;
-
- import javax.annotation.Resource;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- /**
- * @author 庭前云落
- * @Date 2020/4/15 21:40
- * @description
- */
- @Service
- public class SkuSearchServiceImpl implements SkuSearchService {
- @Resource
- private SkuRepository skuRepository;
-
- public Map search(SearchVo searchVo){
- BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
- //分类查询
- boolQueryBuilder.must(QueryBuilders.termQuery("catId",searchVo.getCatId()));
- //关键字查询
- if(StringUtils.isNotBlank(searchVo.getKeyword())){
- boolQueryBuilder.must(QueryBuilders.matchQuery("skuName",searchVo.getKeyword()));
- }
- //品牌查询
- if(searchVo.getBrandId()!=null){
- boolQueryBuilder.must(QueryBuilders.termQuery("brandId",searchVo.getBrandId()));
- }
- //规格查询
- Map<String, String> specList = searchVo.getSpecList();
- if(specList!=null){
- for (Map.Entry<String, String> entry : specList.entrySet()) {
- String key = entry.getKey();
- String value = entry.getValue();
- boolQueryBuilder.must(QueryBuilders.termQuery("spces."+key+".keyword",value));
- }
- }
- if(searchVo.getMaxPrice()!=null&&searchVo.getMaxPrice()!=null){
- boolQueryBuilder.must(QueryBuilders.rangeQuery("price").gte(searchVo.getMinPrice()).lt(searchVo.getMaxPrice()));
- }
- NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
- queryBuilder.withQuery(boolQueryBuilder);
-
-
- if (searchVo.getSortBy()!=null){
- if(searchVo.getSortBy().equals("xl")&&searchVo.getSortWay().equals("asc")){
- //销量升序
- queryBuilder.withSort(SortBuilders.fieldSort("sellerCount").order(SortOrder.ASC));
- }else if(searchVo.getSortBy().equals("xl")&&searchVo.getSortWay().equals("desc")) {
- // 销量降序
- queryBuilder.withSort(SortBuilders.fieldSort("sellerCount").order(SortOrder.DESC));
- }else if(searchVo.getSortBy().equals("jg")&&searchVo.getSortWay().equals("asc")){
- // 价格升序
- queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
- }else if(searchVo.getSortBy().equals("jg")&&searchVo.getSortWay().equals("desc")) {
- // 价格降序
- queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
- }else if(searchVo.getSortBy().equals("pl")&&searchVo.getSortWay().equals("asc")){
- // 评论升序
- queryBuilder.withSort(SortBuilders.fieldSort("commentCount").order(SortOrder.ASC));
- }else if(searchVo.getSortBy().equals("pl")&&searchVo.getSortWay().equals("desc")) {
- // 评论降序
- queryBuilder.withSort(SortBuilders.fieldSort("commentCount").order(SortOrder.DESC));
- }else if(searchVo.getSortBy().equals("sj")&&searchVo.getSortWay().equals("asc")){
- // 上架时间
- queryBuilder.withSort(SortBuilders.fieldSort("onSaleTime").order(SortOrder.ASC));
- }else if(searchVo.getSortBy().equals("sj")&&searchVo.getSortWay().equals("desc")) {
- // 上架时间
- queryBuilder.withSort(SortBuilders.fieldSort("onSaleTime").order(SortOrder.DESC));
- }
- }
-
- // 2.2 分页
- queryBuilder.withPageable(PageRequest.of(searchVo.getPageNum() - 1 ,searchVo.getPageSize()));
-
-
- //3 查询,获取结果
- // 3.1 查询
- Page<SearchSku> pageInfo = this.skuRepository.search(queryBuilder.build());
-
- // 2.2 总条数
- long total = pageInfo.getTotalElements();
-
- // 3.3 获取返回结果 ,组装返回数据(SearchSku-->Return)
- List<SearchSku> list = pageInfo.getContent();
-
- List<ReturnSku> returnList = new ArrayList<>();
-
- for(SearchSku sku:list){
- //创建 ReturnSku对象
- ReturnSku rs = new ReturnSku();
- //依次填充数据
- rs.setId(sku.getId().intValue());
- rs.setGoodsName(sku.getSkuName());
- rs.setMidlogo(sku.getLogo());
- rs.setCommentCount(sku.getCommentCount());
- rs.setPrice(sku.getPrice());
-
- returnList.add(rs);
- }
-
- // 3.4 封装
- Map result = new HashMap();
- result.put("count" , total);
- result.put("list" ,returnList);
-
- return result;
- }
- }