فهرست منبع

feature(uniapp分类): 商品创建功能以及查询功能正常使用

luowenfeng 2 سال پیش
والد
کامیت
617573a59b

+ 24 - 0
sql/optional/mall/mall.sql

@@ -298,3 +298,27 @@ INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `
 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'market:banner:create', 3, 2, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'market:banner:update', 3, 3, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'market:banner:delete', 3, 4, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
+
+alter table product_spu add `code` varchar(128) COMMENT '商品编码';
+alter table product_spu add  total_stock int COMMENT '总库存';
+alter table product_spu add  warn_stock int COMMENT '预警预存';
+alter table product_spu add  show_stock int COMMENT '是否展示库存';
+alter table product_spu add  sales_count int COMMENT '商品销量';
+alter table product_spu add  virtual_sales_count int COMMENT '虚拟销量';
+alter table product_spu add  click_count int COMMENT '商品点击量';
+alter table product_spu add  banner_url  varchar(128) COMMENT '主图地址';
+alter table product_spu add  spec_type int COMMENT '规格类型';
+alter table product_spu add  brand_id int COMMENT '商品品牌编号';
+alter table product_spu add  video_url varchar(128) COMMENT '商品视频';
+alter table product_spu add  min_price int COMMENT '最小价格,单位使用:分';
+alter table product_spu add  max_price int COMMENT '最大价格,单位使用:分';
+alter table product_spu add  market_price int COMMENT '市场价,单位使用:分';
+
+
+alter table product_sku add `name` varchar(128) COMMENT '商品 SKU 名字';
+alter table product_sku add `stock` int COMMENT '库存';
+alter table product_sku add `weight` double COMMENT '商品重量';
+alter table product_sku add `volume` double COMMENT '商品体积';
+
+
+alter table product_sku DROP `original_price`;

+ 14 - 6
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java

@@ -27,16 +27,16 @@ public class ProductSkuBaseVO {
     @NotNull(message = "销售价格,单位:分不能为空")
     private Integer price;
 
-    @ApiModelProperty(value = "价, 单位: 分", required = true)
-    @NotNull(message = "价, 单位: 分不能为空")
-    private Integer originalPrice;
+    @ApiModelProperty(value = "市场价, 单位: 分", required = true)
+    @NotNull(message = "市场价, 单位: 分不能为空")
+    private Integer marketPrice;
 
     @ApiModelProperty(value = "成本价,单位: 分", required = true)
     @NotNull(message = "成本价,单位: 分不能为空")
     private Integer costPrice;
 
-    @ApiModelProperty(value = "条形码", required = true)
-    @NotNull(message = "条形码不能为空")
+    @ApiModelProperty(value = "条形码")
+//    @NotNull(message = "条形码不能为空")
     private String barCode;
 
     @ApiModelProperty(value = "图片地址", required = true)
@@ -46,7 +46,15 @@ public class ProductSkuBaseVO {
     @ApiModelProperty(value = "状态: 0-正常 1-禁用")
     private Integer status;
 
-    // TODO @franky 要有 swagger 注解
+    @ApiModelProperty(value = "库存")
+    private Integer stock;
+
+    @ApiModelProperty(value = "商品重量,单位:kg 千克")
+    private Double weight;
+
+    @ApiModelProperty(value = "商品体积,单位:m^3 平米")
+    private Double volume;
+
     @Data
     public static class Property {
         @NotNull(message = "规格属性名id不能为空")

+ 76 - 9
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java

@@ -1,5 +1,8 @@
 package cn.iocoder.yudao.module.product.controller.admin.spu.vo;
 
+import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
+import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
+import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
@@ -16,6 +19,11 @@ public class ProductSpuBaseVO {
     @ApiModelProperty(value = "商品名称")
     private String name;
 
+    /**
+     * 商品编码
+     */
+    private String code;
+
     @ApiModelProperty(value = "卖点", required = true)
     @NotNull(message = "卖点不能为空")
     private String sellPoint;
@@ -24,28 +32,87 @@ public class ProductSpuBaseVO {
     @NotNull(message = "描述不能为空")
     private String description;
 
+    /**
+     * 商品品牌编号
+     *
+     * 关联 {@link ProductBrandDO#getId()}
+     */
+    private Long brandId;
+
     @ApiModelProperty(value = "分类id", required = true)
     @NotNull(message = "分类id不能为空")
     private Long categoryId;
 
+    /**
+     * 商品主图
+     */
+    private String bannerUrl;
+
     @ApiModelProperty(value = "商品主图地址,* 数组,以逗号分隔,最多上传15张", required = true)
     @NotNull(message = "商品主图地址,* 数组,以逗号分隔,最多上传15张不能为空")
     private List<String> picUrls;
 
+    /**
+     * 商品视频
+     */
+    private String videoUrl;
+
+    /**
+     * 规格类型
+     *
+     * 枚举 {@link ProductSpuSpecTypeEnum}
+     */
+    private Integer specType;
+
     @ApiModelProperty(value = "排序字段", required = true)
     @NotNull(message = "排序字段不能为空")
     private Integer sort;
-
-    @ApiModelProperty(value = "点赞初始人数")
-    private Integer likeCount;
-
-    @ApiModelProperty(value = "价格 单位使用:分")
-    private Integer price;
-
-    @ApiModelProperty(value = "库存数量")
-    private Integer quantity;
+    /**
+     * 最小价格,单位使用:分
+     *
+     * 基于其对应的 {@link ProductSkuDO#getPrice()} 最小值
+     */
+    private Integer minPrice;
+    /**
+     * 最大价格,单位使用:分
+     *
+     * 基于其对应的 {@link ProductSkuDO#getPrice()} 最大值
+     */
+    private Integer maxPrice;
+    /**
+     * 市场价,单位使用:分
+     *
+     * 基于其对应的 {@link ProductSkuDO#getMarketPrice()} 最大值
+     */
+    private Integer marketPrice;
+    /**
+     * 总库存
+     *
+     * 基于其对应的 {@link ProductSkuDO#getStock()} 求和
+     */
+    private Integer totalStock;
+    /**
+     * 预警预存
+     */
+    private Integer warnStock;
+    /**
+     * 是否展示库存
+     */
+    private Boolean showStock;
 
     @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)")
     private Integer status;
 
+    /**
+     * 商品销量
+     */
+    private Integer salesCount;
+    /**
+     * 虚拟销量
+     */
+    private Integer virtualSalesCount;
+    /**
+     * 商品点击量
+     */
+    private Integer clickCount;
 }

+ 2 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java

@@ -49,7 +49,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
         //插入属性值
         List<ProductPropertyValueCreateReqVO> propertyValueList = createReqVO.getPropertyValueList();
         List<ProductPropertyValueDO> productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
-        productPropertyValueDOList.stream().forEach(x-> x.setPropertyId(property.getId()));
+        productPropertyValueDOList.forEach(x-> x.setPropertyId(property.getId()));
         productPropertyValueMapper.insertBatch(productPropertyValueDOList);
         // 返回
         return property.getId();
@@ -67,7 +67,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
         productPropertyValueMapper.deletePropertyValueByPropertyId(updateReqVO.getId());
         List<ProductPropertyValueCreateReqVO> propertyValueList = updateReqVO.getPropertyValueList();
         List<ProductPropertyValueDO> productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
-        productPropertyValueDOList.stream().forEach(x-> x.setPropertyId(updateReqVO.getId()));
+        productPropertyValueDOList.forEach(x-> x.setPropertyId(updateReqVO.getId()));
         productPropertyValueMapper.insertBatch(productPropertyValueDOList);
     }
 

+ 8 - 4
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java

@@ -2,9 +2,14 @@ package cn.iocoder.yudao.module.product.service.sku;
 
 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyCreateReqVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueCreateReqVO;
 import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
-import cn.iocoder.yudao.module.product.controller.admin.sku.vo.*;
+import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
+import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuPageReqVO;
+import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuUpdateReqVO;
 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
 import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
@@ -84,8 +89,6 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         return productSkuMapper.selectPage(pageReqVO);
     }
 
-    // TODO @franky:这个方法,貌似实现的还是有点问题哈。例如说,throw 异常,后面还执行逻辑~
-    // TODO @艿艿 咳咳,throw 那里我是偷懒省略了{},哈哈,我加上,然后我调试下,在优化下
     @Override
     public void validateSkus(List<ProductSkuCreateReqVO> list) {
         List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> p.getProperties().stream()).collect(Collectors.toList());
@@ -99,8 +102,9 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         skuPropertyList.forEach(p -> {
             ProductPropertyRespVO productPropertyRespVO = propertyMap.get(p.getPropertyId());
             // 如果对应的属性名不存在或属性名下的属性值集合为空,给出提示
-            if (null == productPropertyRespVO || productPropertyRespVO.getPropertyValueList().isEmpty())
+            if (null == productPropertyRespVO || productPropertyRespVO.getPropertyValueList().isEmpty()) {
                 throw ServiceExceptionUtil.exception(PROPERTY_NOT_EXISTS);
+            }
             // 判断改属性名对应的属性值是否存在,不存在,给出提示
             if (!productPropertyRespVO.getPropertyValueList().stream().map(ProductPropertyValueRespVO::getId).collect(Collectors.toSet()).contains(p.getValueId())) {
                 throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS);

+ 0 - 240
yudao-ui-admin/src/views/mall/product/spu/index.vue

@@ -181,246 +181,6 @@
 <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body >
   <save @closeDialog="open = false"/>
 </el-dialog>
-    <!-- 对话框(添加 / 修改) -->
-    <!-- <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="商品名称" prop="name">
-          <el-input v-model="form.name" placeholder="请输入商品名称" />
-        </el-form-item>
-        <el-form-item label="卖点" prop="sellPoint">
-          <el-input v-model="form.sellPoint" placeholder="请输入卖点" />
-        </el-form-item>
-        <el-form-item label="描述">
-          <editor v-model="form.description" :min-height="192" />
-        </el-form-item>
-        <el-form-item label="分类id" prop="categoryIds">
-          <el-cascader
-            v-model="form.categoryIds"
-            placeholder="请输入分类id"
-            style="width: 100%"
-            :options="categoryList"
-            :props="propName"
-            clearable
-          ></el-cascader>
-        </el-form-item>
-        <el-form-item label="商品主图地址" prop="picUrls">
-          <ImageUpload v-model="form.picUrls" :limit="10" />
-        </el-form-item>
-        <el-form-item label="商品规格">
-          <el-button size="mini" @click="shopTagInput()">添加规格</el-button>
-          <div v-for="(tag, tagIndex) in skuTags" :key="tagIndex">
-            <span>{{ tag.name }}</span>
-            <el-button
-              style="margin-left: 10px"
-              class="button-new-tag"
-              type="text"
-              icon="el-icon-delete"
-              @click="removeTag(tagIndex)"
-              >删除
-            </el-button>
-            <br />
-            <el-tag
-              v-for="(tagItem, tagItemIndex) in tag.selectValues"
-              :key="tagItemIndex"
-              style="margin-right: 10px"
-              :disable-transitions="false"
-            >
-              {{ tagItem }}
-            </el-tag> -->
-            <!--            <el-input-->
-            <!--              class="input-new-tag"-->
-            <!--              v-if="tagItemInputs[tagIndex] && tagItemInputs[tagIndex].visible"-->
-            <!--              v-model="tagItemInputs[tagIndex].value"-->
-            <!--              :ref="`saveTagInput${tagIndex}`"-->
-            <!--              size="small"-->
-            <!--              @keyup.enter.native="handleInputConfirm(tagIndex)"-->
-            <!--              @blur="handleInputConfirm(tagIndex)">-->
-            <!--            </el-input>-->
-          <!-- </div>
-        </el-form-item>
-        <el-form-item label="规格名" v-show="isShowTagInput">
-          <el-col :span="8">
-            <el-select
-              v-model="addTagInput.name"
-              filterable
-              allow-create
-              default-first-option
-              placeholder="请选择"
-              @change="handleTagClick"
-            >
-              <el-option
-                v-for="item in unUseTags"
-                :key="item.id"
-                :label="item.name"
-                :value="item.name"
-              >
-              </el-option>
-            </el-select>
-          </el-col>
-        </el-form-item>
-        <el-form-item label="规格值" v-show="isShowTagInput">
-          <el-col :span="8">
-            <el-select
-              v-model="addTagInput.selectValues"
-              multiple
-              filterable
-              allow-create
-              default-first-option
-              placeholder="请选择"
-            >
-              <el-option
-                v-for="item in dbTagValues"
-                :key="item.id"
-                :label="item.name"
-                :value="item.name"
-              >
-              </el-option>
-            </el-select>
-          </el-col>
-        </el-form-item>
-        <el-form-item>
-          <el-button
-            size="mini"
-            type="primary"
-            @click="addTag()"
-            v-show="isShowTagInput"
-            >确定</el-button
-          >
-          <el-button size="mini" @click="hideTagInput()" v-show="isShowTagInput"
-            >取消</el-button
-          >
-        </el-form-item>
-        <el-form-item v-if="form.skus.length > 0">
-          <el-table
-            :data="form.skus"
-            border
-            style="width: 100%; margin-top: 20px"
-            :span-method="tableSpanMethod"
-          >
-            <el-table-column
-              v-for="(leftTitle, index) in skuTags"
-              :key="index"
-              :label="leftTitle.name"
-            >
-              <template slot-scope="scope">
-                {{ scope.row.propertyChildNames[index] }}
-              </template>
-            </el-table-column>
-            <el-table-column
-              v-if="skuTags.length"
-              prop="picUrl"
-              label="sku图片"
-              width="180"
-            >
-              <template slot-scope="scope">
-                <ImageUpload v-model="scope.row.picUrl" :limit="1">
-                </ImageUpload>
-              </template>
-            </el-table-column>
-            <el-table-column
-              prop="prodName"
-              label="条形码"
-              width="250"
-              v-if="skuTags.length"
-            >
-              <template slot-scope="scope">
-                <el-input
-                  v-model="scope.row.barCode"
-                  type="textarea"
-                  :disabled="scope.row.status == 1"
-                ></el-input>
-              </template>
-            </el-table-column>
-            <el-table-column prop="price" label="销售价">
-              <template slot-scope="scope">
-                <el-input-number
-                  size="small"
-                  v-model="scope.row.price"
-                  controls-position="right"
-                  :precision="2"
-                  :max="1000000000"
-                  :min="0.01"
-                  :disabled="scope.row.status == 1"
-                >
-                </el-input-number>
-              </template>
-            </el-table-column>
-            <el-table-column prop="oriPrice" label="成本价">
-              <template slot-scope="scope">
-                <el-input-number
-                  size="small"
-                  v-model="scope.row.costPrice"
-                  controls-position="right"
-                  :precision="2"
-                  :max="1000000000"
-                  :min="0.01"
-                  :disabled="scope.row.status == 1"
-                >
-                </el-input-number>
-              </template>
-            </el-table-column>
-            <el-table-column prop="oriPrice" label="原价">
-              <template slot-scope="scope">
-                <el-input-number
-                  size="small"
-                  v-model="scope.row.originalPrice"
-                  controls-position="right"
-                  :precision="2"
-                  :max="1000000000"
-                  :min="0.01"
-                  :disabled="scope.row.status == 1"
-                >
-                </el-input-number>
-              </template>
-            </el-table-column>
-            <el-table-column label="操作">
-              <template slot-scope="scope">
-                <el-button
-                  type="text"
-                  size="small"
-                  @click="changeSkuStatus(`${scope.$index}`)"
-                  v-if="scope.row.status === 0"
-                >
-                  正常
-                </el-button>
-                <el-button
-                  type="text"
-                  size="small"
-                  @click="changeSkuStatus(`${scope.$index}`)"
-                  v-else
-                  >已禁用</el-button
-                >
-              </template>
-            </el-table-column>
-          </el-table>
-        </el-form-item>
-        <el-form-item label="排序字段" prop="sort">
-          <el-input v-model="form.sort" placeholder="请输入排序字段" />
-        </el-form-item>
-        <el-form-item label="点赞初始人数" prop="likeCount">
-          <el-input v-model="form.likeCount" placeholder="请输入点赞初始人数" />
-        </el-form-item>
-        <el-form-item label="价格 单位使用:分" prop="price">
-          <el-input
-            v-model="form.price"
-            placeholder="请输入价格 单位使用:分"
-          />
-        </el-form-item>
-        <el-form-item label="库存数量" prop="quantity">
-          <el-input v-model="form.quantity" placeholder="请输入库存数量" />
-        </el-form-item>
-        <el-form-item label="上下架状态" prop="status">
-          <el-radio-group v-model="form.status">
-            <el-radio label="0">上架</el-radio>
-            <el-radio label="1">下架</el-radio>
-          </el-radio-group>
-        </el-form-item>
-      </el-form>
-      <div slot="footer" class="dialog-footer">
-        <el-button type="primary" @click="submitForm">确 定</el-button>
-        <el-button @click="cancel">取 消</el-button>
-      </div>
-    </el-dialog> -->
   </div>
 </template>
 

+ 150 - 128
yudao-ui-admin/src/views/mall/product/spu/save.vue

@@ -1,26 +1,6 @@
 <template>
   <div class="container">
-    <el-dialog
-      title="请输入规格值,多个请换行"
-      :visible.sync="dialogForSpec"
-      append-to-body
-      width="400px"
-      @close="dialogForSpec = false; specValue = null"
-    >
-      <el-input
-        v-model="specValue"
-        type="textarea"
-        :autosize="{ minRows: 6, maxRows: 6}"
-        placeholder="请输入内容"
-      />
-
-      <div slot="footer" class="dialog-footer">
-        <el-button @click="dialogForSpec = false; specValue = null">取 消</el-button>
-        <el-button type="primary" @click="addSpecValue">确 定</el-button>
-      </div>
-    </el-dialog>
-
-    <el-tabs v-model="activeName"  class="tabs">
+    <el-tabs v-model="activeName" class="tabs">
       <!-- 基础设置 -->
       <el-tab-pane label="基础设置" name="base">
         <el-form ref="baseForm" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
@@ -40,11 +20,11 @@
               clearable
             ></el-cascader>
           </el-form-item>
-          <el-form-item label="商品主图" prop="picUrls">
-            <ImageUpload v-model="baseForm.picUrl" :limit="1" />
+          <el-form-item label="商品主图" prop="bannerUrl">
+            <ImageUpload v-model="baseForm.bannerUrl" :limit="1"/>
           </el-form-item>
-           <el-form-item label="商品轮播图" prop="picUrl">
-            <ImageUpload v-model="baseForm.picUrls" :limit="10" />
+          <el-form-item label="商品轮播图" prop="picUrls">
+            <ImageUpload v-model="baseForm.picUrls" :limit="10"/>
           </el-form-item>
           <el-form-item label="排序字段" prop="sort">
             <el-input v-model="baseForm.sort" placeholder="请输入排序字段"/>
@@ -80,29 +60,28 @@
 
               <div class="spec-header">
                 规格项:
-                <el-input
-                  v-model="specs.spec_name"
-                  placeholder="请填写规格项"
-                  class="spec-name"
-                ></el-input>
+                <el-select v-model="specs.specId" filterable placeholder="请选择" @change="changeSpec">
+                  <el-option
+                    v-for="item in propertyPageList"
+                    :key="item.id"
+                    :label="item.name"
+                    :value="item.id">
+                  </el-option>
+                </el-select>
               </div>
               <div class="spec-values">
-                <template v-for="(specsValue, i) in specs.spec_values">
-                  <el-input
-                    v-model="specs.spec_values[i]"
-                    class="spec-value"
-                    :key="specsValue"
-                  ></el-input>
+                <template v-for="(v, i) in specs.specValue">
+                  <el-input v-model="v.name" class="spec-value" :key="i"/>
                 </template>
-                <el-button
+                <!-- <el-button
                   type="primary"
                   icon="el-icon-plus"
                   circle
                   @click="dialogForSpec = true; currentSpec = index"
-                ></el-button>
+                ></el-button> -->
               </div>
             </div>
-            <el-button type="primary" @click="dynamicSpec.push({spec_values: []}); ratesForm.rates = []"
+            <el-button type="primary" @click="dynamicSpec.push({specValue: []}); ratesForm.rates = []"
             >添加规格项目
             </el-button
             >
@@ -111,22 +90,24 @@
           <!-- 规格明细 -->
           <el-form-item label="规格明细">
             <el-table :data="ratesForm.rates" border style="width: 100%" ref="rates">
-              
-              <template v-if="ratesForm.spec == 1" > 
-                <el-table-column :key="index" v-for="(item, index) in dynamicSpec.filter(v=>v.spec_name != undefined)" :label="item.spec_name" >
-                <template slot-scope="scope">
-                  <el-input
-                    v-if="scope.row.spec"
-                    v-model="scope.row.spec[index]"
-                    disabled
-                  ></el-input>
-                </template>
-              </el-table-column>
+
+              <template v-if="ratesForm.spec == 1">
+                <el-table-column :key="index" v-for="(item, index) in dynamicSpec.filter(v=>v.specName != undefined)"
+                                 :label="item.specName">
+                  <template slot-scope="scope">
+                    <el-input
+                      v-if="scope.row.spec"
+                      v-model="scope.row.spec[index]"
+                      disabled
+                    ></el-input>
+                  </template>
+                </el-table-column>
               </template>
-             
+
               <el-table-column label="规格图片" width="120px">
                 <template slot-scope="scope">
-                  <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false" style="width: 100px; height: 50px" />
+                  <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false"
+                               style="width: 100px; height: 50px"/>
                 </template>
               </el-table-column>
               <el-table-column label="市场价(元)">
@@ -177,40 +158,40 @@
 
       <!-- 商品详情 -->
       <el-tab-pane label="商品描述" name="third">
-        <editor v-model="baseForm.description" :min-height="400" />
+        <editor v-model="baseForm.description" :min-height="400"/>
       </el-tab-pane>
 
       <!-- 销售设置 -->
       <el-tab-pane label="销售设置" name="fourth">
         <el-form ref="baseForm" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
-        <el-form-item label="库存数量" prop="quantity">
-          <el-input v-model="baseForm.quantity" placeholder="请输入库存数量" />
-        </el-form-item>
-        <el-form-item label="上下架状态" prop="status">
-          <el-radio-group v-model="baseForm.status">
-            <el-radio label="0">上架</el-radio>
-            <el-radio label="1">下架</el-radio>
-          </el-radio-group>
-        </el-form-item>
+          <el-form-item label="库存数量" prop="totalStock">
+            <el-input v-model="baseForm.totalStock" placeholder="请输入库存数量"/>
+          </el-form-item>
+          <el-form-item label="上下架状态" prop="status">
+            <el-radio-group v-model="baseForm.status">
+              <el-radio :label="0">上架</el-radio>
+              <el-radio :label="1">下架</el-radio>
+            </el-radio-group>
+          </el-form-item>
         </el-form>
       </el-tab-pane>
     </el-tabs>
 
-  <div class="buttons">
-  <el-button type="info" round @click="cancel">取消</el-button>
-   <el-button type="success" round @click="submit">确认</el-button>
-  </div>
+    <div class="buttons">
+      <el-button type="info" round @click="cancel">取消</el-button>
+      <el-button type="success" round @click="submit">确认</el-button>
+    </div>
 
   </div>
 </template>
 
 <script>
-import {
-  getProductCategoryList
-} from "@/api/mall/product/category";
-
+import {getProductCategoryList} from "@/api/mall/product/category";
+import {createSpu,} from "@/api/mall/product/spu";
+import {getPropertyPage,} from "@/api/mall/product/property";
 import Editor from "@/components/Editor";
 import ImageUpload from "@/components/ImageUpload";
+
 export default {
   components: {
     Editor,
@@ -231,12 +212,12 @@ export default {
         categoryIds: null,
         sort: null,
         description: null,
-        picUrl:null,
+        bannerUrl: null,
         picUrls: [],
-        quantity: null
+        totalStock: null,
+        status: 0
       },
       categoryList: [],
-
       // 价格库存
       ratesForm: {
         spec: 0,
@@ -245,15 +226,16 @@ export default {
       },
       dynamicSpec: [
         // {
-        //   spec_id: 86,
-        //   spec_name: "颜色",
-        //   spec_values: [],
-        //   spec_value_ids: [225],
+        //   specId: 86,
+        //   specName: "颜色",
+        //   specValue:[{
+        //      name: "红色",
+        //      id: 225,
+        //   }]
         // },
       ],
-      dialogForSpec: false,
+      propertyPageList: [],
       specValue: null,
-      currentSpec: null,
 
       // 表单校验
       rules: {
@@ -263,7 +245,7 @@ export default {
         categoryIds: [
           {required: true, message: "分类id不能为空", trigger: "blur"},
         ],
-        picUrls: [{required: true, message: "商品主图地址", trigger: "blur"}],
+        bannerUrl: [{required: true, message: "商品主图地址", trigger: "blur"}],
         sort: [
           {required: true, message: "排序字段不能为空", trigger: "blur"},
         ],
@@ -272,54 +254,44 @@ export default {
   },
   created() {
     this.getListCategory();
+    this.getPropertyPageList();
   },
   methods: {
     changeRadio() {
 
       this.$refs.rates.doLayout()
-      if(this.ratesForm.spec == 0){
+      if (this.ratesForm.spec == 0) {
         this.ratesForm.rates = [{}]
-      }else{
+      } else {
         this.ratesForm.rates = []
-        if(this.dynamicSpec.length > 0){
+        if (this.dynamicSpec.length > 0) {
           this.buildRatesFormRates()
         }
       }
     },
     // 构建规格明细笛卡尔积
-  buildRatesFormRates(){
+    buildRatesFormRates() {
       let rates = [];
-      this.dynamicSpec.map(v=>v.spec_values)
-      .reduce((last, current) => {
-        const array = [];
-        last.forEach(par1 => {
+      this.dynamicSpec.map(v => v.specValue.map(m => m.name))
+        .reduce((last, current) => {
+          const array = [];
+          last.forEach(par1 => {
             current.forEach(par2 => {
-              let v 
-              if(par1 instanceof Array){
+              let v
+              if (par1 instanceof Array) {
                 v = par1.concat(par2)
-              }else{
+              } else {
                 v = [par1, par2];
               }
               array.push(v)
             });
+          });
+          return array;
+        })
+        .forEach(v => {
+          rates.push({spec: v})
         });
-        return array;
-    })
-    .forEach(v=>{
-      rates.push({spec: v})
-    });
-    console.log(rates)
-    this.ratesForm.rates = rates
-  },
-    addSpecValue() {
-      this.dialogForSpec = false;
-      let specValue = this.dynamicSpec[this.currentSpec].spec_values
-        .concat(this.specValue.split(/[(\r\n)\r\n]+/))
-        .filter(v => v != "");
-      console.log(specValue)
-      this.dynamicSpec[this.currentSpec].spec_values = [...new Set(specValue)];
-      this.currentSpec = null;
-      this.buildRatesFormRates()
+      this.ratesForm.rates = rates
     },
     /** 查询分类 */
     getListCategory() {
@@ -328,9 +300,53 @@ export default {
         this.categoryList = this.handleTree(response.data, "id", "parentId");
       });
     },
-    cancel(){
+    cancel() {
+      this.$emit("closeDialog");
+    },
+    submit() {
+      let rates = this.ratesForm.rates;
+      // 动态规格调整字段
+      if (this.ratesForm.spec == 1) {
+        rates.forEach(r => {
+          let properties = []
+          r.spec.forEach((v, i) => {
+            let specValue = this.dynamicSpec[i].specValue.find(o => o.name == v);
+            let propertie = {};
+            propertie.propertyId = this.dynamicSpec[i].specId;
+            propertie.valueId = specValue.id;
+            properties.push(propertie);
+          })
+          r.properties = properties;
+        })
+      }
+      this.baseForm.skus = rates;
+      this.baseForm.specType = this.ratesForm.spec;
+      this.baseForm.categoryId = this.baseForm.categoryIds[this.baseForm.categoryIds.length - 1];
+      console.log(this.baseForm)
+      createSpu(this.baseForm).then((response) => {
+        this.$modal.msgSuccess("新增成功");
+        this.open = false;
+        this.getList();
         this.$emit("closeDialog");
+      });
     },
+    /** 查询规格 */
+    getPropertyPageList() {
+      // 执行查询
+      getPropertyPage().then((response) => {
+        this.propertyPageList = response.data.list;
+      });
+    },
+    changeSpec(val) {
+      let obj = this.propertyPageList.find(o => o.id == val);
+      let dynamicSpec = this.dynamicSpec;
+      let spec = dynamicSpec.find(o => o.specId == val)
+      spec.specId = obj.id;
+      spec.specName = obj.name;
+      spec.specValue = obj.propertyValueList;
+      this.dynamicSpec = dynamicSpec;
+      this.buildRatesFormRates();
+    }
   },
 };
 </script>
@@ -349,7 +365,7 @@ export default {
 
   .spec-header {
     padding: 30px;
-    padding-bottom: 0;
+    padding-bottom: 20px;
 
     .spec-name {
       display: inline;
@@ -364,6 +380,7 @@ export default {
     width: 84%;
     padding: 25px;
     margin: auto;
+    padding-top: 5px;
 
     .spec-value {
       display: inline-block;
@@ -381,35 +398,40 @@ export default {
   }
 }
 
-.tabs{
+.tabs {
   height: 500px;
   border-bottom: 2px solid #f2f2f2;
-  .el-tab-pane{
+
+  .el-tab-pane {
     height: 445px;
     overflow-y: auto;
   }
 }
 
 // 库存价格图片样式修改
-.rates{
-.component-upload-image{
-  margin: auto;
-}
-.el-upload--picture-card{
-  width: 100px;
-  height: 50px;
-  line-height: 60px;
-  margin: auto;
-}
-.el-upload-list__item{
-   width: 100px !important;
-  height: 50px !important;
-}
+.rates {
+  .component-upload-image {
+    margin: auto;
+  }
+
+  .el-upload--picture-card {
+    width: 100px;
+    height: 50px;
+    line-height: 60px;
+    margin: auto;
+  }
+
+  .el-upload-list__item {
+    width: 100px !important;
+    height: 50px !important;
+  }
 }
-.buttons{
+
+.buttons {
   margin-top: 20px;
   height: 36px;
-  button{
+
+  button {
     float: right;
     margin-left: 15px;
   }