• 021 商品规格管理


    1.商品规格数据结构

    乐优商城是一个全品类的电商网站,因此商品的种类繁多,每一件商品,其属性又有差别。为了更准确描述商品及细分差别,抽象出两个概念:SPU和SKU,了解一下:

    (1)SPU和SKU

    SPU:Standard Product Unit (标准产品单位) ,一组具有共同属性的商品集

    SKU:Stock Keeping Unit(库存量单位),SPU商品集因具体特性不同而细分的每个商品

    以图为例来看:

    • 本页的 华为Mate10 就是一个商品集(SPU)

    • 因为颜色、内存等不同,而细分出不同的Mate10,如亮黑色128G版。(SKU)

    可以看出:

    • SPU是一个抽象的商品集概念,为了方便后台的管理。

    • SKU才是具体要销售的商品,每一个SKU的价格、库存可能会不一样,用户购买的是SKU而不是SPU

    (2)规格参数表

    <1>表结构

    我们看下规格参数的格式:

    可以看到规格参数是分组的,每一组都有多个参数键值对。不过对于规格参数的模板而言,其值现在是不确定的,不同的商品值肯定不同,模板中只要保存组信息、组内参数信息即可。

    因此我们设计了两张表:

    • tb_spec_group:组,与商品分类关联

    • tb_spec_param:参数名,与组关联,一对多

    <2>规格组

    规格参数分组表:tb_spec_group

    CREATE TABLE `tb_spec_group` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `cid` bigint(20) NOT NULL COMMENT '商品分类id,一个分类下有多个规格组',
      `name` varchar(50) NOT NULL COMMENT '规格组的名称',
      PRIMARY KEY (`id`),
      KEY `key_category` (`cid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COMMENT='规格参数的分组表,每个商品分类下有多个规格参数组';

    规格组有3个字段:

    • id:主键

    • cid:商品分类id,一个分类下有多个模板

    • name:该规格组的名称。

    <3>规格参数

    规格参数表:tb_spec_param

    CREATE TABLE `tb_spec_param` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
      `cid` bigint(20) NOT NULL COMMENT '商品分类id',
      `group_id` bigint(20) NOT NULL,
      `name` varchar(255) NOT NULL COMMENT '参数名',
      `numeric` tinyint(1) NOT NULL COMMENT '是否是数字类型参数,true或false',
      `unit` varchar(255) DEFAULT '' COMMENT '数字类型参数的单位,非数字类型可以为空',
      `generic` tinyint(1) NOT NULL COMMENT '是否是sku通用属性,true或false',
      `searching` tinyint(1) NOT NULL COMMENT '是否用于搜索过滤,true或false',
      `segments` varchar(1000) DEFAULT '' COMMENT '数值类型参数,如果需要搜索,则添加分段间隔值,如CPU频率间隔:0.5-1.0',
      PRIMARY KEY (`id`),
      KEY `key_group` (`group_id`),
      KEY `key_category` (`cid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COMMENT='规格参数组下的参数名';

    通用属性:

      用一个布尔类型字段来标记是否为通用:

    • generic来标记是否为通用属性:

      • true:代表通用属性

      • false:代表sku特有属性

    搜索过滤:

      与搜索相关的有两个字段:

    • searching:标记是否用作过滤

      • true:用于过滤搜索

      • false:不用于过滤

    • segments:某些数值类型的参数,在搜索时需要按区间划分,这里提前确定好划分区间

      • 比如电池容量,0~2000mAh,2000mAh~3000mAh,3000mAh~4000mAh

    数据类型:

      某些规格参数可能为数值类型,这样的数据才需要划分区间,我们有两个字段来描述:

    • numberic:是否为数值类型

      • true:数值类型

      • false:不是数值类型

    • unit:参数的单位

     (3)表关系总结:

     2.商品规格参数管理

     (1)页面布局

    <1>整体布局

    打开规格参数页面,看到如下内容:

    因为规格是跟商品分类绑定的,因此首先会展现商品分类树,并且提示你要选择商品分类,才能看到规格参数的模板。一起了解下页面的实现:

    页面结构(Specification.vue):

    这里使用了v-layout来完成页面布局,并且添加了row属性,代表接下来的内容是行布局(左右)。

    可以看出页面分成2个部分:

    • <v-flex xs3>:左侧,内部又分上下两部分:商品分类树及标题

      • v-card-title:标题部分,这里是提示信息,告诉用户要先选择分类,才能看到模板

      • v-tree:这里用到的是我们之前讲过的树组件,展示商品分类树,

    • <v-flex xs9 class="px-1">:右侧:内部是规格参数展示

    (2)规格组的查询

    <1>树节点的点击事件

    当我们点击树节点时,要将v-dialog打开,因此必须绑定一个点击事件:(Specification.vue)

    我们来看下handleClick方法:(Specification.vue)

    点击事件发生时,发生了两件事:

    • 记录当前选中的节点,选中的就是商品分类

    • showGroup被置为true,则规格组就会显示了。

    同时,我们把被选中的节点(商品分类)的id传递给了SpecGroup组件:(Specification.vue)

     

    <2>页面查询规格组

    来看下SpecGroup.vue中的实现:

    我们查看页面控制台,可以看到请求已经发出:

    <3>后端代码

    最终代码截图:

    实体类:

    service业务代码:

    (1)实体类:SpecGroup

    package lucky.leyou.item.domain;
    
    import javax.persistence.*;
    import java.util.List;
    
    @Table(name = "tb_spec_group")
    public class SpecGroup {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private Long cid;
    
        private String name;
    
        @Transient
        private List<SpecParam> params;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public Long getCid() {
            return cid;
        }
    
        public void setCid(Long cid) {
            this.cid = cid;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<SpecParam> getParams() {
            return params;
        }
    
        public void setParams(List<SpecParam> params) {
            this.params = params;
        }
    }

    实体类:SpecParam

    package lucky.leyou.item.domain;
    
    import javax.persistence.*;
    
    @Table(name = "tb_spec_param")
    public class SpecParam {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private Long cid;
        private Long groupId;
        private String name;
        @Column(name = "`numeric`")
        private Boolean numeric;
        private String unit;
        private Boolean generic;
        private Boolean searching;
        private String segments;
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public Long getCid() {
            return cid;
        }
    
        public void setCid(Long cid) {
            this.cid = cid;
        }
    
        public Long getGroupId() {
            return groupId;
        }
    
        public void setGroupId(Long groupId) {
            this.groupId = groupId;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Boolean getNumeric() {
            return numeric;
        }
    
        public void setNumeric(Boolean numeric) {
            this.numeric = numeric;
        }
    
        public String getUnit() {
            return unit;
        }
    
        public void setUnit(String unit) {
            this.unit = unit;
        }
    
        public Boolean getGeneric() {
            return generic;
        }
    
        public void setGeneric(Boolean generic) {
            this.generic = generic;
        }
    
        public Boolean getSearching() {
            return searching;
        }
    
        public void setSearching(Boolean searching) {
            this.searching = searching;
        }
    
        public String getSegments() {
            return segments;
        }
    
        public void setSegments(String segments) {
            this.segments = segments;
        }
    }

    (2)在leyou-item-service中编写业务:

    <1>mapper

    SpecParamMapper

    package lucky.leyou.item.mapper;
    
    import lucky.leyou.item.domain.SpecParam;
    import tk.mybatis.mapper.common.Mapper;
    
    public interface SpecParamMapper extends Mapper<SpecParam> {
    }

    SpecGroupMapper

    package lucky.leyou.item.mapper;
    
    import lucky.leyou.item.domain.SpecGroup;
    import tk.mybatis.mapper.common.Mapper;
    
    public interface SpecGroupMapper extends Mapper<SpecGroup> {
    }

    <2>controller

    package lucky.leyou.item.controller;
    
    import lucky.leyou.item.domain.SpecGroup;
    import lucky.leyou.item.service.ISpecificationService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Controller;
    import org.springframework.util.CollectionUtils;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import java.util.List;
    
    @Controller
    @RequestMapping(path = "/spec")
    public class SpecificationController {
    
        @Autowired
        private ISpecificationService specificationService;
    
        /**
         * 根据分类id查询分组
         * @param cid
         * @return
         */
        @GetMapping(path = "/groups/{cid}")
        public ResponseEntity<List<SpecGroup>> queryGroupsByCid(@PathVariable("cid")Long cid){
            List<SpecGroup> groups = this.specificationService.queryGroupsByCid(cid);
            if (CollectionUtils.isEmpty(groups)){
                return ResponseEntity.notFound().build();
            }
            return ResponseEntity.ok(groups);
        }
    }

    <3>service

    接口

    package lucky.leyou.item.service;
    
    import lucky.leyou.item.domain.SpecGroup;
    
    import java.util.List;
    
    public interface ISpecificationService {
    
        /**
         * 根据分类id查询分组
         * @param cid
         * @return
         */
        public List<SpecGroup> queryGroupsByCid(Long cid);
    }

    实现类

    package lucky.leyou.item.service.impl;
    
    import lucky.leyou.item.domain.SpecGroup;
    import lucky.leyou.item.mapper.SpecGroupMapper;
    import lucky.leyou.item.mapper.SpecParamMapper;
    import lucky.leyou.item.service.ISpecificationService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class SpecificationServiceImpl implements ISpecificationService {
        @Autowired
        private SpecGroupMapper specGroupMapper;
    
        @Autowired
        private SpecParamMapper specParamMapper;
    
        /**
         * 根据分类id查询分组
         * @param cid
         * @return
         */
        @Override
        public List<SpecGroup> queryGroupsByCid(Long cid) {
            SpecGroup specGroup = new SpecGroup();
            specGroup.setCid(cid);
            return this.specGroupMapper.select(specGroup);
        }
    }

    <4>效果图

    (3)规格参数查询

    <1>表格切换

    当我们点击规格组,会切换到规格参数显示,肯定是在规格组中绑定了点击事件:

    我们看下事件处理:

    可以看到这里是使用了父子通信,子组件触发了select事件:

    再来看下父组件的事件绑定:

    事件处理:

    这里我们记录了选中的分组,并且把标记设置为false,这样规格组就不显示了,而是显示:SpecParam

    并且,我们把group也传递到spec-param组件:

     

    <2>页面查询规格参数

    我们来看SpecParam.vue的实现:

     查看页面控制台,发现请求已经发出:

    <3>后台代码

    (1)在SpecificationController类中添加如下方法

    /**
         * 根据条件查询规格参数
         * @param gid
         * @return
         */
        @GetMapping(path = "/params")
        public ResponseEntity<List<SpecParam>> queryParams(@RequestParam("gid")Long gid){
            List<SpecParam>  params = this.specificationService.queryParams(gid);
            if (CollectionUtils.isEmpty(params)){
                return ResponseEntity.notFound().build();
            }
            return ResponseEntity.ok(params);
        }

    (2)在ISpecificationService及其实现类中添加如下方法

    /**
         * 根据条件查询规格参数
         * @param gid
         * @return
         */
        @Override
        public List<SpecParam> queryParams(Long gid) {
            SpecParam param = new SpecParam();
            param.setGroupId(gid);
            return this.specParamMapper.select(param);
        }

    <4>重启微服务

    <5>效果图

  • 相关阅读:
    css常用属性
    html常用标签
    通讯录管理
    消息推送
    企业微信API开发前准备
    毕业设计-基于图像处理的垃圾分类系统2020.03.17
    毕业设计-基于图像处理的垃圾分类系统2020.03.15
    毕业设计-基于图像处理的垃圾分类系统2020.03.14
    毕业设计-基于图像处理的垃圾分类系统2020.03.13
    毕业设计-基于图像处理的垃圾分类系统2020.03.12
  • 原文地址:https://www.cnblogs.com/luckyplj/p/11526021.html
Copyright © 2020-2023  润新知