1. 程式人生 > >樂優商城(十一)商品管理

樂優商城(十一)商品管理

目錄

3.8 表單提交

3.8.1 新增提交按鈕和動畫

樣式:

        <v-layout row>
          <v-spacer></v-spacer>
            <v-btn
              :loading="loading3"
              :disabled="loading3"
              color="blue-grey"
              class="white--text mt-5"
              @click.native="loader = 'loading3'"
              @click="submit"
            >
             儲存商品資訊
              <v-icon right dark>cloud_upload</v-icon>
            </v-btn>
        </v-layout>
<style scoped>
  @-moz-keyframes loader {
    from {
      transform: rotate(0);
    }
    to {
      transform: rotate(360deg);
    }
  }
  @-webkit-keyframes loader {
    from {
      transform: rotate(0);
    }
    to {
      transform: rotate(360deg);
    }
  }
  @-o-keyframes loader {
    from {
      transform: rotate(0);
    }
    to {
      transform: rotate(360deg);
    }
  }
  @keyframes loader {
    from {
      transform: rotate(0);
    }
    to {
      transform: rotate(360deg);
    }
  }
</style>

動畫:

        loader () {
          const l = this.loader
          this[l] = !this[l]

          setTimeout(() => (this[l] = false), 2000)

          this.loader = null
        },

效果:

3.8.2 點選事件

當用戶點選儲存,就需要對頁面的資料進行整理,然後提交到後臺服務。

現在頁面包含了哪些資訊呢?先與資料庫對比,看看少什麼

  • goods:裡面包含了SPU的幾乎所有資訊

    • title:標題

    • subtitle:子標題,賣點

    • categories:分類物件陣列,需要進行整理 **

    • brandId:品牌id

    • spuDetail:商品詳情

      • packingList:包裝清單

      • afterService:售後服務

      • description:商品描述

      • 缺少全域性規格屬性specifications **

      • 缺少特有規格屬性模板spec_template **

  • skus:包含了sku列表的幾乎所有資訊

    • price:價格,需要處理為以分為單位

    • stock:庫存

    • enable:是否啟用

    • indexes:索引

    • images:圖片,陣列,需要處理為字串**

    • 缺少其它特有規格,ows_spec **

    • 缺少標題:需要根據spu的標題結合特有屬性生成 **

  • specifications:全域性規格引數的鍵值對資訊

  • specialSpec:特有規格引數資訊

在頁面繫結點選事件:

程式碼(新增和修改二合一):

        submit(){
          //1.先處理goods,用結構表示式接收,除了categories外,都接收到goodsParams中
          const {categories: [{id:cid1},{id:cid2},{id:cid3}], ...goodsParams} = this.goods;
          //2.處理全部規格引數
          //目前specifications中只有公共屬性的值,要把特有屬性的值加上,一起存入資料庫

          this.allSpecs.forEach(({group,params}) => {
            const special = this.specialSpecs;
            params.forEach(s => {
              if (!s.global){
                //如果是特殊屬性,那麼從specialSpecs中獲取selected的值賦值給option
                special.forEach(t => {
                  if (t.k === s.k){
                    s.options = t.selected
                  }
                })
              }
            })
          });
          //去掉公共屬性中的options
          const specs = this.allSpecs.map(({group,params}) => {
            const newParams = params.map(s => {
              if (s.global) {
                let {options, ...rest} = s;
                return rest;
              }else {
                return s;
              }
            });
            return {group,params:newParams}
          });
          //3.處理特有規格引數模板
          const specTemplate = {};
          this.specialSpecs.forEach(({k,selected}) => {
            specTemplate[k] = selected;
          });
          //4.處理sku
          const skus = this.skus.filter(s => s.enable).map(({price,stock,enable,images,indexes, ...rest}) => {
            //標題,在spu的title基礎上,拼接特有規格屬性值(記憶體、機身儲存、機身顏色)
            const title = goodsParams.title+" "+Object.values(rest).join(" ");
            return {
              price: this.$format(price+""),enable,indexes,title, //基本屬性
              stock: this.$format(stock+""),
              images: images && images.length > 0 ? images.join(",") : "", //圖片
              ownSpec:JSON.stringify(rest),  //特有規格引數
            }
          });
          Object.assign(goodsParams,{
            cid1,cid2,cid3, //商品分類
            skus,
          });
          goodsParams.spuDetail.specifications = JSON.stringify(specs);
          goodsParams.spuDetail.specTemplate = JSON.stringify(specTemplate);
          //console.log(goodsParams)


          this.$http({
            url:"/item/goods",
            method: this.isEdit ? 'put':'post',
            data:goodsParams
          }).then(() => {
              //成功,關閉視窗
              setTimeout(() =>{
                this.$emit('close');
                this.$message.success("儲存成功!");
                this.clear();
              },2000);
          }).catch(() => {
            this.$message.error("儲存失敗!");
          });
        }

測試提交資料:

3.8.3 後臺介面

Pojo

Spu

package com.leyou.item.pojo;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;

/**
 * @author li
 */
@Table(name = "tb_spu")
public class Spu {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long brandId;
    /**
     * 1級類目
     */
    private Long cid1;
    /**
     * 2級類目
     */
    private Long cid2;
    /**
     * 3級類目
     */
    private Long cid3;
    /**
     * 標題
     */
    private String title;
    /**
     * 子標題
     */
    private String subTitle;
    /**
     * 是否上架
     */
    private Boolean saleable;
    /**
     * 是否有效,邏輯刪除使用
     */
    private Boolean valid;
    /**
     * 建立時間
     */
    private Date createTime;
    /**
     * 最後修改時間
     */
    private Date lastUpdateTime;
}

Sku

package com.leyou.item.pojo;

import javax.persistence.*;
import java.util.Date;

/**
 * @author li
 */
@Table(name = "tb_sku")
public class Sku {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private Long spuId;
    private String title;
    private String images;
    private Long price;
    /**
     * 商品特殊規格的鍵值對
     */
    private String ownSpec;
    /**
     * 商品特殊規格的下標
     */
    private String indexes;
    /**
     * 是否有效,邏輯刪除用
     */
    private Boolean enable;
    /**
     * 建立時間
     */
    private Date createTime;
    /**
     * 最後修改時間
     */
    private Date lastUpdateTime;
    @Transient
    /**
     * @Transient 表示該屬性並非一個到資料庫表的欄位的對映,ORM框架將忽略該屬性.
     */
    private Long stock;
}

注意:這裡儲存了一個庫存欄位,在資料庫中是另外一張表儲存的,方便查詢。

Stock

ckage com.leyou.item.pojo;

import javax.persistence.Id;
import javax.persistence.Table;

/**
 * @author li
 */
@Table(name = "tb_stock")
public class Stock {

    @Id
    private Long skuId;
    /**
     * 秒殺可用庫存
     */
    private Integer seckillStock;
    /**
     * 已秒殺數量
     */
    private Integer seckillTotal;
    /**
     * 正常庫存
     */
    private Long stock;
}

Controller

四個問題:

  • 請求方式:POST

  • 請求路徑:/goods

  • 請求引數:Spu的json格式的物件,spu中包含spuDetail和Sku集合。那麼該怎麼接收?使用之前定義了一個SpuBo物件,作為業務物件,不過需要再擴充套件spuDetail和skus欄位:

package com.leyou.item.bo;

import com.leyou.item.pojo.Sku;
import com.leyou.item.pojo.Spu;
import com.leyou.item.pojo.SpuDetail;

import javax.persistence.Transient;
import java.util.List;

/**
 * @author: 98050
 * Time: 2018-08-14 22:10
 * Feature:
 */
public class SpuBo extends Spu {
    /**
     * 商品分類名稱
     */
    @Transient
    private String cname;
    /**
     * 品牌名稱
     */
    @Transient
    private String bname;

    /**
     * 商品詳情
     */
    @Transient
    private SpuDetail spuDetail;

    /**
     * sku列表
     */
    @Transient
    private List<Sku> skus;
}
  • 返回型別:無

程式碼:

    /**
     * 儲存商品
     * @param spu
     * @return
     */
    @PostMapping
    public ResponseEntity<Void> saveGoods(@RequestBody SpuBo spu){
        this.goodsService.saveGoods(spu);
        return ResponseEntity.status(HttpStatus.CREATED).build();
    }

注意:通過@RequestBody註解來接收Json請求

Mapper

這裡面涉及到的spuMapper、skuMapper、stockMapper和spuDetailMapper都是通用mapper。

Service

介面

    /**
     * 儲存商品
     * @param spu
     */
    void saveGoods(SpuBo spu);

實現類

這裡的邏輯比較複雜,除了要對SPU新增以外,還要對SpuDetail、Sku、Stock進行儲存 。

    /**
     * 儲存商品
     * @param spu
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveGoods(SpuBo spu) {
        //儲存spu
        spu.setSaleable(true);
        spu.setValid(true);
        spu.setCreateTime(new Date());
        spu.setLastUpdateTime(spu.getCreateTime());
        this.spuMapper.insert(spu);

        //儲存spu詳情
        SpuDetail spuDetail = spu.getSpuDetail();
        spuDetail.setSpuId(spu.getId());
        System.out.println(spuDetail.getSpecifications().length());
        this.spuDetailMapper.insert(spuDetail);

        //儲存sku和庫存資訊
        saveSkuAndStock(spu.getSkus(),spu.getId());
    }

    private void saveSkuAndStock(List<Sku> skus, Long id) {
        for (Sku sku : skus){
            if (!sku.getEnable()){
                continue;
            }
            //儲存sku
            sku.setSpuId(id);
            //預設不參加任何促銷
            sku.setCreateTime(new Date());
            sku.setLastUpdateTime(sku.getCreateTime());
            this.skuMapper.insert(sku);

            //儲存庫存資訊
            Stock stock = new Stock();
            stock.setSkuId(sku.getId());
            stock.setStock(sku.getStock());
            this.stockMapper.insert(stock);
        }
    }