电商平台spu和sku的完整设计

一、关于数据库表的设计

  • 1、商品属性表

    比如一个衣服有颜色、尺码、款式这个叫属性表

    -- ------------------------
    -- 商品属性表
    -- ------------------------
    DROP TABLE IF EXISTS `attribute`;
    CREATE TABLE `attribute` (
        `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT  COMMENT '主键id',
        `name` varchar(50) not null  COMMENT '属性名',
        `status` tinyint(4) DEFAULT 0 COMMENT '状态,0表示正常,1表示禁用',
        `remark` varchar(100) default  null comment '备注',
        `created_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
        `updated_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
        `deleted_at` timestamp(6) NULL DEFAULT NULL COMMENT '软删除时间',
        UNIQUE KEY `UK_name_deleted_at` (`name`,`deleted_at`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT = "商品属性表";
    
  • 2、商品属性值表

    上面说的颜色,可能是红色、黄色、绿色,尺码可能是S、M、L

    -- ------------------------
    -- 商品属性值表
    -- ------------------------
    DROP TABLE IF EXISTS `attribute_value`;
    CREATE TABLE `attribute_value` (
        `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT  COMMENT '主键id',
        `attribute_id` int(11) not null comment '关联到attribute表主键id',
        `name` varchar(50) not null  COMMENT '属性值',
        `status` tinyint(4) DEFAULT 0 COMMENT '状态,0表示正常,1表示禁用',
        `remark` varchar(100) default  null comment '备注',
        `created_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
        `updated_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
        `deleted_at` timestamp(6) NULL DEFAULT NULL COMMENT '软删除时间',
        UNIQUE KEY `UK_attribute_id_name_deleted_at` (`attribute_id`,`name`,`deleted_at`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT = "商品属性值表";
    
  • 3、spu表,或者直接叫商品表也可以的

    spu表比如我们说的苹果手机、华为手机、戴尔笔记本这样的叫spu

    -- ------------------------
    -- 商品spu表
    -- ------------------------
    DROP TABLE IF EXISTS `spu`;
    CREATE TABLE `spu` (
          `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT  COMMENT '主键id',
          `name` varchar(50) not null  COMMENT '商品名称',
          `keyword` varchar(50) not null  COMMENT '关键词',
          `introduction` varchar(100) not null  COMMENT '简介',
          `category_id` int(11) not null  COMMENT '关联到category表主键id',
          `brand_id` int(11) default null comment  '关联到brand表主键id',
          `pic_url` varchar(200) default  null comment  '封面图',
          `video_url` varchar(200) default  null comment  '视频地址',
          `slider_pic_urls` varchar(500) default null COMMENT '商品轮播图地址',
          `unit` int(11) default  null comment  '单位,关联到dict表主键id',
          `spec_type` tinyint(4) default 0 comment '单双规格,0表示单规格,1表示多规格(sku)',
          `price` decimal(10,2) default '0.00' comment '商品单价',
          `market_price` decimal(10,2) default '0.00' comment '商品市场价',
          `discount_price` decimal(10,2) default '0.00' comment '商品折扣价',
          `vip_price` decimal(10,2) default '0.00' comment '商品vip价',
          `cost_price` decimal(10,2) default '0.00' comment '商品成本价',
          `stock` int(11) default 0 comment '库存(如果是多规格求和)',
          `sort` int(11) DEFAULT 1 COMMENT '排序',
          `status` tinyint(4) DEFAULT 0 COMMENT '状态,0表示正常,1表示禁用',
          `is_hot` tinyint(4) DEFAULT 0 COMMENT '是否热销,0表示不是,1表示是',
          `is_benefit` tinyint(4) DEFAULT 0 COMMENT '是否优惠推荐,0表示不是,1表示是',
          `is_best` tinyint(4) DEFAULT 0 COMMENT '是否精品,0表示不是,1表示是',
          `is_new` tinyint(4) DEFAULT 0 COMMENT '是否新品,0表示不是,1表示是',
          `is_good` tinyint(4) DEFAULT 0 COMMENT '是否优品推荐,0表示不是,1表示是',
          `give_integral` int(11) DEFAULT 0 COMMENT '赠送积分',
          `sales_count` int(11) DEFAULT 0 COMMENT '销量',
          `browse_count` int(11) DEFAULT 0 COMMENT '浏览数',
          `content` text NOT NULL COMMENT '商品详情',
          `attribute` varchar(1000) default null COMMENT '销售属性数组,JSON 格式',
          `remark` varchar(100) default  null comment '备注',
          `created_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
          `updated_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
          `deleted_at` timestamp(6) NULL DEFAULT NULL COMMENT '软删除时间',
          UNIQUE KEY `UK_name_deleted_at` (`name`,`deleted_at`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT = "商品spu表";
    
  • 4、sku

    上面说的苹果手机,可能是【黄色-128GB-大陆版】,【白色-256GB-港版】这样的叫sku

    -- ------------------------
    -- 商品sku表
    -- ------------------------
    DROP TABLE IF EXISTS `sku`;
    CREATE TABLE `sku` (
           `id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT  COMMENT '主键id',
           `spu_id` int(11) NOT NULL comment '关联到spu主键id',
           `attribute_value` varchar(200) default null comment '销售属性值:用英文,拼接',
           `price` decimal(10,2) default '0.00' comment '商品单价',
           `market_price` decimal(10,2) default '0.00' comment '商品市场价',
           `discount_price` decimal(10,2) default '0.00' comment '商品折扣价',
           `vip_price` decimal(10,2) default '0.00' comment '商品vip价',
           `cost_price` decimal(10,2) default '0.00' comment '商品成本价',
           `bar_code` varchar(64)  DEFAULT NULL COMMENT 'SKU 的条形码',
           `pic_url` varchar(200)  NOT NULL COMMENT '图片地址',
           `stock` int DEFAULT NULL COMMENT '库存',
           `weight` double DEFAULT NULL COMMENT '商品重量,单位:kg 千克',
           `volume` double DEFAULT NULL COMMENT '商品体积,单位:m^3 平米',
           `sales_count` int DEFAULT NULL COMMENT '商品销量',
           `created_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
           `updated_at` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
           `deleted_at` timestamp(6) NULL DEFAULT NULL COMMENT '软删除时间'
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT = "商品sku表";
    

二、前端选择销售属性

  • 1、最后效果图

    在这里插入图片描述

  • 2、上面的数据提前手动插入到数据库中的

在这里插入图片描述


在这里插入图片描述

  • 3、后端提供一个接口先查询全部的商品属性,在根据商品属性的id去查询商品属性值,这块可以自己见代码

三、选择商品属性生成SKU

  • 1、效果展示

在这里插入图片描述

  • 2、由销售属性来生成下面的表格的方法

    const checkPropertyList = ref([]);
      /**
       * 生成sku数据
       * @param {*} skuAttribute 选中的商品属性
       */
      const generateSku = (skuAttribute) => {
        console.log(JSON.stringify(skuAttribute));
        const attrValue = [];
        // 获取选中的属性
        const checkList = [];
        for (const item of skuAttribute) {
          attrValue.push(item.attributeItem.filter((it) => item.checkList.includes(it.id)));
          checkList.push(item.id); // 选中的主键id
        }
        checkPropertyList.value = checkList;
        console.log(attrValue, '???');
        if (attrValue.length == 0) {
          tableData.value = [];
          return;
        }
        // 处理添加一个属性的时候表格置空
        if (!attrValue[attrValue.length - 1].length) {
          return;
        }
        // 循环组成sku数据
        const skuList = attrValue
          .reduce((pre, cur) => {
            let res = [];
            for (const item of pre) {
              for (const it of cur) {
                let t = item.name + ',' + it.name;
                res.push({
                  name: t,
                  url: item.url || it.url || '',
                });
              }
            }
            return res;
          })
          .map((it) => {
            const oldData = afterSku.value.find((item) => item.name == it.name);
            return {
              ...it,
              id: oldData ? oldData.id : '',
              price: oldData ? oldData.price : '', // 单价
              stock: oldData ? oldData.stock : '', // 库存
            };
          });
        tableData.value = skuList;
      };
    
  • 3、在什么时候调用上面这个方法呢?,直接监听销售属性的变化就可以

    watch(
        () => skuAttributes.value,
        (newValue) => {
          generateSku(cloneDeep(newValue));
        },
        {
          deep: true,
        }
    );
    // 监听sku表格的变化,并将当前sku进行备份
    const afterSku = ref([]);
    watch(
        () => tableData.value,
        (value) => {
          afterSku.value = cloneDeep(value);
        },
        { deep: true }
    );
    
  • 4、点击按钮提交数据给后端

    const submitHandler = async () => {
        ElMessage.success('请查看浏览器控制台');
        console.log('销售属性:', JSON.stringify(skuAttributes.value));
        console.log('表格数据:', JSON.stringify(tableData.value));
        const postData = {
          name: '苹果13',
          keyword: '苹果手机',
          introduction: 'laboris sint in',
          categoryId: 10,
          brandId: 50,
          picUrl: 'http://dummyimage.com/400x400',
          videoUrl: 'http://voanozyj.vg/suuadzgv',
          sliderPicUrls: 'http://dummyimage.com/400x400',
          unit: 25,
          specType: 79,
          price: 90,
          marketPrice: 11,
          discountPrice: 82,
          vipPrice: 32,
          costPrice: 87,
          stock: 19,
          sort: 33,
          isHot: 0,
          isBenefit: 0,
          isBest: 0,
          isNew: 0,
          isGood: 0,
          giveIntegral: 43,
          content: '手机详情',
          remark: 'magna eu laboris',
          // 过滤掉没有选择的sku属性
          attribute: JSON.stringify(skuAttributes.value),
          skuList: tableData.value.map((item) => {
            return {
              ...item,
              attributeValue: item.name,
              barCode: item.name,
              discountPrice: item.price,
              costPrice: item.price,
              picUrl: 'http://dummyimage.com/400x400',
              vipPrice: item.price,
              volume: 85,
              marketPrice: 26,
              weight: 50,
            };
          }),
        };
        console.log(JSON.stringify(postData), '提交数据');
        const data = await SkuService.createSpuApi(postData);
        console.log(data);
      };
    
  • 5、完整代码如下

    <template>
      <div class="sku">
        <el-card shadow="never">
          <el-form>
            <el-form-item label="销售属性">
              <el-card
                shadow="never"
                v-for="(item, index) of skuAttributes"
                :key="index"
                :gutter="20"
                class="sku-row"
              >
                <el-button type="danger" class="delete-row-btn" @click="deleteRowHandler(index)"
                  >删除</el-button
                >
                <el-row :gutter="10">
                  <el-col :span="2">属性名称:</el-col>
                  <el-col :span="8">
                    <el-select
                      v-model="item.id"
                      placeholder="请选择属性"
                      @change="changeAttributeHandler"
                    >
                      <el-option
                        v-for="item in attributeItem"
                        :key="item.id"
                        :label="item.name"
                        :value="item.id"
                        :disabled="checkPropertyList.includes(item.id)"
                      />
                    </el-select>
                  </el-col>
                </el-row>
                <el-row :gutter="10">
                  <el-col :span="2"> 属性值: </el-col>
                  <el-col :span="22">
                    <el-checkbox-group v-model="item.checkList">
                      <el-checkbox
                        :label="value.id"
                        v-for="(value, i) of item.attributeItem"
                        :key="i"
                        >{{ value.name }}</el-checkbox
                      >
                    </el-checkbox-group>
                  </el-col>
                </el-row>
              </el-card>
              <div>
                <el-button type="primary" @click="addSkuAttrHandler">增加销售属性</el-button>
              </div>
            </el-form-item>
          </el-form>
        </el-card>
        <!-- 下面表格 -->
        <el-card shadow="never" style="margin-top: 20px">
          <el-table :data="tableData" style="width: 100%" border>
            <el-table-column prop="name" label="销售规格" width="180" />
            <el-table-column prop="price" label="单价">
              <template #default="scope">
                <el-input v-model="scope.row.price" placeholder="单价"></el-input>
              </template>
            </el-table-column>
            <el-table-column prop="stock" label="库存">
              <template #default="scope">
                <el-input v-model="scope.row.stock" placeholder="库存"></el-input>
              </template>
            </el-table-column>
          </el-table>
          <el-button type="primary" style="margin-top: 20px" @click="submitHandler">提交数据</el-button>
        </el-card>
      </div>
    </template>
    
    <script setup>
      import { SkuService } from '@/services';
      import { ref, onMounted, watch } from 'vue';
      import { cloneDeep } from 'lodash';
      import { ElMessage } from 'element-plus';
      const skuAttributes = ref([]);
      // 添加属性
      const addSkuAttrHandler = () => {
        skuAttributes.value.push({
          id: null,
          attributeItem: [],
          checkList: [],
        });
      };
      // 删除
      const deleteRowHandler = (index) => {
        skuAttributes.value.splice(index, 1);
      };
      // 1.获取全部的销售属性
      const attributeItem = ref([]);
      const getAllAttrApi = async () => {
        const data = await SkuService.getAttributeListApi();
        attributeItem.value = data.result;
      };
      // 切换的时候
      const changeAttributeHandler = async (item) => {
        let currentItem = skuAttributes.value.find((it) => it.id == item);
        const currentIndex = skuAttributes.value.findIndex((it) => it.id == item);
        const data = await SkuService.getAttributeValueByAttributeIdApi(item);
        currentItem.attributeItem = data.result;
        currentItem.name = attributeItem.value.find((it) => it.id == item)?.name;
        // 替换之前的
        skuAttributes.value.splice(currentIndex, 1, currentItem);
      };
      // 表格数据
      const tableData = ref([]);
      const submitHandler = async () => {
        ElMessage.success('请查看浏览器控制台');
        console.log('销售属性:', JSON.stringify(skuAttributes.value));
        console.log('表格数据:', JSON.stringify(tableData.value));
        const postData = {
          name: '苹果13',
          keyword: '苹果手机',
          introduction: 'laboris sint in',
          categoryId: 10,
          brandId: 50,
          picUrl: 'http://dummyimage.com/400x400',
          videoUrl: 'http://voanozyj.vg/suuadzgv',
          sliderPicUrls: 'http://dummyimage.com/400x400',
          unit: 25,
          specType: 79,
          price: 90,
          marketPrice: 11,
          discountPrice: 82,
          vipPrice: 32,
          costPrice: 87,
          stock: 19,
          sort: 33,
          isHot: 0,
          isBenefit: 0,
          isBest: 0,
          isNew: 0,
          isGood: 0,
          giveIntegral: 43,
          content: '手机详情',
          remark: 'magna eu laboris',
          // 过滤掉没有选择的sku属性
          attribute: JSON.stringify(skuAttributes.value),
          skuList: tableData.value.map((item) => {
            return {
              ...item,
              attributeValue: item.name,
              barCode: item.name,
              discountPrice: item.price,
              costPrice: item.price,
              picUrl: 'http://dummyimage.com/400x400',
              vipPrice: item.price,
              volume: 85,
              marketPrice: 26,
              weight: 50,
            };
          }),
        };
        console.log(JSON.stringify(postData), '提交数据');
        const data = await SkuService.createSpuApi(postData);
        console.log(data);
      };
      watch(
        () => skuAttributes.value,
        (newValue) => {
          generateSku(cloneDeep(newValue));
        },
        {
          deep: true,
        }
      );
      // 监听sku表格的变化,并将当前sku进行备份
      const afterSku = ref([]);
      watch(
        () => tableData.value,
        (value) => {
          afterSku.value = cloneDeep(value);
        },
        { deep: true }
      );
      const checkPropertyList = ref([]);
      /**
       * 生成sku数据
       * @param {*} skuAttribute 选中的商品属性
       */
      const generateSku = (skuAttribute) => {
        console.log(JSON.stringify(skuAttribute));
        const attrValue = [];
        // 获取选中的属性
        const checkList = [];
        for (const item of skuAttribute) {
          attrValue.push(item.attributeItem.filter((it) => item.checkList.includes(it.id)));
          checkList.push(item.id); // 选中的主键id
        }
        checkPropertyList.value = checkList;
        console.log(attrValue, '???');
        if (attrValue.length == 0) {
          tableData.value = [];
          return;
        }
        // 处理添加一个属性的时候表格置空
        if (!attrValue[attrValue.length - 1].length) {
          return;
        }
        // 循环组成sku数据
        const skuList = attrValue
          .reduce((pre, cur) => {
            let res = [];
            for (const item of pre) {
              for (const it of cur) {
                let t = item.name + ',' + it.name;
                res.push({
                  name: t,
                  url: item.url || it.url || '',
                });
              }
            }
            return res;
          })
          .map((it) => {
            const oldData = afterSku.value.find((item) => item.name == it.name);
            return {
              ...it,
              id: oldData ? oldData.id : '',
              price: oldData ? oldData.price : '', // 单价
              stock: oldData ? oldData.stock : '', // 库存
            };
          });
        tableData.value = skuList;
      };
      onMounted(() => {
        getAllAttrApi();
      });
    </script>
    
    <style lang="scss" scoped>
      .sku-row {
        width: 100%;
        margin-bottom: 10px;
        position: relative;
        .delete-row-btn {
          position: absolute;
          right: 10px;
          top: 10px;
          cursor: pointer;
          z-index: 30;
        }
        .sku-value-item {
          margin-bottom: 10px;
          position: relative;
          .close-icon {
            position: absolute;
            right: 0;
            top: 0;
            z-index: 10;
            cursor: pointer;
            opacity: 0;
          }
          &:hover {
            .close-icon {
              opacity: 1;
            }
          }
        }
      }
    </style>
    

四、前端实现sku选择

  • 1、效果图如下

    在这里插入图片描述

  • 2、实现代码见如下

    <template>
      <div class="sku">
        <h3>iphone 13</h3>
        <div v-for="(item, index) of processAttribute" :key="index">
          <div class="title" style="margin-bottom: 10px; margin-top: 10px">{{ item.title }}</div>
          <template v-for="(item1, index1) of item.attributeItem" :key="index1">
            <el-tag
              type="success"
              :class="[
                {
                  active: item1.activity,
                  disabled: item1.disabled,
                },
              ]"
              style="margin-right: 10px; cursor: pointer"
              @click="skuClickHandler(index, index1)"
              >{{ item1.name }}</el-tag
            >
          </template>
        </div>
        <div>当前选中的库存:{{ stock }}</div>
        <div
          >价格范围:
          <span v-if="minPrice == maxPrice">{{ maxPrice }}</span>
          <span v-else>{{ minPrice }}-{{ maxPrice }}</span>
        </div>
      </div>
    </template>
    
    <script setup>
      import { onMounted } from 'vue';
      import { SkuService } from '@/services';
      import { useRoute } from 'vue-router';
      const route = useRoute();
      const skuAttribute = ref([]);
      const skuList = ref([]);
      const processAttribute = ref([]);
      const processSkuMap = ref({});
      const initData = () => {
        for (const item of skuAttribute.value) {
          let temp = {
            id: item.id,
            title: item.title,
          };
          temp.attributeItem = item.attributeItem
            .filter((it) => item.checkList.includes(it.id)) // 过滤有的属性
            .map((it) => {
              return {
                ...it,
                activity: false,
                disabled: itemquantity(it.name) <= 0, // 判断当前是否小于0的库存
                stock: itemquantity(it.name),
              };
            });
          processAttribute.value.push(temp);
        }
        // 对 skuList 数据进行加工,并存入 processSkuMap 中
        for (const item of skuList.value) {
          let combArr = arrayCombine(item.attributeValue.split(','));
          for (let j = 0; j < combArr.length; j++) {
            var key = combArr[j].join(',');
            if (processSkuMap.value[key]) {
              // 库存累加,价格添加进数组
              processSkuMap.value[key].stock += +item.stock;
              processSkuMap.value[key].prices.push(item.price);
            } else {
              processSkuMap.value[key] = {
                stock: +item.stock,
                prices: [item.price],
              };
            }
          }
        }
        // 计算下
        // skuCheck();
      };
      // 计算当前sku的库存
      const itemquantity = (item) => {
        let quantity = 0;
        skuList.value.forEach((element) => {
          var skuArr = element.attributeValue.split(',');
          if (skuArr.indexOf(item) != -1) {
            quantity += +element.stock;
          }
        });
        return quantity;
      };
      const arrayCombine = (targetArr) => {
        let resultArr = [];
        for (var n = 0; n <= targetArr.length; n++) {
          var flagArrs = getFlagArrs(targetArr.length, n);
          while (flagArrs.length) {
            var flagArr = flagArrs.shift();
            var combArr = Array(targetArr.length);
            for (var i = 0; i < targetArr.length; i++) {
              if (flagArr[i]) {
                combArr[i] = targetArr[i];
              }
            }
            resultArr.push(combArr);
          }
        }
        return resultArr;
      };
    
      const getFlagArrs = (m, n) => {
        let flagArrs = [];
        let flagArr = [];
        let isEnd = false;
        for (let i = 0; i < m; i++) {
          flagArr[i] = i < n ? 1 : 0;
        }
        flagArrs.push(flagArr.concat());
        // 当n不等于0并且m大于n的时候进入
        if (n && m > n) {
          while (!isEnd) {
            var leftCnt = 0;
            for (var i = 0; i < m - 1; i++) {
              if (flagArr[i] == 1 && flagArr[i + 1] == 0) {
                for (var j = 0; j < i; j++) {
                  flagArr[j] = j < leftCnt ? 1 : 0;
                }
                flagArr[i] = 0;
                flagArr[i + 1] = 1;
                var aTmp = flagArr.concat();
                flagArrs.push(aTmp);
                if (aTmp.slice(-n).join('').indexOf('0') == -1) {
                  isEnd = true;
                }
                break;
              }
              flagArr[i] == 1 && leftCnt++;
            }
          }
        }
        return flagArrs;
      };
      // 点击sku
      const skuClickHandler = (key1, key2) => {
        console.log(key1, key2, '点击了', processAttribute.value[key1]);
        // 如果不是被禁用的时候才执行
        if (!processAttribute.value[key1].attributeItem[key2].disabled) {
          // 选择和取消选中
          processAttribute.value[key1].attributeItem.map((item, index) => {
            item.activity = index == key2 ? !item.activity : false;
          });
          // 检查当前的sku是否有库存
          skuCheck();
          // 每次点击的时候判断禁用
          getStockPrice();
        }
      };
      // 当前选中的sku的库存机最小单价最大单价
      const stock = ref(0);
      const minPrice = ref(null);
      const maxPrice = ref(null);
      const skuCheck = () => {
        let sku = [];
        processAttribute.value.map((attr) => {
          let name = '';
          attr.attributeItem.map((item) => {
            console.log(item, '111');
            if (item.activity) {
              name = item.name;
            }
          });
          sku.push(name);
        });
        console.log(sku, '选中的的值', sku.join(','));
        stock.value = processSkuMap.value[sku.join(',')].stock;
        minPrice.value = Math.min.apply(Math, processSkuMap.value[sku.join(',')].prices);
        maxPrice.value = Math.max.apply(Math, processSkuMap.value[sku.join(',')].prices);
      };
      // 点击的时候判断库存禁用
      const getStockPrice = () => {
        processAttribute.value.map((attr) => {
          attr.attributeItem.map((item) => {
            item.disabled = itemquantity(item.name) <= 0;
          });
        });
        let count = 0;
        let i = 0;
        processAttribute.value.map((attr, index) => {
          let flag = false;
          attr.attributeItem.map((item) => {
            if (item.activity) {
              flag = true;
            }
          });
          if (!flag) {
            count += 1;
            i = index;
          }
        });
        // 当只有一组规格没选时
        if (count == 1) {
          processAttribute.value[i].attributeItem.map((item) => {
            let sku = [];
            let text = item.name;
            processAttribute.value.map((attr, index) => {
              if (index != i) {
                attr.attributeItem.map((item2) => {
                  if (item2.activity) {
                    sku.push(item2.name);
                  }
                });
              } else {
                sku.push(text);
              }
            });
            if (processSkuMap.value[sku.join(',')].stock == 0) {
              item.disabled = true;
            }
          });
        }
        // 当所有规格都有选时
        if (count == 0) {
          processAttribute.value.map((attr, index) => {
            let i = index;
            processAttribute.value[index].attributeItem.map((item) => {
              if (!item.activity) {
                let sku = [];
                let text = item.name;
                processAttribute.value.map((list, index) => {
                  if (index != i) {
                    list.attributeItem.map((item2) => {
                      if (item2.activity) {
                        sku.push(item2.name);
                      }
                    });
                  } else {
                    sku.push(text);
                  }
                });
                if (processSkuMap.value[sku.join(',')].stock == 0) {
                  item.disabled = true;
                }
              }
            });
          });
        }
      };
      const initSkuData = async () => {
        const { result } = await SkuService.getSkuByIdApi(route.query.id);
        // console.log(data);
        console.log(result.skuAttribute, '111');
        skuAttribute.value = result.skuAttribute;
        skuList.value = result.skuList;
      };
      onMounted(async () => {
        await initSkuData();
        initData();
      });
    </script>
    
    <style lang="scss" scoped>
      .sku {
        .active {
          background: skyblue;
          color: #fff;
          border: none;
        }
        .disabled {
          background: #ddd;
        }
      }
    </style>
    
    

五、具体代码见

  • 20
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
购物城的Spu-Sku数据库设计主要是为了管理品的库存和销售信息。Spu(Standard Product Unit)是品的标准产品单位,通常指的是一组具有相同特征但可能有不同规格的品,例如同一款衣服的不同颜色或尺码。Sku(Stock Keeping Unit)是品的库存管理单位,是对Spu的具体细分,用于区分不同规格或属性的品。 在数据库设计中,可以建立两个主要的表:Spu表和Sku表。Spu表用于存储品的基本信息,包括品的名称、描述、品牌、分类等。此外,可以为Spu表添加一些扩展字段,例如品的图片、销售状态等。 Sku表用于存储品的具体规格和库存信息,其中包括Spu的外键关联、品的属性、规格、价格和库存数量等。通过外键关联,可以将Sku与其对应的Spu关联起来,实现SpuSku的多对一关系。同时,可以在Sku表中添加一些扩展字段,例如品的条形码、上架时间等。 为了提高查询效率,可以在Sku表中添加索引,例如根据品的价格、库存数量、销售状态等字段进行索引,以快速获取满足条件的品信息。 此外,为了提高系统的可维护性和可扩展性,可以添加一些辅助表,例如属性表和属性值表,用于管理品的属性信息。属性表用于存储品的属性名称,属性值表用于存储属性的具体取值范围。 总之,购物城的Spu-Sku数据库设计需要考虑SpuSku之间的关联关系,以及品的基本信息和规格信息的存储和管理。通过合理的设计和优化索引,可以提高系统的查询性能和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水痕01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值