ソースを参照

feature(管理后台): 商品列表

luowenfeng 2 年 前
コミット
fdb2d7339f

+ 15 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuPageReqVO.java

@@ -29,4 +29,19 @@ public class ProductSpuPageReqVO extends PageParam {
     @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)")
     private Integer status;
 
+    @ApiModelProperty(value = "销量最小值", example = "1")
+    private Integer salesCountMin;
+
+    @ApiModelProperty(value = "销量最大值", example = "1024")
+    private Integer salesCountMax;
+
+    @ApiModelProperty(value = "市场价最小值", example = "1")
+    private Integer marketPriceMin;
+
+    @ApiModelProperty(value = "市场价最大值", example = "1024")
+    private Integer marketPriceMax;
+
+    @ApiModelProperty(value = "tab 状态 null 全部, 0:销售中(上架) 1:仓库中(下架) 2:预警中", example = "1")
+    private Integer tabStatus;
+
 }

+ 27 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/dal/mysql/spu/ProductSpuMapper.java

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReq
 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * 商品spu Mapper
  *
@@ -20,7 +22,32 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
                 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
                 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
                 .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
+                .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
+                .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
+                .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
+                .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
                 .orderByDesc(ProductSpuDO::getSort));
     }
 
+    default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO, List<Long> spuIds) {
+        LambdaQueryWrapperX<ProductSpuDO> productSpuDOLambdaQueryWrapperX = new LambdaQueryWrapperX<ProductSpuDO>()
+                .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
+                .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
+                .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
+                .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
+                .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
+                .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
+                .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
+                .orderByDesc(ProductSpuDO::getSort);
+
+        if(reqVO.getTabStatus()!= null && reqVO.getTabStatus() == 2){
+            productSpuDOLambdaQueryWrapperX.inIfPresent(ProductSpuDO::getId, spuIds);
+        }else{
+            productSpuDOLambdaQueryWrapperX.eqIfPresent(ProductSpuDO::getStatus, reqVO.getTabStatus());
+        }
+
+        return selectPage(reqVO, productSpuDOLambdaQueryWrapperX);
+    }
+
+
 }

+ 7 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuService.java

@@ -83,4 +83,11 @@ public interface ProductSkuService {
      */
     void deleteSkuBySpuId(Long spuId);
 
+    /**
+     * 获得商品预警中的spu集合
+     *
+     * @return 商品spuId集合
+     */
+    List<Long> getRemindSpuIds();
+
 }

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

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.product.service.sku;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
@@ -14,6 +15,7 @@ import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants;
 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
 import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
 import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
@@ -131,6 +133,12 @@ public class ProductSkuServiceImpl implements ProductSkuService {
         productSkuMapper.deleteBySpuId(spuId);
     }
 
+    @Override
+    public List<Long> getRemindSpuIds() {
+        List<ProductSkuDO> productSkuDOS = productSkuMapper.selectList(new QueryWrapper<ProductSkuDO>().apply("stock <= warn_stock"));
+        return productSkuDOS.stream().map(ProductSkuDO::getSpuId).distinct().collect(Collectors.toList());
+    }
+
     @Override
     @Transactional
     public void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {

+ 10 - 11
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java

@@ -3,8 +3,8 @@ package cn.iocoder.yudao.module.product.service.spu;
 import cn.hutool.core.bean.BeanUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
+import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
@@ -190,16 +190,15 @@ public class ProductSpuServiceImpl implements ProductSpuService {
 
     @Override
     public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
-        PageResult<ProductSpuRespVO> spuVOs = ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO));
-        // 查询 sku 的信息
-//        List<Long> spuIds = spuVOs.getList().stream().map(ProductSpuRespVO::getId).collect(Collectors.toList());
-//        List<ProductSkuRespVO> skus = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuIds(spuIds));
-        // TODO @franky:使用 CollUtil 里的方法替代哈
-        // TODO 芋艿:临时注释
-//        Map<Long, List<ProductSkuRespVO>> skuMap = skus.stream().collect(Collectors.groupingBy(ProductSkuRespVO::getSpuId));
-//        // 将 spu 和 sku 进行组装
-//        spuVOs.getList().forEach(p -> p.setSkus(skuMap.get(p.getId())));
-        return spuVOs;
+        List<Long> remindSpuIds= null;
+        // todo @yunai 预警类型的判断应该可以优化,看下怎么处理
+        if(pageReqVO.getTabStatus() != null && pageReqVO.getTabStatus() == 2){
+            remindSpuIds= productSkuService.getRemindSpuIds();
+            if(remindSpuIds.isEmpty()){
+                remindSpuIds.add(null);
+            }
+        }
+        return ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO, remindSpuIds));
     }
 
     @Override

+ 38 - 26
yudao-ui-admin/src/views/mall/product/property/value.vue

@@ -24,7 +24,8 @@
     <el-row :gutter="10" class="mb8">
       <el-col :span="1.5">
         <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
-                   v-hasPermi="['system:dict:create']">新增</el-button>
+                   v-hasPermi="['system:dict:create']">新增
+        </el-button>
       </el-col>
       <!-- <el-col :span="1.5">
         <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
@@ -33,15 +34,15 @@
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
-    <el-table v-loading="loading" :data="dataList" >
-      <el-table-column label="规格值id" align="center" prop="id" />
-      <el-table-column label="规格值" align="center" prop="name" />
+    <el-table v-loading="loading" :data="dataList">
+      <el-table-column label="规格值id" align="center" prop="id"/>
+      <el-table-column label="规格值" align="center" prop="name"/>
       <el-table-column label="状态" align="center" prop="status">
         <template slot-scope="scope">
           <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
         </template>
       </el-table-column>
-      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true"/>
       <el-table-column label="创建时间" align="center" prop="createTime" width="180">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.createTime) }}</span>
@@ -50,9 +51,11 @@
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
           <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
-                     v-hasPermi="['system:dict:update']">修改</el-button>
+                     v-hasPermi="['system:dict:update']">修改
+          </el-button>
           <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
-                     v-hasPermi="['system:dict:delete']">删除</el-button>
+                     v-hasPermi="['system:dict:delete']">删除
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -64,10 +67,10 @@
     <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
       <el-form ref="form" :model="form" :rules="rules" label-width="90px">
         <el-form-item label="规格值编码">
-          <el-input v-model="form.propertyId" :disabled="true" />
+          <el-input v-model="form.propertyId" :disabled="true"/>
         </el-form-item>
         <el-form-item label="规格值" prop="name">
-          <el-input v-model="form.name" placeholder="请输入数据标签" />
+          <el-input v-model="form.name" placeholder="请输入数据标签"/>
         </el-form-item>
         <el-form-item label="状态" prop="status">
           <el-radio-group v-model="form.status">
@@ -89,8 +92,15 @@
 </template>
 
 <script>
-import { getPropertyList, getPropertyValuePage, createPropertyValue, updatePropertyValue, getPropertyValue, deletePropertyValue } from '@/api/mall/product/property'
-import {  getProperty } from "@/api/mall/product/property";
+import {
+  createPropertyValue,
+  deletePropertyValue,
+  getProperty,
+  getPropertyList,
+  getPropertyValue,
+  getPropertyValuePage,
+  updatePropertyValue
+} from '@/api/mall/product/property'
 
 export default {
   name: "PropertyValue",
@@ -127,10 +137,10 @@ export default {
       // 表单校验
       rules: {
         name: [
-          { required: true, message: "规格值不能为空", trigger: "blur" }
+          {required: true, message: "规格值不能为空", trigger: "blur"}
         ],
         status: [
-          { required: true, message: "状态不能为空", trigger: "blur" }
+          {required: true, message: "状态不能为空", trigger: "blur"}
         ]
       },
 
@@ -210,7 +220,7 @@ export default {
       });
     },
     /** 提交按钮 */
-    submitForm: function() {
+    submitForm: function () {
       this.$refs["form"].validate(valid => {
         if (valid) {
           if (this.form.id !== undefined) {
@@ -232,23 +242,25 @@ export default {
     /** 删除按钮操作 */
     handleDelete(row) {
       const ids = row.id;
-      this.$modal.confirm('是否确认删除字典编码为"' + ids + '"的数据项?').then(function() {
-          return deletePropertyValue(ids);
-        }).then(() => {
-          this.getList();
-          this.$modal.msgSuccess("删除成功");
-      }).catch(() => {});
+      this.$modal.confirm('是否确认删除字典编码为"' + ids + '"的数据项?').then(function () {
+        return deletePropertyValue(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {
+      });
     },
     /** 导出按钮操作 */
     handleExport() {
       const queryParams = this.queryParams;
       this.$modal.confirm('是否确认导出所有数据项?').then(() => {
-          this.exportLoading = true;
-          return exportData(queryParams);
-        }).then(response => {
-          this.$download.excel(response, '字典数据.xls');
-          this.exportLoading = false;
-      }).catch(() => {});
+        this.exportLoading = true;
+        return exportData(queryParams);
+      }).then(response => {
+        this.$download.excel(response, '字典数据.xls');
+        this.exportLoading = false;
+      }).catch(() => {
+      });
     }
   }
 };

+ 282 - 76
yudao-ui-admin/src/views/mall/product/spu/index.vue

@@ -1,30 +1,77 @@
 <template>
   <div class="app-container">
-    <!-- 搜索工作栏 -->
-    <!-- TODO @Luowenfeng:参考界面;https://v5.niuteam.cn/shop/goods/lists.html
-      商品名称、商品编码、商品分类、商品品牌
-      商品销量、商品价格
-     -->
     <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
       <el-form-item label="商品名称" prop="name">
         <el-input v-model="queryParams.name" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
       </el-form-item>
 
       <el-form-item label="商品编码" prop="code">
-        <el-input v-model="queryParams.code" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
+        <el-input v-model="queryParams.code" placeholder="请输入商品编码" clearable @keyup.enter.native="handleQuery"/>
       </el-form-item>
 
-      <el-form-item label="商品分类" prop="categoryId">
+      <el-form-item label="商品分类" prop="categoryIds">
         <el-cascader v-model="queryParams.categoryIds" placeholder="请输入商品分类"
-                         :options="categoryList" :props="propName" clearable ref="category" />
+                     :options="categoryList" :props="propName" clearable ref="category"/>
       </el-form-item>
 
       <el-form-item label="商品品牌" prop="brandId">
         <el-select v-model="queryParams.brandId" placeholder="请输入商品品牌" clearable @keyup.enter.native="handleQuery">
-          <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
+          <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id"/>
         </el-select>
       </el-form-item>
 
+      <el-form-item label="商品销量">
+        <el-col
+          :span="6"
+          style="padding-left:0"
+        >
+          <el-form-item prop="salesCountMin">
+            <el-input v-model="queryParams.salesCountMin" placeholder="最小值" clearable
+                      @keyup.enter.native="handleQuery"/>
+          </el-form-item>
+        </el-col>
+        <el-col
+          :span="1"
+        >
+          -
+        </el-col>
+        <el-col
+          :span="6"
+          style="padding-left:0"
+        >
+          <el-form-item prop="salesCountMax">
+            <el-input v-model="queryParams.salesCountMax" placeholder="最大值" clearable
+                      @keyup.enter.native="handleQuery"/>
+          </el-form-item>
+        </el-col>
+      </el-form-item>
+
+      <el-form-item label="商品价格" prop="code">
+        <el-col
+          :span="6"
+          style="padding-left:0"
+        >
+          <el-form-item prop="marketPriceMin">
+            <el-input v-model="queryParams.marketPriceMin" placeholder="最小值" clearable
+                      @keyup.enter.native="handleQuery"/>
+          </el-form-item>
+        </el-col>
+        <el-col
+          :span="1"
+        >
+          -
+        </el-col>
+        <el-col
+          :span="6"
+          style="padding-left:0"
+        >
+          <el-form-item prop="marketPriceMax">
+            <el-input v-model="queryParams.marketPriceMax" placeholder="最大值" clearable
+                      @keyup.enter.native="handleQuery"/>
+          </el-form-item>
+        </el-col>
+      </el-form-item>
+
       <el-form-item>
         <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
         <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
@@ -35,77 +82,211 @@
     <el-row :gutter="10" class="mb8">
       <el-col :span="1.5">
         <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
-                   v-hasPermi="['product:spu:create']">新增</el-button>
+                   v-hasPermi="['product:spu:create']">新增
+        </el-button>
       </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"/>
     </el-row>
 
-    <!-- 列表 -->
-    <el-table v-loading="loading" :data="list">
-      <!--
-      TODO @Luowenfeng:参考界面;
-       https://v5.niuteam.cn/shop/goods/lists.html
-       1. 字段:商品信息、价格、库存、销量、排序、创建时间、状态、操作;
-       2. tab 分成全部、销售中、仓库中、预警中
-       -->
-      <el-table-column label="商品信息" align="center" width="260">
+    <el-tabs v-model="activeTabs" type="card" @tab-click="handleClick">
+      <!-- 全部 -->
+      <el-tab-pane label="全部" name="all">
+        <!-- 列表 -->
+        <el-table v-loading="loading" :data="list">
+          <el-table-column label="商品信息" align="center" width="260">
+            <template slot-scope="scope">
+              <div class="product-info">
+                <img
+                  v-if="scope.row.picUrls"
+                  :src="scope.row.picUrls[0]"
+                  alt="分类图片"
+                  class="img-height"
+                />
+                <div class="message">{{ scope.row.name }}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
+          <el-table-column label="库存" align="center" prop="totalStock"/>
+          <el-table-column label="销量" align="center" prop="salesCount"/>
+          <el-table-column label="排序" align="center" prop="sort"/>
+          <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.createTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="状态" align="center" prop="status">
+            <template slot-scope="scope">
+              <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                         v-hasPermi="['product:spu:update']">修改
+              </el-button>
+              <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                         v-hasPermi="['product:spu:delete']">删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+
+      <!-- 销售中 -->
+      <el-tab-pane label="销售中" name="on">
+        <!-- 列表 -->
+        <el-table v-loading="loading" :data="list">
+          <el-table-column label="商品信息" align="center" width="260">
+            <template slot-scope="scope">
+              <div class="product-info">
+                <img
+                  v-if="scope.row.picUrls"
+                  :src="scope.row.picUrls[0]"
+                  alt="分类图片"
+                  class="img-height"
+                />
+                <div class="message">{{ scope.row.name }}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
+          <el-table-column label="库存" align="center" prop="totalStock"/>
+          <el-table-column label="销量" align="center" prop="salesCount"/>
+          <el-table-column label="排序" align="center" prop="sort"/>
+          <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.createTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="状态" align="center" prop="status">
+            <template slot-scope="scope">
+              <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                         v-hasPermi="['product:spu:update']">修改
+              </el-button>
+              <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                         v-hasPermi="['product:spu:delete']">删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
 
-        <template slot-scope="scope" >
-          <div class="product-info">
-            <img
-              v-if="scope.row.picUrls"
-              :src="scope.row.picUrls[0]"
-              alt="分类图片"
-              class="img-height"
-            />
-            <div class="message">{{scope.row.name}}</div>
-          </div>
-        </template>
-      </el-table-column>
-      <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
-      <el-table-column label="库存" align="center" prop="totalStock" />
-      <el-table-column label="销量" align="center" prop="salesCount" />
-      <el-table-column label="排序" align="center" prop="sort" />
-      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
-        <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.createTime) }}</span>
-        </template>
-      </el-table-column>
-      <el-table-column label="状态" align="center" prop="status">
-        <template slot-scope="scope">
-          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
-        </template>
-      </el-table-column>
+      <!-- 仓库中 -->
+      <el-tab-pane label="仓库中" name="off">
+        <!-- 列表 -->
+        <el-table v-loading="loading" :data="list">
+          <el-table-column label="商品信息" align="center" width="260">
+            <template slot-scope="scope">
+              <div class="product-info">
+                <img
+                  v-if="scope.row.picUrls"
+                  :src="scope.row.picUrls[0]"
+                  alt="分类图片"
+                  class="img-height"
+                />
+                <div class="message">{{ scope.row.name }}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
+          <el-table-column label="库存" align="center" prop="totalStock"/>
+          <el-table-column label="销量" align="center" prop="salesCount"/>
+          <el-table-column label="排序" align="center" prop="sort"/>
+          <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.createTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="状态" align="center" prop="status">
+            <template slot-scope="scope">
+              <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
+            </template>
+          </el-table-column>
 
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
-                     v-hasPermi="['product:spu:update']">修改</el-button>
-          <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
-                     v-hasPermi="['product:spu:delete']">删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                         v-hasPermi="['product:spu:update']">修改
+              </el-button>
+              <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                         v-hasPermi="['product:spu:delete']">删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+
+      <!-- 预警中 -->
+      <el-tab-pane label="预警中" name="remind">
+        <!-- 列表 -->
+        <el-table v-loading="loading" :data="list">
+          <el-table-column label="商品信息" align="center" width="260">
+            <template slot-scope="scope">
+              <div class="product-info">
+                <img
+                  v-if="scope.row.picUrls"
+                  :src="scope.row.picUrls[0]"
+                  alt="分类图片"
+                  class="img-height"
+                />
+                <div class="message">{{ scope.row.name }}</div>
+              </div>
+            </template>
+          </el-table-column>
+          <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
+          <el-table-column label="库存" align="center" prop="totalStock"/>
+          <el-table-column label="销量" align="center" prop="salesCount"/>
+          <el-table-column label="排序" align="center" prop="sort"/>
+          <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+            <template slot-scope="scope">
+              <span>{{ parseTime(scope.row.createTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column label="状态" align="center" prop="status">
+            <template slot-scope="scope">
+              <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+            <template slot-scope="scope">
+              <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
+                         v-hasPermi="['product:spu:update']">修改
+              </el-button>
+              <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
+                         v-hasPermi="['product:spu:delete']">删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+    </el-tabs>
     <!-- 分页组件 -->
     <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
                 @pagination="getList"/>
 
-    <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body destroy-on-close :close-on-click-modal="false" >
-      <save @closeDialog="closeDialog" :obj="dialogObj" v-if="open" />
+    <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body destroy-on-close
+               :close-on-click-modal="false">
+      <save @closeDialog="closeDialog" :obj="dialogObj" v-if="open"/>
     </el-dialog>
   </div>
 </template>
 
 <script>
-import {
-  deleteSpu,
-  getSpuPage,
-} from "@/api/mall/product/spu";
+import {deleteSpu, getSpuPage,} from "@/api/mall/product/spu";
 import {getProductCategoryList} from "@/api/mall/product/category";
 import {getBrandList} from "@/api/mall/product/brand";
 import Editor from "@/components/Editor";
 import ImageUpload from "@/components/ImageUpload";
-import save  from "./save";
+import save from "./save";
 
 // 1. TODO @Luowenfeng:商品的添加、修改,走一个单独的页面,不走弹窗;https://v5.niuteam.cn/shop/goods/addgoods.html
 // 2. TODO
@@ -119,6 +300,7 @@ export default {
   },
   data() {
     return {
+      activeTabs: "all",
       propName: {
         checkStrictly: true,
         label: "name",
@@ -141,7 +323,7 @@ export default {
       // 是否显示弹出层
       open: false,
       // 弹出层参数
-      dialogObj:{},
+      dialogObj: {},
       dateRangeCreateTime: [],
       // 查询参数
       queryParams: {
@@ -153,6 +335,11 @@ export default {
         categoryId: null,
         brandId: null,
         status: null,
+        salesCountMin: null,
+        salesCountMax: null,
+        marketPriceMin: null,
+        marketPriceMax: null,
+        tabStatus: null,
       },
       tagIndex: 0,
     };
@@ -181,13 +368,15 @@ export default {
     getList() {
       this.loading = true;
       // 处理查询参数
-      let params = { ...this.queryParams };
-      params.categoryId =  this.queryParams.categoryIds[ this.queryParams.categoryIds.length - 1];
+      let params = {...this.queryParams};
+      params.marketPriceMin = this.queryParams.marketPriceMin === null ? null : params.marketPriceMin * 100;
+      params.marketPriceMax = this.queryParams.marketPriceMax === null ? null : params.marketPriceMax * 100;
+      params.categoryId = this.queryParams.categoryIds[this.queryParams.categoryIds.length - 1];
       this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime");
       // 执行查询
       getSpuPage(params).then((response) => {
         response.data.list.forEach(element => {
-          element.price = this.divide(element.minPrice, 100)+"~"+this.divide(element.maxPrice, 100)
+          element.price = this.divide(element.minPrice, 100) + "~" + this.divide(element.maxPrice, 100)
         });
         this.list = response.data.list;
         this.total = response.data.total;
@@ -209,15 +398,14 @@ export default {
     resetQuery() {
       this.dateRangeCreateTime = [];
       this.$refs.category.$refs.panel.checkedValue = [];//也可以是指定的值,默认返回值是数组,也可以返回单个值
-    this.$refs.category.$refs.panel.activePath = [];
-    this.$refs.category.$refs.panel.syncActivePath();
-      this.queryParams.categoryIds = [];
+      this.$refs.category.$refs.panel.activePath = [];
+      this.$refs.category.$refs.panel.syncActivePath();
       this.resetForm("queryForm");
       this.handleQuery();
     },
     /** 新增按钮操作 */
     handleAdd() {
-      this.dialogObj={};
+      this.dialogObj = {};
       this.open = true;
       this.title = "添加商品spu";
     },
@@ -227,8 +415,8 @@ export default {
       this.open = true;
       this.title = "修改商品spu";
     },
-    closeDialog(){
-      this.dialogObj={};
+    closeDialog() {
+      this.dialogObj = {};
       this.open = false;
       this.getList()
     },
@@ -244,10 +432,26 @@ export default {
           this.getList();
           this.$modal.msgSuccess("删除成功");
         })
-        .catch(() => {});
+        .catch(() => {
+        });
     },
-    unitConversion(row, column, cellValue){
+    unitConversion(row, column, cellValue) {
       return this.divide(cellValue, 100);
+    },
+    // 选中tab
+    handleClick(val) {
+      if (val.name === "all") {
+        this.queryParams.tabStatus = null;
+      } else if (val.name === "on") {
+        this.queryParams.tabStatus = 0;
+      } else if (val.name === "off") {
+        this.queryParams.tabStatus = 1;
+      } else if (val.name === "remind") {
+        this.queryParams.tabStatus = 2;
+      } else {
+        this.queryParams.tabStatus = null;
+      }
+      this.getList();
     }
   },
 };
@@ -272,13 +476,15 @@ export default {
     vertical-align: bottom;
   }
 
-  .product-info{
+  .product-info {
     display: flex;
+
     .img-height {
       height: 50px;
       width: 50px;
     }
-    .message{
+
+    .message {
       margin-left: 10px;
       text-overflow: ellipsis;
       display: -webkit-box;

+ 149 - 136
yudao-ui-admin/src/views/mall/product/spu/save.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="container">
-    <el-tabs v-model="activeName" class="tabs"  >
+    <el-tabs v-model="activeName" class="tabs">
       <!-- 基础设置 -->
       <el-tab-pane label="基础设置" name="base">
         <el-form ref="base" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
@@ -11,20 +11,20 @@
             <el-input type="textarea" v-model="baseForm.sellPoint" placeholder="请输入商品卖点"/>
           </el-form-item>
           <el-form-item label="商品主图" prop="picUrls">
-            <ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10" class="mall-image" />
+            <ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10" class="mall-image"/>
           </el-form-item>
           <el-form-item label="商品视频" prop="videoUrl">
-            <VideoUpload v-model="baseForm.videoUrl" :value="baseForm.videoUrl" />
+            <VideoUpload v-model="baseForm.videoUrl" :value="baseForm.videoUrl"/>
           </el-form-item>
 
           <el-form-item label="商品品牌" prop="brandId">
             <el-select v-model="baseForm.brandId" placeholder="请选择商品品牌">
-              <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
+              <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id"/>
             </el-select>
           </el-form-item>
           <el-form-item label="商品分类" prop="categoryIds">
             <el-cascader v-model="baseForm.categoryIds" placeholder="商品分类" style="width: 100%"
-                         :options="categoryList" :props="propName" clearable />
+                         :options="categoryList" :props="propName" clearable/>
           </el-form-item>
           <el-form-item label="是否上架" prop="status">
             <el-radio-group v-model="baseForm.status">
@@ -46,11 +46,11 @@
           <div v-show="ratesForm.spec === 2">
             <div v-for="(specs, index) in dynamicSpec" :key="index" class="dynamic-spec">
               <!-- 删除按钮 -->
-              <el-button type="danger" icon="el-icon-delete" circle class="spec-delete" @click="removeSpec(index)" />
+              <el-button type="danger" icon="el-icon-delete" circle class="spec-delete" @click="removeSpec(index)"/>
               <div class="spec-header">
                 规格项:
                 <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 v-for="item in propertyPageList" :key="item.id" :label="item.name" :value="item.id"/>
                 </el-select>
               </div>
               <div class="spec-values">
@@ -59,7 +59,8 @@
                 </template>
               </div>
             </div>
-            <el-button type="primary" @click="dynamicSpec.push({specValue: []}); ratesForm.rates = []">添加规格项目</el-button>
+            <el-button type="primary" @click="dynamicSpec.push({specValue: []}); ratesForm.rates = []">添加规格项目
+            </el-button>
           </div>
 
           <!-- 规格明细 -->
@@ -69,53 +70,59 @@
                 <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 v-if="scope.row.spec" v-model="scope.row.spec[index]" disabled/>
                   </template>
                 </el-table-column>
               </template>
               <el-table-column label="规格图片" width="120px" :render-header="addRedStar" key="90">
                 <template slot-scope="scope">
-                    <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false"
+                  <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false"
                                style="width: 100px; height: 50px"/>
                 </template>
               </el-table-column>
               <template v-if="this.activeSwitch">
-               <el-table-column label="sku名称" :render-header="addRedStar" key="91">
+                <el-table-column label="sku名称" :render-header="addRedStar" key="91">
                   <template slot-scope="scope">
-                    <el-form-item :prop="'rates.'+ scope.$index + '.name'" :rules="[{required: true, trigger: 'change'}]">
-                      <el-input v-model="scope.row.name" />
+                    <el-form-item :prop="'rates.'+ scope.$index + '.name'"
+                                  :rules="[{required: true, trigger: 'change'}]">
+                      <el-input v-model="scope.row.name"/>
                     </el-form-item>
                   </template>
                 </el-table-column>
               </template>
               <el-table-column label="市场价(元)" :render-header="addRedStar" key="92">
                 <template slot-scope="scope">
-                  <el-form-item :prop="'rates.'+ scope.$index + '.marketPrice'" :rules="[{required: true, trigger: 'change'}]">
+                  <el-form-item :prop="'rates.'+ scope.$index + '.marketPrice'"
+                                :rules="[{required: true, trigger: 'change'}]">
                     <el-input v-model="scope.row.marketPrice"
-                      oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"/>
+                              oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"/>
                   </el-form-item>
                 </template>
               </el-table-column>
               <el-table-column label="销售价(元)" :render-header="addRedStar" key="93">
                 <template slot-scope="scope">
-                 <el-form-item :prop="'rates.'+ scope.$index + '.price'" :rules="[{required: true, trigger: 'change'}]">
-                  <el-input v-model="scope.row.price" oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"></el-input>
+                  <el-form-item :prop="'rates.'+ scope.$index + '.price'"
+                                :rules="[{required: true, trigger: 'change'}]">
+                    <el-input v-model="scope.row.price"
+                              oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"></el-input>
                   </el-form-item>
                 </template>
               </el-table-column>
               <el-table-column label="成本价" :render-header="addRedStar" key="94">
                 <template slot-scope="scope">
-                <el-form-item :prop="'rates.'+ scope.$index + '.costPrice'" :rules="[{required: true, trigger: 'change'}]">
-                  <el-input
-                    v-model="scope.row.costPrice"
-                    oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"
-                  ></el-input>
+                  <el-form-item :prop="'rates.'+ scope.$index + '.costPrice'"
+                                :rules="[{required: true, trigger: 'change'}]">
+                    <el-input
+                      v-model="scope.row.costPrice"
+                      oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"
+                    ></el-input>
                   </el-form-item>
                 </template>
               </el-table-column>
               <el-table-column label="库存" :render-header="addRedStar" key="95">
                 <template slot-scope="scope">
-                  <el-form-item :prop="'rates.'+ scope.$index + '.stock'" :rules="[{required: true, trigger: 'change'}]">
+                  <el-form-item :prop="'rates.'+ scope.$index + '.stock'"
+                                :rules="[{required: true, trigger: 'change'}]">
                     <el-input v-model="scope.row.stock" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"></el-input>
                   </el-form-item>
                 </template>
@@ -127,12 +134,12 @@
               </el-table-column>
               <el-table-column label="体积" key="97">
                 <template slot-scope="scope">
-                  <el-input v-model="scope.row.volume" ></el-input>
+                  <el-input v-model="scope.row.volume"></el-input>
                 </template>
               </el-table-column>
               <el-table-column label="重量" key="98">
                 <template slot-scope="scope">
-                  <el-input v-model="scope.row.weight" ></el-input>
+                  <el-input v-model="scope.row.weight"></el-input>
                 </template>
               </el-table-column>
               <el-table-column label="条码" key="99">
@@ -140,29 +147,34 @@
                   <el-input v-model="scope.row.barCode"></el-input>
                 </template>
               </el-table-column>
-               <template v-if="this.activeSwitch">
+              <template v-if="this.activeSwitch">
                 <el-table-column fixed="right" label="操作" width="50" key="100">
                   <template slot-scope="scope">
-                    <el-button @click="scope.row.status = 1" type="text" size="small" v-show="scope.row.status == undefined || scope.row.status == 0 ">禁用</el-button>
-                    <el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status == 1">启用</el-button>
+                    <el-button @click="scope.row.status = 1" type="text" size="small"
+                               v-show="scope.row.status == undefined || scope.row.status == 0 ">禁用
+                    </el-button>
+                    <el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status == 1">
+                      启用
+                    </el-button>
                   </template>
                 </el-table-column>
               </template>
             </el-table>
           </el-form-item>
-          <el-form-item label="虚拟销量" prop="virtualSalesCount" >
-            <el-input v-model="baseForm.virtualSalesCount" placeholder="请输入虚拟销量" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
+          <el-form-item label="虚拟销量" prop="virtualSalesCount">
+            <el-input v-model="baseForm.virtualSalesCount" placeholder="请输入虚拟销量"
+                      oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
           </el-form-item>
         </el-form>
       </el-tab-pane>
 
       <!-- 商品详情 -->
       <el-tab-pane label="商品详情" name="third">
-      <el-form ref="third" :model="baseForm" :rules="rules">
-        <el-form-item prop="description">
-          <editor v-model="baseForm.description" :min-height="380"/>
-        </el-form-item>
-      </el-form>
+        <el-form ref="third" :model="baseForm" :rules="rules">
+          <el-form-item prop="description">
+            <editor v-model="baseForm.description" :min-height="380"/>
+          </el-form-item>
+        </el-form>
       </el-tab-pane>
 
       <!-- 销售设置 -->
@@ -171,8 +183,8 @@
           <el-form-item label="排序字段">
             <el-input v-model="baseForm.sort" placeholder="请输入排序字段" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
           </el-form-item>
-           <el-form-item label="是否展示库存" prop="showStock">
-             <el-radio-group v-model="baseForm.showStock">
+          <el-form-item label="是否展示库存" prop="showStock">
+            <el-radio-group v-model="baseForm.showStock">
               <el-radio :label="true">是</el-radio>
               <el-radio :label="false">否</el-radio>
             </el-radio-group>
@@ -193,7 +205,7 @@
 
 import {getBrandList} from "@/api/mall/product/brand";
 import {getProductCategoryList} from "@/api/mall/product/category";
-import {createSpu, updateSpu, getSpuDetail} from "@/api/mall/product/spu";
+import {createSpu, getSpuDetail, updateSpu} from "@/api/mall/product/spu";
 import {getPropertyListAndValue,} from "@/api/mall/product/property";
 import Editor from "@/components/Editor";
 import ImageUpload from "@/components/ImageUpload";
@@ -205,7 +217,7 @@ export default {
     ImageUpload,
     VideoUpload
   },
-  props:{
+  props: {
     obj: Object
   },
   data() {
@@ -256,7 +268,7 @@ export default {
 
       // 表单校验
       rules: {
-        name:[{required: true, message: "商品名称不能为空", trigger: "blur"},],
+        name: [{required: true, message: "商品名称不能为空", trigger: "blur"},],
         description: [{required: true, message: "描述不能为空", trigger: "blur"},],
         categoryIds: [{required: true, message: "分类id不能为空", trigger: "blur"},],
         status: [{required: true, message: "商品状态不能为空", trigger: "blur"}],
@@ -269,24 +281,24 @@ export default {
     this.getListBrand();
     this.getListCategory();
     this.getPropertyPageList();
-    if(this.obj.id != null){
+    if (this.obj.id != null) {
       this.updateType(this.obj.id)
     }
   },
   methods: {
-    removeSpec(index){
-        this.dynamicSpec.splice(index, 1);
-        this.changeRadio()
+    removeSpec(index) {
+      this.dynamicSpec.splice(index, 1);
+      this.changeRadio()
     },
     // 必选标识
-    addRedStar(h, { column }) {
+    addRedStar(h, {column}) {
       return [
-        h('span', { style: 'color: #F56C6C' }, '*'),
+        h('span', {style: 'color: #F56C6C'}, '*'),
         h('span', ' ' + column.label)
       ];
     },
     changeRadio() {
-      this.activeSwitch ? this.ratesForm.spec = 2:  this.ratesForm.spec = 1;
+      this.activeSwitch ? this.ratesForm.spec = 2 : this.ratesForm.spec = 1;
       this.$refs.ratesTable.doLayout();
       if (this.ratesForm.spec == 1) {
         this.ratesForm.rates = [{}]
@@ -334,7 +346,7 @@ export default {
         this.categoryList = this.handleTree(response.data, "id", "parentId");
       });
     },
-     /** 查询品牌列表 */
+    /** 查询品牌列表 */
     getListBrand() {
       // 执行查询
       getBrandList().then((response) => {
@@ -345,30 +357,30 @@ export default {
       this.$emit("closeDialog");
     },
     submit() {
-       this.$refs[this.activeName].validate((valid) => {
+      this.$refs[this.activeName].validate((valid) => {
         if (!valid) {
           return;
         }
-      let rates = this.ratesForm.rates;
+        let rates = this.ratesForm.rates;
 
-      // 价格元转分
-      rates.forEach(r=>{
-        r.marketPrice = r.marketPrice*100;
-        r.price = r.price*100;
-        r.costPrice = r.costPrice*100;
-      })
-
-      // 动态规格调整字段
-      if (this.activeSwitch) {
+        // 价格元转分
         rates.forEach(r => {
-          let properties = []
+          r.marketPrice = r.marketPrice * 100;
+          r.price = r.price * 100;
+          r.costPrice = r.costPrice * 100;
+        })
+
+        // 动态规格调整字段
+        if (this.activeSwitch) {
+          rates.forEach(r => {
+            let properties = []
             Array.of(r.spec).forEach(s => {
               let obj;
-               if (s instanceof Array) {
-                  obj = s;
-               }else{
-                  obj = Array.of(s);
-               }
+              if (s instanceof Array) {
+                obj = s;
+              } else {
+                obj = Array.of(s);
+              }
               obj.forEach((v, i) => {
                 let specValue = this.dynamicSpec[i].specValue.find(o => o.name == v);
                 let propertie = {};
@@ -377,35 +389,35 @@ export default {
                 properties.push(propertie);
               })
             })
-          r.properties = properties;
-        })
-      }else{
-        rates[0].name = this.baseForm.name;
-        rates[0].status = this.baseForm.status;
-      }
-      let form = this.baseForm
-      if(form.picUrls instanceof Array){
-        form.picUrls = form.picUrls.flatMap(m=>m.split(','))
-      }else if(form.picUrls.split(',') instanceof Array){
-        form.picUrls = form.picUrls.split(',').flatMap(m=>m.split(','))
-      }else{
-        form.picUrls = Array.of(form.picUrls)
-      }
-      form.skus = rates;
-      form.specType = this.ratesForm.spec;
-      form.categoryId = form.categoryIds[this.baseForm.categoryIds.length - 1];
-
-      if(form.id == null){
-        createSpu(form).then((response) => {
-          this.$modal.msgSuccess("新增成功");
-          this.$emit("closeDialog");
-        })
-      }else{
-        updateSpu(form).then((response) => {
-          this.$modal.msgSuccess("修改成功");
-          this.$emit("closeDialog");
-        })
-      }
+            r.properties = properties;
+          })
+        } else {
+          rates[0].name = this.baseForm.name;
+          rates[0].status = this.baseForm.status;
+        }
+        let form = this.baseForm
+        if (form.picUrls instanceof Array) {
+          form.picUrls = form.picUrls.flatMap(m => m.split(','))
+        } else if (form.picUrls.split(',') instanceof Array) {
+          form.picUrls = form.picUrls.split(',').flatMap(m => m.split(','))
+        } else {
+          form.picUrls = Array.of(form.picUrls)
+        }
+        form.skus = rates;
+        form.specType = this.ratesForm.spec;
+        form.categoryId = form.categoryIds[this.baseForm.categoryIds.length - 1];
+
+        if (form.id == null) {
+          createSpu(form).then((response) => {
+            this.$modal.msgSuccess("新增成功");
+            this.$emit("closeDialog");
+          })
+        } else {
+          updateSpu(form).then((response) => {
+            this.$modal.msgSuccess("修改成功");
+            this.$emit("closeDialog");
+          })
+        }
       });
 
     },
@@ -425,46 +437,46 @@ export default {
       spec.specValue = obj.values;
       this.buildRatesFormRates();
     },
-    updateType(id){
-      getSpuDetail(id).then((response) =>{
-            let data = response.data;
-            this.baseForm.id=data.id;
-            this.baseForm.name=data.name;
-            this.baseForm.sellPoint=data.sellPoint;
-            this.baseForm.categoryIds=data.categoryIds;
-            this.baseForm.videoUrl = data.videoUrl;
-            this.baseForm.sort=data.sort;
-            this.baseForm.description=data.description;
-            this.baseForm.picUrls=data.picUrls;
-            this.baseForm.status=data.status;
-            this.baseForm.virtualSalesCount=data.virtualSalesCount;
-            this.baseForm.showStock=data.showStock;
-            this.baseForm.brandId=data.brandId;
-            this.ratesForm.spec=data.specType;
-            data.skus.forEach(r=>{
-              r.marketPrice = this.divide(r.marketPrice, 100)
-              r.price = this.divide(r.price, 100)
-              r.costPrice = this.divide(r.costPrice, 100)
-            })
-            if(this.ratesForm.spec == 2){
-              this.activeSwitch = true;
-              data.productPropertyViews.forEach(p=>{
-                let obj = {};
-                obj.specId = p.propertyId;
-                obj.specName = p.name;
-                obj.specValue = p.propertyValues;
-                this.dynamicSpec.push(obj);
-              })
-              data.skus.forEach(s=>{
-                s.spec = [];
-                s.properties.forEach(sp=>{
-                  let spec = data.productPropertyViews.find(o=>o.propertyId == sp.propertyId).propertyValues.find(v=>v.id == sp.valueId).name;
-                   s.spec.push(spec)
-                })
-              })
-            }
-            this.ratesForm.rates=data.skus
+    updateType(id) {
+      getSpuDetail(id).then((response) => {
+        let data = response.data;
+        this.baseForm.id = data.id;
+        this.baseForm.name = data.name;
+        this.baseForm.sellPoint = data.sellPoint;
+        this.baseForm.categoryIds = data.categoryIds;
+        this.baseForm.videoUrl = data.videoUrl;
+        this.baseForm.sort = data.sort;
+        this.baseForm.description = data.description;
+        this.baseForm.picUrls = data.picUrls;
+        this.baseForm.status = data.status;
+        this.baseForm.virtualSalesCount = data.virtualSalesCount;
+        this.baseForm.showStock = data.showStock;
+        this.baseForm.brandId = data.brandId;
+        this.ratesForm.spec = data.specType;
+        data.skus.forEach(r => {
+          r.marketPrice = this.divide(r.marketPrice, 100)
+          r.price = this.divide(r.price, 100)
+          r.costPrice = this.divide(r.costPrice, 100)
         })
+        if (this.ratesForm.spec == 2) {
+          this.activeSwitch = true;
+          data.productPropertyViews.forEach(p => {
+            let obj = {};
+            obj.specId = p.propertyId;
+            obj.specName = p.name;
+            obj.specValue = p.propertyValues;
+            this.dynamicSpec.push(obj);
+          })
+          data.skus.forEach(s => {
+            s.spec = [];
+            s.properties.forEach(sp => {
+              let spec = data.productPropertyViews.find(o => o.propertyId == sp.propertyId).propertyValues.find(v => v.id == sp.valueId).name;
+              s.spec.push(spec)
+            })
+          })
+        }
+        this.ratesForm.rates = data.skus
+      })
     },
 
   },
@@ -557,13 +569,14 @@ export default {
   }
 }
 
-.mall-image{
-  .el-upload--picture-card{
+.mall-image {
+  .el-upload--picture-card {
     width: 80px;
     height: 80px;
     line-height: 90px;
   }
-  .el-upload-list__item{
+
+  .el-upload-list__item {
     width: 80px;
     height: 80px;
   }