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