乐优商城(十一)商品管理

目录

3.8 表单提交

3.8.1 添加提交按钮和动画

3.8.2 点击事件

3.8.3 后台接口


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);
        }
    }

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值