当前位置: 代码迷 >> 综合 >> 【B2C-爱购物商城】 开发文档 day07
  详细解决方案

【B2C-爱购物商城】 开发文档 day07

热度:60   发布时间:2023-12-13 14:06:31.0

一、sku相关概念

1、什么是sku??

SKU=Stock Keeping Unit(库存量单位).一个sku能够确定有多少库存及什么价格 --> 相当于是条形码.

什么又是spu??

SPU = Standard Product Unit (标准产品单位)SPU是商品信息聚合的最小单位,是一组可复用、易检索的标准化信息的集合,该集合描述了一个产品的特性。

例如:iPhone X 可以确定一个产品即为一个SPU。

2、sku属性及选项

一个sku能够确定库存及价格.而且知道价格会被多个sku属性影响.而且每个sku属性都是有多个sku属性选项.

一个商品有多个sku,sku的组成是由多个sku属性及它们的sku属性选项进行组合产生 注:我们买卖的sku,不是商品!

xxx旗袍 -sku

sku属性:颜色,和尺寸

sku属性选项: 颜色(红色,白色),尺寸(xl,xxl)

skus:红色xl,红色xxl.白色xl,白色xxl

3、什么是商品SKU?

商品SKU实际上就是SKU,为了避免误解和SKU属性混淆,我用商品SKU来命名,表示从属于商品的、实际销售和存储的子实体。

一个商品SKU,表示该商品关联的若干SKU属性的的属性值的某个组合所形成的子实体。

如对应上面的例子,其中的一种组合 XL + 红色 就会形成一个商品SKU。然后,我们可以在该实体上管理价格、库存、专门的图片等信息。

4、商品变种(变异)

商品变异其实就是商品SKU,只不过在某些技术文章中这样定义了。即以“变异”来表达商品SKU的生成

5、属性集

用于管理各类扩展属性的集合,其中SKU属性也是在管理范畴之内。

商品通过关联属性集而获得该属性集设置好的SKU属性,然后才可以根据这些SKU属性生成商品SKU。

属性集也成为产品类型。

常见的属性集有:服装、PC、家具、图书等。

二、前后端代码实现

1、后端根据数据库生成如下表:
在这里插入图片描述

注:这里t_product中新增了一个medias字段,因此重新生成覆盖了之前的!
在这里插入图片描述

修改生成的代码:
在这里插入图片描述

对于前端显示时间问题解决:
在这里插入图片描述

2、zuul网关配置超时时间 解决前端fallback问题
在这里插入图片描述

3、完成后端代码

public interface ProductMapper extends BaseMapper<Product> {
    List<Product> loadPageData(Page<Product> page, ProductQuery query); //加载分页数据
}
public interface IProductService extends IService<Product> {
    PageList<Product> selectPageList(ProductQuery query);//跨表高级分页
}
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
    @Autowiredprivate ProductMapper productMapper;@Autowiredprivate ProductExtMapper productExtMapper;@Overridepublic PageList<Product> selectPageList(ProductQuery query) {
    Page<Product> page = new Page<>(query.getPage(),query.getRows());List<Product> data =  productMapper.loadPageData(page,query);long total = page.getTotal();return new PageList<>(total,data);}@Overridepublic boolean insert(Product entity) {
    //添加本表信息以外,还要存放关联表entity.setCreateTime(new Date().getTime());productMapper.insert(entity);System.out.println(entity.getId());if (entity.getProductExt() != null) {
    entity.getProductExt().setProductId(entity.getId());productExtMapper.insert(entity.getProductExt());}return true;}@Overridepublic boolean updateById(Product entity) {
    //添加本表信息以外,还要存放关联表entity.setUpdateTime(new Date().getTime());productMapper.updateById(entity);//通过productId查询productExtWrapper<ProductExt> wrapper = new EntityWrapper<ProductExt>().eq("productId", entity.getId());ProductExt productExt = productExtMapper.selectList(wrapper).get(0);//把前台传递进来值设置给数据库查询出来值,并且把它修改进去ProductExt tmp = entity.getProductExt();if ( tmp!= null) {
    productExt.setDescription(tmp.getDescription());productExt.setRichContent(tmp.getRichContent());productExtMapper.updateById(productExt);}return true;}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhengqing.aigou.mapper.ProductMapper"><!-- 通用查询映射结果 --><resultMap id="BaseResultMap" type="com.zhengqing.aigou.domain.Product"><id column="id" property="id" /><result column="createTime" property="createTime" /><result column="updateTime" property="updateTime" /><result column="name" property="name" /><result column="subName" property="subName" /><result column="code" property="code" /><result column="product_type_id" property="productTypeId" /><result column="onSaleTime" property="onSaleTime" /><result column="offSaleTime" property="offSaleTime" /><result column="brand_id" property="brandId" /><result column="state" property="state" /><result column="maxPrice" property="maxPrice" /><result column="minPrice" property="minPrice" /><result column="saleCount" property="saleCount" /><result column="viewCount" property="viewCount" /><result column="commentCount" property="commentCount" /><result column="commentScore" property="commentScore" /><result column="viewProperties" property="viewProperties" /><result column="goodCommentCount" property="goodCommentCount" /><result column="commonCommentCount" property="commonCommentCount" /><result column="medias" property="medias" /><result column="badCommentCount" property="badCommentCount" /></resultMap><!--List<Product> loadPageData(Page<Product> page, ProductQuery query);--><select id="loadPageData" parameterType="ProductQuery" resultMap="productMap">SELECTp.*, pt.id ptid,pt.`name` ptname,b.id bid,b. NAME bname,pe.id peid,pe.description,pe.richContentFROMt_product pLEFT JOIN t_product_type pt ON p.product_type_id = pt.idLEFT JOIN t_brand b ON p.brand_id = b.idLEFT JOIN t_product_ext pe on p.id = pe.productIdorder by id ASC</select><resultMap id="productMap" type="Product"><!--基本信息管理--><id column="id" property="id" /><result column="createTime" property="createTime" /><result column="updateTime" property="updateTime" /><result column="name" property="name" /><result column="subName" property="subName" /><result column="code" property="code" /><result column="product_type_id" property="productTypeId" /><result column="onSaleTime" property="onSaleTime" /><result column="offSaleTime" property="offSaleTime" /><result column="brand_id" property="brandId" /><result column="state" property="state" /><result column="maxPrice" property="maxPrice" /><result column="minPrice" property="minPrice" /><result column="saleCount" property="saleCount" /><result column="viewCount" property="viewCount" /><result column="commentCount" property="commentCount" /><result column="commentScore" property="commentScore" /><result column="viewProperties" property="viewProperties" /><result column="goodCommentCount" property="goodCommentCount" /><result column="commonCommentCount" property="commonCommentCount" /><result column="medias" property="medias" /><result column="badCommentCount" property="badCommentCount" /><!--品牌和类型--><association property="brand" javaType="Brand"><id column="bid" property="id" /><result column="bname" property="name" /></association><association property="productType" javaType="ProductType"><id column="ptid" property="id" /><result column="ptname" property="name" /></association><association property="productExt" javaType="ProductExt"><id column="peid" property="id" /><result column="description" property="description" /><result column="richContent" property="richContent" /></association></resultMap></mapper>
@RestController
@RequestMapping("/product")
public class ProductController {
    @Autowiredpublic IProductService productService;/*** 保存和修改公用的* @param product 传递的实体* @return Ajaxresult转换结果*/@RequestMapping(value="/save",method= RequestMethod.POST)public AjaxResult save(@RequestBody Product product){
    try {
    if(product.getId()!=null){
    productService.updateById(product);}else{
    productService.insert(product);}return AjaxResult.me();} catch (Exception e) {
    e.printStackTrace();return AjaxResult.me().setMessage("保存对象失败!"+e.getMessage());}}/*** 删除对象信息*/@RequestMapping(value="/{id}",method=RequestMethod.DELETE)public AjaxResult delete(@PathVariable("id") Long id){
    try {
    productService.deleteById(id);return AjaxResult.me();} catch (Exception e) {
    e.printStackTrace();return AjaxResult.me().setMessage("删除对象失败!"+e.getMessage());}}//获取用户@RequestMapping(value = "/{id}",method = RequestMethod.GET)public Product get(@PathVariable("id")Long id){
    return productService.selectById(id);}/*** 查看所有的员工信息*/@RequestMapping(value = "/list",method = RequestMethod.GET)public List<Product> list(){
    return productService.selectList(null);}/*** 分页查询数据* @param query 查询对象* @return PageList 分页对象*/@RequestMapping(value = "/json",method = RequestMethod.POST)public PageList<Product> json(@RequestBody ProductQuery query){
    return productService.selectPageList(query);}
}

4、完成前端代码

①商品类型
在这里插入图片描述
拷贝代码到如下位置
在这里插入图片描述

<!-- 树状选择器 -->
<template><el-popoverref="popover"placement="bottom-start"trigger="click"@show="onShowPopover"@hide="onHidePopover"><el-treeref="tree"class="select-tree"highlight-current:style="`min-width: ${treeWidth}`":data="data":props="props":expand-on-click-node="false":filter-node-method="filterNode":default-expand-all="false"@node-click="onClickNode"></el-tree><el-inputslot="reference"ref="input"v-model="labelModel"clearable:style="`width: ${width}px`":class="{ 'rotate': showStatus }"suffix-icon="el-icon-arrow-down":placeholder="placeholder"></el-input></el-popover>
</template><script>export default {name: 'Pagination',props: {// 接收绑定参数value: String,// 输入框宽度width: String,// 选项数据options: {type: Array,required: true,},// 输入框占位符placeholder: {type: String,required: false,default: '请选择',},// 树节点配置选项props: {type: Object,required: false,default: () => ({parent: 'pid',value: 'id',label: 'name',children: 'children',}),},},// 设置绑定参数model: {prop: 'value',event: 'selected',},computed: {// 是否为树状结构数据dataType() {const jsonStr = JSON.stringify(this.options);return jsonStr.indexOf(this.props.children) !== -1;},// 若非树状结构,则转化为树状结构数据data() {return this.dataType ? this.options : this.switchTree();},},watch: {labelModel(val) {if (!val) {this.valueModel = '';}this.$refs.tree.filter(val);},value(val) {this.labelModel = this.queryTree(this.data, val);},},data() {return {// 树状菜单显示状态showStatus: false,// 菜单宽度treeWidth: 'auto',// 输入框显示值labelModel: '',// 实际请求传值valueModel: '0',};},created() {// 检测输入框原有值并显示对应 labelif (this.value) {this.labelModel = this.queryTree(this.data, this.value);}// 获取输入框宽度同步至树状菜单宽度this.$nextTick(() => {this.treeWidth = `${(this.width || this.$refs.input.$refs.input.clientWidth) - 24}px`;});},methods: {// 单击节点onClickNode(node) {this.labelModel = node[this.props.label];this.valueModel = node[this.props.value];this.onCloseTree();},// 偏平数组转化为树状层级结构switchTree() {return this.cleanChildren(this.buildTree(this.options, '0'));},// 隐藏树状菜单onCloseTree() {this.$refs.popover.showPopper = false;},// 显示时触发onShowPopover() {this.showStatus = true;this.$refs.tree.filter(false);},// 隐藏时触发onHidePopover() {this.showStatus = false;this.$emit('selected', this.valueModel);},// 树节点过滤方法filterNode(query, data) {if (!query) return true;return data[this.props.label].indexOf(query) !== -1;},// 搜索树状数据中的 IDqueryTree(tree, id) {let stark = [];stark = stark.concat(tree);while (stark.length) {const temp = stark.shift();if (temp[this.props.children]) {stark = stark.concat(temp[this.props.children]);}if (temp[this.props.value] === id) {return temp[this.props.label];}}return '';},// 将一维的扁平数组转换为多层级对象buildTree(data, id = '0') {const fa = (parentId) => {const temp = [];for (let i = 0; i < data.length; i++) {const n = data[i];if (n[this.props.parent] === parentId) {n.children = fa(n.rowGuid);temp.push(n);}}return temp;};return fa(id);},// 清除空 children项cleanChildren(data) {const fa = (list) => {list.map((e) => {if (e.children.length) {fa(e.children);} else {delete e.children;}return e;});return list;};return fa(data);},},};
</script><style>.el-input.el-input--suffix {cursor: pointer;overflow: hidden;}.el-input.el-input--suffix.rotate .el-input__suffix {transform: rotate(180deg);}.select-tree {max-height: 350px;overflow-y: scroll;}/* 菜单滚动条 */.select-tree::-webkit-scrollbar {z-index: 11;width: 6px;}.select-tree::-webkit-scrollbar-track,.select-tree::-webkit-scrollbar-corner {background: #fff;}.select-tree::-webkit-scrollbar-thumb {border-radius: 5px;width: 6px;background: #b4bccc;}.select-tree::-webkit-scrollbar-track-piece {background: #fff;width: 6px;}
</style>

注:这坨代码很关键
在这里插入图片描述

然后在product.vue中引入
在这里插入图片描述

使用:
在这里插入图片描述

② vue富文本编辑器
在这里插入图片描述

安装:npm install vue-quill-editor --save
在这里插入图片描述
引入:
在这里插入图片描述
使用:
在这里插入图片描述


源码和文档: https://pan.baidu.com/s/1PT3FDUAvCm64oxG53lQdNw