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>效果圖


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM