Commit fdb2d7339fbec1163d53ebd1bce35207aa55290b

Authored by luowenfeng
1 parent f122c0c5

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

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 {
29 29 @ApiModelProperty(value = "上下架状态: 0 上架(开启) 1 下架(禁用)")
30 30 private Integer status;
31 31  
  32 + @ApiModelProperty(value = "销量最小值", example = "1")
  33 + private Integer salesCountMin;
  34 +
  35 + @ApiModelProperty(value = "销量最大值", example = "1024")
  36 + private Integer salesCountMax;
  37 +
  38 + @ApiModelProperty(value = "市场价最小值", example = "1")
  39 + private Integer marketPriceMin;
  40 +
  41 + @ApiModelProperty(value = "市场价最大值", example = "1024")
  42 + private Integer marketPriceMax;
  43 +
  44 + @ApiModelProperty(value = "tab 状态 null 全部, 0:销售中(上架) 1:仓库中(下架) 2:预警中", example = "1")
  45 + private Integer tabStatus;
  46 +
32 47 }
... ...
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
7 7 import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
8 8 import org.apache.ibatis.annotations.Mapper;
9 9  
  10 +import java.util.List;
  11 +
10 12 /**
11 13 * 商品spu Mapper
12 14 *
... ... @@ -20,7 +22,32 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
20 22 .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
21 23 .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
22 24 .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
  25 + .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
  26 + .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
  27 + .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
  28 + .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
23 29 .orderByDesc(ProductSpuDO::getSort));
24 30 }
25 31  
  32 + default PageResult<ProductSpuDO> selectPage(ProductSpuPageReqVO reqVO, List<Long> spuIds) {
  33 + LambdaQueryWrapperX<ProductSpuDO> productSpuDOLambdaQueryWrapperX = new LambdaQueryWrapperX<ProductSpuDO>()
  34 + .likeIfPresent(ProductSpuDO::getName, reqVO.getName())
  35 + .eqIfPresent(ProductSpuDO::getCategoryId, reqVO.getCategoryId())
  36 + .eqIfPresent(ProductSpuDO::getStatus, reqVO.getStatus())
  37 + .leIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMax())
  38 + .geIfPresent(ProductSpuDO::getSalesCount, reqVO.getSalesCountMin())
  39 + .leIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMax())
  40 + .geIfPresent(ProductSpuDO::getMarketPrice, reqVO.getMarketPriceMin())
  41 + .orderByDesc(ProductSpuDO::getSort);
  42 +
  43 + if(reqVO.getTabStatus()!= null && reqVO.getTabStatus() == 2){
  44 + productSpuDOLambdaQueryWrapperX.inIfPresent(ProductSpuDO::getId, spuIds);
  45 + }else{
  46 + productSpuDOLambdaQueryWrapperX.eqIfPresent(ProductSpuDO::getStatus, reqVO.getTabStatus());
  47 + }
  48 +
  49 + return selectPage(reqVO, productSpuDOLambdaQueryWrapperX);
  50 + }
  51 +
  52 +
26 53 }
... ...
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 {
83 83 */
84 84 void deleteSkuBySpuId(Long spuId);
85 85  
  86 + /**
  87 + * 获得商品预警中的spu集合
  88 + *
  89 + * @return 商品spuId集合
  90 + */
  91 + List<Long> getRemindSpuIds();
  92 +
86 93 }
... ...
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;
3 3 import cn.hutool.core.collection.CollectionUtil;
4 4 import cn.hutool.core.util.ObjectUtil;
5 5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  6 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 7 import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
7 8 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
8 9 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
... ... @@ -14,6 +15,7 @@ import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants;
14 15 import cn.iocoder.yudao.module.product.enums.spu.ProductSpuSpecTypeEnum;
15 16 import cn.iocoder.yudao.module.product.service.property.ProductPropertyService;
16 17 import cn.iocoder.yudao.module.product.service.property.ProductPropertyValueService;
  18 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
17 19 import org.springframework.stereotype.Service;
18 20 import org.springframework.transaction.annotation.Transactional;
19 21 import org.springframework.validation.annotation.Validated;
... ... @@ -132,6 +134,12 @@ public class ProductSkuServiceImpl implements ProductSkuService {
132 134 }
133 135  
134 136 @Override
  137 + public List<Long> getRemindSpuIds() {
  138 + List<ProductSkuDO> productSkuDOS = productSkuMapper.selectList(new QueryWrapper<ProductSkuDO>().apply("stock <= warn_stock"));
  139 + return productSkuDOS.stream().map(ProductSkuDO::getSpuId).distinct().collect(Collectors.toList());
  140 + }
  141 +
  142 + @Override
135 143 @Transactional
136 144 public void updateProductSkus(Long spuId, List<ProductSkuCreateOrUpdateReqVO> skus) {
137 145 // 查询 SPU 下已经存在的 SKU 的集合
... ...
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;
3 3 import cn.hutool.core.bean.BeanUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
6   -import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
7 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyViewRespVO;
  7 +import cn.iocoder.yudao.module.product.controller.admin.property.vo.property.ProductPropertyRespVO;
8 8 import cn.iocoder.yudao.module.product.controller.admin.property.vo.value.ProductPropertyValueRespVO;
9 9 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
10 10 import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateOrUpdateReqVO;
... ... @@ -190,16 +190,15 @@ public class ProductSpuServiceImpl implements ProductSpuService {
190 190  
191 191 @Override
192 192 public PageResult<ProductSpuRespVO> getSpuPage(ProductSpuPageReqVO pageReqVO) {
193   - PageResult<ProductSpuRespVO> spuVOs = ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO));
194   - // 查询 sku 的信息
195   -// List<Long> spuIds = spuVOs.getList().stream().map(ProductSpuRespVO::getId).collect(Collectors.toList());
196   -// List<ProductSkuRespVO> skus = ProductSkuConvert.INSTANCE.convertList(productSkuService.getSkusBySpuIds(spuIds));
197   - // TODO @franky:使用 CollUtil 里的方法替代哈
198   - // TODO 芋艿:临时注释
199   -// Map<Long, List<ProductSkuRespVO>> skuMap = skus.stream().collect(Collectors.groupingBy(ProductSkuRespVO::getSpuId));
200   -// // 将 spu 和 sku 进行组装
201   -// spuVOs.getList().forEach(p -> p.setSkus(skuMap.get(p.getId())));
202   - return spuVOs;
  193 + List<Long> remindSpuIds= null;
  194 + // todo @yunai 预警类型的判断应该可以优化,看下怎么处理
  195 + if(pageReqVO.getTabStatus() != null && pageReqVO.getTabStatus() == 2){
  196 + remindSpuIds= productSkuService.getRemindSpuIds();
  197 + if(remindSpuIds.isEmpty()){
  198 + remindSpuIds.add(null);
  199 + }
  200 + }
  201 + return ProductSpuConvert.INSTANCE.convertPage(ProductSpuMapper.selectPage(pageReqVO, remindSpuIds));
203 202 }
204 203  
205 204 @Override
... ...
yudao-ui-admin/src/views/mall/product/property/value.vue
... ... @@ -24,7 +24,8 @@
24 24 <el-row :gutter="10" class="mb8">
25 25 <el-col :span="1.5">
26 26 <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
27   - v-hasPermi="['system:dict:create']">新增</el-button>
  27 + v-hasPermi="['system:dict:create']">新增
  28 + </el-button>
28 29 </el-col>
29 30 <!-- <el-col :span="1.5">
30 31 <el-button type="warning" icon="el-icon-download" size="mini" @click="handleExport" :loading="exportLoading"
... ... @@ -33,15 +34,15 @@
33 34 <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
34 35 </el-row>
35 36  
36   - <el-table v-loading="loading" :data="dataList" >
37   - <el-table-column label="规格值id" align="center" prop="id" />
38   - <el-table-column label="规格值" align="center" prop="name" />
  37 + <el-table v-loading="loading" :data="dataList">
  38 + <el-table-column label="规格值id" align="center" prop="id"/>
  39 + <el-table-column label="规格值" align="center" prop="name"/>
39 40 <el-table-column label="状态" align="center" prop="status">
40 41 <template slot-scope="scope">
41 42 <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
42 43 </template>
43 44 </el-table-column>
44   - <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
  45 + <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true"/>
45 46 <el-table-column label="创建时间" align="center" prop="createTime" width="180">
46 47 <template slot-scope="scope">
47 48 <span>{{ parseTime(scope.row.createTime) }}</span>
... ... @@ -50,9 +51,11 @@
50 51 <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
51 52 <template slot-scope="scope">
52 53 <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
53   - v-hasPermi="['system:dict:update']">修改</el-button>
  54 + v-hasPermi="['system:dict:update']">修改
  55 + </el-button>
54 56 <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
55   - v-hasPermi="['system:dict:delete']">删除</el-button>
  57 + v-hasPermi="['system:dict:delete']">删除
  58 + </el-button>
56 59 </template>
57 60 </el-table-column>
58 61 </el-table>
... ... @@ -64,10 +67,10 @@
64 67 <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
65 68 <el-form ref="form" :model="form" :rules="rules" label-width="90px">
66 69 <el-form-item label="规格值编码">
67   - <el-input v-model="form.propertyId" :disabled="true" />
  70 + <el-input v-model="form.propertyId" :disabled="true"/>
68 71 </el-form-item>
69 72 <el-form-item label="规格值" prop="name">
70   - <el-input v-model="form.name" placeholder="请输入数据标签" />
  73 + <el-input v-model="form.name" placeholder="请输入数据标签"/>
71 74 </el-form-item>
72 75 <el-form-item label="状态" prop="status">
73 76 <el-radio-group v-model="form.status">
... ... @@ -89,8 +92,15 @@
89 92 </template>
90 93  
91 94 <script>
92   -import { getPropertyList, getPropertyValuePage, createPropertyValue, updatePropertyValue, getPropertyValue, deletePropertyValue } from '@/api/mall/product/property'
93   -import { getProperty } from "@/api/mall/product/property";
  95 +import {
  96 + createPropertyValue,
  97 + deletePropertyValue,
  98 + getProperty,
  99 + getPropertyList,
  100 + getPropertyValue,
  101 + getPropertyValuePage,
  102 + updatePropertyValue
  103 +} from '@/api/mall/product/property'
94 104  
95 105 export default {
96 106 name: "PropertyValue",
... ... @@ -127,10 +137,10 @@ export default {
127 137 // 表单校验
128 138 rules: {
129 139 name: [
130   - { required: true, message: "规格值不能为空", trigger: "blur" }
  140 + {required: true, message: "规格值不能为空", trigger: "blur"}
131 141 ],
132 142 status: [
133   - { required: true, message: "状态不能为空", trigger: "blur" }
  143 + {required: true, message: "状态不能为空", trigger: "blur"}
134 144 ]
135 145 },
136 146  
... ... @@ -210,7 +220,7 @@ export default {
210 220 });
211 221 },
212 222 /** 提交按钮 */
213   - submitForm: function() {
  223 + submitForm: function () {
214 224 this.$refs["form"].validate(valid => {
215 225 if (valid) {
216 226 if (this.form.id !== undefined) {
... ... @@ -232,23 +242,25 @@ export default {
232 242 /** 删除按钮操作 */
233 243 handleDelete(row) {
234 244 const ids = row.id;
235   - this.$modal.confirm('是否确认删除字典编码为"' + ids + '"的数据项?').then(function() {
236   - return deletePropertyValue(ids);
237   - }).then(() => {
238   - this.getList();
239   - this.$modal.msgSuccess("删除成功");
240   - }).catch(() => {});
  245 + this.$modal.confirm('是否确认删除字典编码为"' + ids + '"的数据项?').then(function () {
  246 + return deletePropertyValue(ids);
  247 + }).then(() => {
  248 + this.getList();
  249 + this.$modal.msgSuccess("删除成功");
  250 + }).catch(() => {
  251 + });
241 252 },
242 253 /** 导出按钮操作 */
243 254 handleExport() {
244 255 const queryParams = this.queryParams;
245 256 this.$modal.confirm('是否确认导出所有数据项?').then(() => {
246   - this.exportLoading = true;
247   - return exportData(queryParams);
248   - }).then(response => {
249   - this.$download.excel(response, '字典数据.xls');
250   - this.exportLoading = false;
251   - }).catch(() => {});
  257 + this.exportLoading = true;
  258 + return exportData(queryParams);
  259 + }).then(response => {
  260 + this.$download.excel(response, '字典数据.xls');
  261 + this.exportLoading = false;
  262 + }).catch(() => {
  263 + });
252 264 }
253 265 }
254 266 };
... ...
yudao-ui-admin/src/views/mall/product/spu/index.vue
1 1 <template>
2 2 <div class="app-container">
3   - <!-- 搜索工作栏 -->
4   - <!-- TODO @Luowenfeng:参考界面;https://v5.niuteam.cn/shop/goods/lists.html
5   - 商品名称、商品编码、商品分类、商品品牌
6   - 商品销量、商品价格
7   - -->
8 3 <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
9 4 <el-form-item label="商品名称" prop="name">
10 5 <el-input v-model="queryParams.name" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
11 6 </el-form-item>
12 7  
13 8 <el-form-item label="商品编码" prop="code">
14   - <el-input v-model="queryParams.code" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
  9 + <el-input v-model="queryParams.code" placeholder="请输入商品编码" clearable @keyup.enter.native="handleQuery"/>
15 10 </el-form-item>
16 11  
17   - <el-form-item label="商品分类" prop="categoryId">
  12 + <el-form-item label="商品分类" prop="categoryIds">
18 13 <el-cascader v-model="queryParams.categoryIds" placeholder="请输入商品分类"
19   - :options="categoryList" :props="propName" clearable ref="category" />
  14 + :options="categoryList" :props="propName" clearable ref="category"/>
20 15 </el-form-item>
21 16  
22 17 <el-form-item label="商品品牌" prop="brandId">
23 18 <el-select v-model="queryParams.brandId" placeholder="请输入商品品牌" clearable @keyup.enter.native="handleQuery">
24   - <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
  19 + <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id"/>
25 20 </el-select>
26 21 </el-form-item>
27 22  
  23 + <el-form-item label="商品销量">
  24 + <el-col
  25 + :span="6"
  26 + style="padding-left:0"
  27 + >
  28 + <el-form-item prop="salesCountMin">
  29 + <el-input v-model="queryParams.salesCountMin" placeholder="最小值" clearable
  30 + @keyup.enter.native="handleQuery"/>
  31 + </el-form-item>
  32 + </el-col>
  33 + <el-col
  34 + :span="1"
  35 + >
  36 + -
  37 + </el-col>
  38 + <el-col
  39 + :span="6"
  40 + style="padding-left:0"
  41 + >
  42 + <el-form-item prop="salesCountMax">
  43 + <el-input v-model="queryParams.salesCountMax" placeholder="最大值" clearable
  44 + @keyup.enter.native="handleQuery"/>
  45 + </el-form-item>
  46 + </el-col>
  47 + </el-form-item>
  48 +
  49 + <el-form-item label="商品价格" prop="code">
  50 + <el-col
  51 + :span="6"
  52 + style="padding-left:0"
  53 + >
  54 + <el-form-item prop="marketPriceMin">
  55 + <el-input v-model="queryParams.marketPriceMin" placeholder="最小值" clearable
  56 + @keyup.enter.native="handleQuery"/>
  57 + </el-form-item>
  58 + </el-col>
  59 + <el-col
  60 + :span="1"
  61 + >
  62 + -
  63 + </el-col>
  64 + <el-col
  65 + :span="6"
  66 + style="padding-left:0"
  67 + >
  68 + <el-form-item prop="marketPriceMax">
  69 + <el-input v-model="queryParams.marketPriceMax" placeholder="最大值" clearable
  70 + @keyup.enter.native="handleQuery"/>
  71 + </el-form-item>
  72 + </el-col>
  73 + </el-form-item>
  74 +
28 75 <el-form-item>
29 76 <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
30 77 <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
... ... @@ -35,77 +82,211 @@
35 82 <el-row :gutter="10" class="mb8">
36 83 <el-col :span="1.5">
37 84 <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
38   - v-hasPermi="['product:spu:create']">新增</el-button>
  85 + v-hasPermi="['product:spu:create']">新增
  86 + </el-button>
39 87 </el-col>
40   - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
  88 + <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"/>
41 89 </el-row>
42 90  
43   - <!-- 列表 -->
44   - <el-table v-loading="loading" :data="list">
45   - <!--
46   - TODO @Luowenfeng:参考界面;
47   - https://v5.niuteam.cn/shop/goods/lists.html
48   - 1. 字段:商品信息、价格、库存、销量、排序、创建时间、状态、操作;
49   - 2. tab 分成全部、销售中、仓库中、预警中
50   - -->
51   - <el-table-column label="商品信息" align="center" width="260">
  91 + <el-tabs v-model="activeTabs" type="card" @tab-click="handleClick">
  92 + <!-- 全部 -->
  93 + <el-tab-pane label="全部" name="all">
  94 + <!-- 列表 -->
  95 + <el-table v-loading="loading" :data="list">
  96 + <el-table-column label="商品信息" align="center" width="260">
  97 + <template slot-scope="scope">
  98 + <div class="product-info">
  99 + <img
  100 + v-if="scope.row.picUrls"
  101 + :src="scope.row.picUrls[0]"
  102 + alt="分类图片"
  103 + class="img-height"
  104 + />
  105 + <div class="message">{{ scope.row.name }}</div>
  106 + </div>
  107 + </template>
  108 + </el-table-column>
  109 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  110 + <el-table-column label="库存" align="center" prop="totalStock"/>
  111 + <el-table-column label="销量" align="center" prop="salesCount"/>
  112 + <el-table-column label="排序" align="center" prop="sort"/>
  113 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  114 + <template slot-scope="scope">
  115 + <span>{{ parseTime(scope.row.createTime) }}</span>
  116 + </template>
  117 + </el-table-column>
  118 + <el-table-column label="状态" align="center" prop="status">
  119 + <template slot-scope="scope">
  120 + <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  121 + </template>
  122 + </el-table-column>
  123 +
  124 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  125 + <template slot-scope="scope">
  126 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  127 + v-hasPermi="['product:spu:update']">修改
  128 + </el-button>
  129 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  130 + v-hasPermi="['product:spu:delete']">删除
  131 + </el-button>
  132 + </template>
  133 + </el-table-column>
  134 + </el-table>
  135 + </el-tab-pane>
  136 +
  137 + <!-- 销售中 -->
  138 + <el-tab-pane label="销售中" name="on">
  139 + <!-- 列表 -->
  140 + <el-table v-loading="loading" :data="list">
  141 + <el-table-column label="商品信息" align="center" width="260">
  142 + <template slot-scope="scope">
  143 + <div class="product-info">
  144 + <img
  145 + v-if="scope.row.picUrls"
  146 + :src="scope.row.picUrls[0]"
  147 + alt="分类图片"
  148 + class="img-height"
  149 + />
  150 + <div class="message">{{ scope.row.name }}</div>
  151 + </div>
  152 + </template>
  153 + </el-table-column>
  154 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  155 + <el-table-column label="库存" align="center" prop="totalStock"/>
  156 + <el-table-column label="销量" align="center" prop="salesCount"/>
  157 + <el-table-column label="排序" align="center" prop="sort"/>
  158 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  159 + <template slot-scope="scope">
  160 + <span>{{ parseTime(scope.row.createTime) }}</span>
  161 + </template>
  162 + </el-table-column>
  163 + <el-table-column label="状态" align="center" prop="status">
  164 + <template slot-scope="scope">
  165 + <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  166 + </template>
  167 + </el-table-column>
  168 +
  169 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  170 + <template slot-scope="scope">
  171 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  172 + v-hasPermi="['product:spu:update']">修改
  173 + </el-button>
  174 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  175 + v-hasPermi="['product:spu:delete']">删除
  176 + </el-button>
  177 + </template>
  178 + </el-table-column>
  179 + </el-table>
  180 + </el-tab-pane>
52 181  
53   - <template slot-scope="scope" >
54   - <div class="product-info">
55   - <img
56   - v-if="scope.row.picUrls"
57   - :src="scope.row.picUrls[0]"
58   - alt="分类图片"
59   - class="img-height"
60   - />
61   - <div class="message">{{scope.row.name}}</div>
62   - </div>
63   - </template>
64   - </el-table-column>
65   - <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
66   - <el-table-column label="库存" align="center" prop="totalStock" />
67   - <el-table-column label="销量" align="center" prop="salesCount" />
68   - <el-table-column label="排序" align="center" prop="sort" />
69   - <el-table-column label="创建时间" align="center" prop="createTime" width="180">
70   - <template slot-scope="scope">
71   - <span>{{ parseTime(scope.row.createTime) }}</span>
72   - </template>
73   - </el-table-column>
74   - <el-table-column label="状态" align="center" prop="status">
75   - <template slot-scope="scope">
76   - <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
77   - </template>
78   - </el-table-column>
  182 + <!-- 仓库中 -->
  183 + <el-tab-pane label="仓库中" name="off">
  184 + <!-- 列表 -->
  185 + <el-table v-loading="loading" :data="list">
  186 + <el-table-column label="商品信息" align="center" width="260">
  187 + <template slot-scope="scope">
  188 + <div class="product-info">
  189 + <img
  190 + v-if="scope.row.picUrls"
  191 + :src="scope.row.picUrls[0]"
  192 + alt="分类图片"
  193 + class="img-height"
  194 + />
  195 + <div class="message">{{ scope.row.name }}</div>
  196 + </div>
  197 + </template>
  198 + </el-table-column>
  199 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  200 + <el-table-column label="库存" align="center" prop="totalStock"/>
  201 + <el-table-column label="销量" align="center" prop="salesCount"/>
  202 + <el-table-column label="排序" align="center" prop="sort"/>
  203 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  204 + <template slot-scope="scope">
  205 + <span>{{ parseTime(scope.row.createTime) }}</span>
  206 + </template>
  207 + </el-table-column>
  208 + <el-table-column label="状态" align="center" prop="status">
  209 + <template slot-scope="scope">
  210 + <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  211 + </template>
  212 + </el-table-column>
79 213  
80   - <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
81   - <template slot-scope="scope">
82   - <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
83   - v-hasPermi="['product:spu:update']">修改</el-button>
84   - <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
85   - v-hasPermi="['product:spu:delete']">删除</el-button>
86   - </template>
87   - </el-table-column>
88   - </el-table>
  214 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  215 + <template slot-scope="scope">
  216 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  217 + v-hasPermi="['product:spu:update']">修改
  218 + </el-button>
  219 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  220 + v-hasPermi="['product:spu:delete']">删除
  221 + </el-button>
  222 + </template>
  223 + </el-table-column>
  224 + </el-table>
  225 + </el-tab-pane>
  226 +
  227 + <!-- 预警中 -->
  228 + <el-tab-pane label="预警中" name="remind">
  229 + <!-- 列表 -->
  230 + <el-table v-loading="loading" :data="list">
  231 + <el-table-column label="商品信息" align="center" width="260">
  232 + <template slot-scope="scope">
  233 + <div class="product-info">
  234 + <img
  235 + v-if="scope.row.picUrls"
  236 + :src="scope.row.picUrls[0]"
  237 + alt="分类图片"
  238 + class="img-height"
  239 + />
  240 + <div class="message">{{ scope.row.name }}</div>
  241 + </div>
  242 + </template>
  243 + </el-table-column>
  244 + <el-table-column label="价格" align="center" prop="marketPrice" :formatter="unitConversion"/>
  245 + <el-table-column label="库存" align="center" prop="totalStock"/>
  246 + <el-table-column label="销量" align="center" prop="salesCount"/>
  247 + <el-table-column label="排序" align="center" prop="sort"/>
  248 + <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  249 + <template slot-scope="scope">
  250 + <span>{{ parseTime(scope.row.createTime) }}</span>
  251 + </template>
  252 + </el-table-column>
  253 + <el-table-column label="状态" align="center" prop="status">
  254 + <template slot-scope="scope">
  255 + <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status"/>
  256 + </template>
  257 + </el-table-column>
  258 +
  259 + <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  260 + <template slot-scope="scope">
  261 + <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
  262 + v-hasPermi="['product:spu:update']">修改
  263 + </el-button>
  264 + <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
  265 + v-hasPermi="['product:spu:delete']">删除
  266 + </el-button>
  267 + </template>
  268 + </el-table-column>
  269 + </el-table>
  270 + </el-tab-pane>
  271 + </el-tabs>
89 272 <!-- 分页组件 -->
90 273 <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
91 274 @pagination="getList"/>
92 275  
93   - <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body destroy-on-close :close-on-click-modal="false" >
94   - <save @closeDialog="closeDialog" :obj="dialogObj" v-if="open" />
  276 + <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body destroy-on-close
  277 + :close-on-click-modal="false">
  278 + <save @closeDialog="closeDialog" :obj="dialogObj" v-if="open"/>
95 279 </el-dialog>
96 280 </div>
97 281 </template>
98 282  
99 283 <script>
100   -import {
101   - deleteSpu,
102   - getSpuPage,
103   -} from "@/api/mall/product/spu";
  284 +import {deleteSpu, getSpuPage,} from "@/api/mall/product/spu";
104 285 import {getProductCategoryList} from "@/api/mall/product/category";
105 286 import {getBrandList} from "@/api/mall/product/brand";
106 287 import Editor from "@/components/Editor";
107 288 import ImageUpload from "@/components/ImageUpload";
108   -import save from "./save";
  289 +import save from "./save";
109 290  
110 291 // 1. TODO @Luowenfeng:商品的添加、修改,走一个单独的页面,不走弹窗;https://v5.niuteam.cn/shop/goods/addgoods.html
111 292 // 2. TODO
... ... @@ -119,6 +300,7 @@ export default {
119 300 },
120 301 data() {
121 302 return {
  303 + activeTabs: "all",
122 304 propName: {
123 305 checkStrictly: true,
124 306 label: "name",
... ... @@ -141,7 +323,7 @@ export default {
141 323 // 是否显示弹出层
142 324 open: false,
143 325 // 弹出层参数
144   - dialogObj:{},
  326 + dialogObj: {},
145 327 dateRangeCreateTime: [],
146 328 // 查询参数
147 329 queryParams: {
... ... @@ -153,6 +335,11 @@ export default {
153 335 categoryId: null,
154 336 brandId: null,
155 337 status: null,
  338 + salesCountMin: null,
  339 + salesCountMax: null,
  340 + marketPriceMin: null,
  341 + marketPriceMax: null,
  342 + tabStatus: null,
156 343 },
157 344 tagIndex: 0,
158 345 };
... ... @@ -181,13 +368,15 @@ export default {
181 368 getList() {
182 369 this.loading = true;
183 370 // 处理查询参数
184   - let params = { ...this.queryParams };
185   - params.categoryId = this.queryParams.categoryIds[ this.queryParams.categoryIds.length - 1];
  371 + let params = {...this.queryParams};
  372 + params.marketPriceMin = this.queryParams.marketPriceMin === null ? null : params.marketPriceMin * 100;
  373 + params.marketPriceMax = this.queryParams.marketPriceMax === null ? null : params.marketPriceMax * 100;
  374 + params.categoryId = this.queryParams.categoryIds[this.queryParams.categoryIds.length - 1];
186 375 this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime");
187 376 // 执行查询
188 377 getSpuPage(params).then((response) => {
189 378 response.data.list.forEach(element => {
190   - element.price = this.divide(element.minPrice, 100)+"~"+this.divide(element.maxPrice, 100)
  379 + element.price = this.divide(element.minPrice, 100) + "~" + this.divide(element.maxPrice, 100)
191 380 });
192 381 this.list = response.data.list;
193 382 this.total = response.data.total;
... ... @@ -209,15 +398,14 @@ export default {
209 398 resetQuery() {
210 399 this.dateRangeCreateTime = [];
211 400 this.$refs.category.$refs.panel.checkedValue = [];//也可以是指定的值,默认返回值是数组,也可以返回单个值
212   -   this.$refs.category.$refs.panel.activePath = [];
213   -   this.$refs.category.$refs.panel.syncActivePath();
214   - this.queryParams.categoryIds = [];
  401 + this.$refs.category.$refs.panel.activePath = [];
  402 + this.$refs.category.$refs.panel.syncActivePath();
215 403 this.resetForm("queryForm");
216 404 this.handleQuery();
217 405 },
218 406 /** 新增按钮操作 */
219 407 handleAdd() {
220   - this.dialogObj={};
  408 + this.dialogObj = {};
221 409 this.open = true;
222 410 this.title = "添加商品spu";
223 411 },
... ... @@ -227,8 +415,8 @@ export default {
227 415 this.open = true;
228 416 this.title = "修改商品spu";
229 417 },
230   - closeDialog(){
231   - this.dialogObj={};
  418 + closeDialog() {
  419 + this.dialogObj = {};
232 420 this.open = false;
233 421 this.getList()
234 422 },
... ... @@ -244,10 +432,26 @@ export default {
244 432 this.getList();
245 433 this.$modal.msgSuccess("删除成功");
246 434 })
247   - .catch(() => {});
  435 + .catch(() => {
  436 + });
248 437 },
249   - unitConversion(row, column, cellValue){
  438 + unitConversion(row, column, cellValue) {
250 439 return this.divide(cellValue, 100);
  440 + },
  441 + // 选中tab
  442 + handleClick(val) {
  443 + if (val.name === "all") {
  444 + this.queryParams.tabStatus = null;
  445 + } else if (val.name === "on") {
  446 + this.queryParams.tabStatus = 0;
  447 + } else if (val.name === "off") {
  448 + this.queryParams.tabStatus = 1;
  449 + } else if (val.name === "remind") {
  450 + this.queryParams.tabStatus = 2;
  451 + } else {
  452 + this.queryParams.tabStatus = null;
  453 + }
  454 + this.getList();
251 455 }
252 456 },
253 457 };
... ... @@ -272,13 +476,15 @@ export default {
272 476 vertical-align: bottom;
273 477 }
274 478  
275   - .product-info{
  479 + .product-info {
276 480 display: flex;
  481 +
277 482 .img-height {
278 483 height: 50px;
279 484 width: 50px;
280 485 }
281   - .message{
  486 +
  487 + .message {
282 488 margin-left: 10px;
283 489 text-overflow: ellipsis;
284 490 display: -webkit-box;
... ...
yudao-ui-admin/src/views/mall/product/spu/save.vue
1 1 <template>
2 2 <div class="container">
3   - <el-tabs v-model="activeName" class="tabs" >
  3 + <el-tabs v-model="activeName" class="tabs">
4 4 <!-- 基础设置 -->
5 5 <el-tab-pane label="基础设置" name="base">
6 6 <el-form ref="base" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
... ... @@ -11,20 +11,20 @@
11 11 <el-input type="textarea" v-model="baseForm.sellPoint" placeholder="请输入商品卖点"/>
12 12 </el-form-item>
13 13 <el-form-item label="商品主图" prop="picUrls">
14   - <ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10" class="mall-image" />
  14 + <ImageUpload v-model="baseForm.picUrls" :value="baseForm.picUrls" :limit="10" class="mall-image"/>
15 15 </el-form-item>
16 16 <el-form-item label="商品视频" prop="videoUrl">
17   - <VideoUpload v-model="baseForm.videoUrl" :value="baseForm.videoUrl" />
  17 + <VideoUpload v-model="baseForm.videoUrl" :value="baseForm.videoUrl"/>
18 18 </el-form-item>
19 19  
20 20 <el-form-item label="商品品牌" prop="brandId">
21 21 <el-select v-model="baseForm.brandId" placeholder="请选择商品品牌">
22   - <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id" />
  22 + <el-option v-for="item in brandList" :key="item.id" :label="item.name" :value="item.id"/>
23 23 </el-select>
24 24 </el-form-item>
25 25 <el-form-item label="商品分类" prop="categoryIds">
26 26 <el-cascader v-model="baseForm.categoryIds" placeholder="商品分类" style="width: 100%"
27   - :options="categoryList" :props="propName" clearable />
  27 + :options="categoryList" :props="propName" clearable/>
28 28 </el-form-item>
29 29 <el-form-item label="是否上架" prop="status">
30 30 <el-radio-group v-model="baseForm.status">
... ... @@ -46,11 +46,11 @@
46 46 <div v-show="ratesForm.spec === 2">
47 47 <div v-for="(specs, index) in dynamicSpec" :key="index" class="dynamic-spec">
48 48 <!-- 删除按钮 -->
49   - <el-button type="danger" icon="el-icon-delete" circle class="spec-delete" @click="removeSpec(index)" />
  49 + <el-button type="danger" icon="el-icon-delete" circle class="spec-delete" @click="removeSpec(index)"/>
50 50 <div class="spec-header">
51 51 规格项:
52 52 <el-select v-model="specs.specId" filterable placeholder="请选择" @change="changeSpec">
53   - <el-option v-for="item in propertyPageList" :key="item.id" :label="item.name" :value="item.id" />
  53 + <el-option v-for="item in propertyPageList" :key="item.id" :label="item.name" :value="item.id"/>
54 54 </el-select>
55 55 </div>
56 56 <div class="spec-values">
... ... @@ -59,7 +59,8 @@
59 59 </template>
60 60 </div>
61 61 </div>
62   - <el-button type="primary" @click="dynamicSpec.push({specValue: []}); ratesForm.rates = []">添加规格项目</el-button>
  62 + <el-button type="primary" @click="dynamicSpec.push({specValue: []}); ratesForm.rates = []">添加规格项目
  63 + </el-button>
63 64 </div>
64 65  
65 66 <!-- 规格明细 -->
... ... @@ -69,53 +70,59 @@
69 70 <el-table-column :key="index" v-for="(item, index) in dynamicSpec.filter(v => v.specName !== undefined)"
70 71 :label="item.specName">
71 72 <template slot-scope="scope">
72   - <el-input v-if="scope.row.spec" v-model="scope.row.spec[index]" disabled />
  73 + <el-input v-if="scope.row.spec" v-model="scope.row.spec[index]" disabled/>
73 74 </template>
74 75 </el-table-column>
75 76 </template>
76 77 <el-table-column label="规格图片" width="120px" :render-header="addRedStar" key="90">
77 78 <template slot-scope="scope">
78   - <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false"
  79 + <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false"
79 80 style="width: 100px; height: 50px"/>
80 81 </template>
81 82 </el-table-column>
82 83 <template v-if="this.activeSwitch">
83   - <el-table-column label="sku名称" :render-header="addRedStar" key="91">
  84 + <el-table-column label="sku名称" :render-header="addRedStar" key="91">
84 85 <template slot-scope="scope">
85   - <el-form-item :prop="'rates.'+ scope.$index + '.name'" :rules="[{required: true, trigger: 'change'}]">
86   - <el-input v-model="scope.row.name" />
  86 + <el-form-item :prop="'rates.'+ scope.$index + '.name'"
  87 + :rules="[{required: true, trigger: 'change'}]">
  88 + <el-input v-model="scope.row.name"/>
87 89 </el-form-item>
88 90 </template>
89 91 </el-table-column>
90 92 </template>
91 93 <el-table-column label="市场价(元)" :render-header="addRedStar" key="92">
92 94 <template slot-scope="scope">
93   - <el-form-item :prop="'rates.'+ scope.$index + '.marketPrice'" :rules="[{required: true, trigger: 'change'}]">
  95 + <el-form-item :prop="'rates.'+ scope.$index + '.marketPrice'"
  96 + :rules="[{required: true, trigger: 'change'}]">
94 97 <el-input v-model="scope.row.marketPrice"
95   - oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"/>
  98 + oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"/>
96 99 </el-form-item>
97 100 </template>
98 101 </el-table-column>
99 102 <el-table-column label="销售价(元)" :render-header="addRedStar" key="93">
100 103 <template slot-scope="scope">
101   - <el-form-item :prop="'rates.'+ scope.$index + '.price'" :rules="[{required: true, trigger: 'change'}]">
102   - <el-input v-model="scope.row.price" oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"></el-input>
  104 + <el-form-item :prop="'rates.'+ scope.$index + '.price'"
  105 + :rules="[{required: true, trigger: 'change'}]">
  106 + <el-input v-model="scope.row.price"
  107 + oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"></el-input>
103 108 </el-form-item>
104 109 </template>
105 110 </el-table-column>
106 111 <el-table-column label="成本价" :render-header="addRedStar" key="94">
107 112 <template slot-scope="scope">
108   - <el-form-item :prop="'rates.'+ scope.$index + '.costPrice'" :rules="[{required: true, trigger: 'change'}]">
109   - <el-input
110   - v-model="scope.row.costPrice"
111   - oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"
112   - ></el-input>
  113 + <el-form-item :prop="'rates.'+ scope.$index + '.costPrice'"
  114 + :rules="[{required: true, trigger: 'change'}]">
  115 + <el-input
  116 + v-model="scope.row.costPrice"
  117 + oninput="value= value.match(/\d+(\.\d{0,2})?/) ? value.match(/\d+(\.\d{0,2})?/)[0] : ''"
  118 + ></el-input>
113 119 </el-form-item>
114 120 </template>
115 121 </el-table-column>
116 122 <el-table-column label="库存" :render-header="addRedStar" key="95">
117 123 <template slot-scope="scope">
118   - <el-form-item :prop="'rates.'+ scope.$index + '.stock'" :rules="[{required: true, trigger: 'change'}]">
  124 + <el-form-item :prop="'rates.'+ scope.$index + '.stock'"
  125 + :rules="[{required: true, trigger: 'change'}]">
119 126 <el-input v-model="scope.row.stock" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"></el-input>
120 127 </el-form-item>
121 128 </template>
... ... @@ -127,12 +134,12 @@
127 134 </el-table-column>
128 135 <el-table-column label="体积" key="97">
129 136 <template slot-scope="scope">
130   - <el-input v-model="scope.row.volume" ></el-input>
  137 + <el-input v-model="scope.row.volume"></el-input>
131 138 </template>
132 139 </el-table-column>
133 140 <el-table-column label="重量" key="98">
134 141 <template slot-scope="scope">
135   - <el-input v-model="scope.row.weight" ></el-input>
  142 + <el-input v-model="scope.row.weight"></el-input>
136 143 </template>
137 144 </el-table-column>
138 145 <el-table-column label="条码" key="99">
... ... @@ -140,29 +147,34 @@
140 147 <el-input v-model="scope.row.barCode"></el-input>
141 148 </template>
142 149 </el-table-column>
143   - <template v-if="this.activeSwitch">
  150 + <template v-if="this.activeSwitch">
144 151 <el-table-column fixed="right" label="操作" width="50" key="100">
145 152 <template slot-scope="scope">
146   - <el-button @click="scope.row.status = 1" type="text" size="small" v-show="scope.row.status == undefined || scope.row.status == 0 ">禁用</el-button>
147   - <el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status == 1">启用</el-button>
  153 + <el-button @click="scope.row.status = 1" type="text" size="small"
  154 + v-show="scope.row.status == undefined || scope.row.status == 0 ">禁用
  155 + </el-button>
  156 + <el-button @click="scope.row.status = 0" type="text" size="small" v-show="scope.row.status == 1">
  157 + 启用
  158 + </el-button>
148 159 </template>
149 160 </el-table-column>
150 161 </template>
151 162 </el-table>
152 163 </el-form-item>
153   - <el-form-item label="虚拟销量" prop="virtualSalesCount" >
154   - <el-input v-model="baseForm.virtualSalesCount" placeholder="请输入虚拟销量" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
  164 + <el-form-item label="虚拟销量" prop="virtualSalesCount">
  165 + <el-input v-model="baseForm.virtualSalesCount" placeholder="请输入虚拟销量"
  166 + oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
155 167 </el-form-item>
156 168 </el-form>
157 169 </el-tab-pane>
158 170  
159 171 <!-- 商品详情 -->
160 172 <el-tab-pane label="商品详情" name="third">
161   - <el-form ref="third" :model="baseForm" :rules="rules">
162   - <el-form-item prop="description">
163   - <editor v-model="baseForm.description" :min-height="380"/>
164   - </el-form-item>
165   - </el-form>
  173 + <el-form ref="third" :model="baseForm" :rules="rules">
  174 + <el-form-item prop="description">
  175 + <editor v-model="baseForm.description" :min-height="380"/>
  176 + </el-form-item>
  177 + </el-form>
166 178 </el-tab-pane>
167 179  
168 180 <!-- 销售设置 -->
... ... @@ -171,8 +183,8 @@
171 183 <el-form-item label="排序字段">
172 184 <el-input v-model="baseForm.sort" placeholder="请输入排序字段" oninput="value=value.replace(/^(0+)|[^\d]+/g,'')"/>
173 185 </el-form-item>
174   - <el-form-item label="是否展示库存" prop="showStock">
175   - <el-radio-group v-model="baseForm.showStock">
  186 + <el-form-item label="是否展示库存" prop="showStock">
  187 + <el-radio-group v-model="baseForm.showStock">
176 188 <el-radio :label="true">是</el-radio>
177 189 <el-radio :label="false">否</el-radio>
178 190 </el-radio-group>
... ... @@ -193,7 +205,7 @@
193 205  
194 206 import {getBrandList} from "@/api/mall/product/brand";
195 207 import {getProductCategoryList} from "@/api/mall/product/category";
196   -import {createSpu, updateSpu, getSpuDetail} from "@/api/mall/product/spu";
  208 +import {createSpu, getSpuDetail, updateSpu} from "@/api/mall/product/spu";
197 209 import {getPropertyListAndValue,} from "@/api/mall/product/property";
198 210 import Editor from "@/components/Editor";
199 211 import ImageUpload from "@/components/ImageUpload";
... ... @@ -205,7 +217,7 @@ export default {
205 217 ImageUpload,
206 218 VideoUpload
207 219 },
208   - props:{
  220 + props: {
209 221 obj: Object
210 222 },
211 223 data() {
... ... @@ -256,7 +268,7 @@ export default {
256 268  
257 269 // 表单校验
258 270 rules: {
259   - name:[{required: true, message: "商品名称不能为空", trigger: "blur"},],
  271 + name: [{required: true, message: "商品名称不能为空", trigger: "blur"},],
260 272 description: [{required: true, message: "描述不能为空", trigger: "blur"},],
261 273 categoryIds: [{required: true, message: "分类id不能为空", trigger: "blur"},],
262 274 status: [{required: true, message: "商品状态不能为空", trigger: "blur"}],
... ... @@ -269,24 +281,24 @@ export default {
269 281 this.getListBrand();
270 282 this.getListCategory();
271 283 this.getPropertyPageList();
272   - if(this.obj.id != null){
  284 + if (this.obj.id != null) {
273 285 this.updateType(this.obj.id)
274 286 }
275 287 },
276 288 methods: {
277   - removeSpec(index){
278   - this.dynamicSpec.splice(index, 1);
279   - this.changeRadio()
  289 + removeSpec(index) {
  290 + this.dynamicSpec.splice(index, 1);
  291 + this.changeRadio()
280 292 },
281 293 // 必选标识
282   - addRedStar(h, { column }) {
  294 + addRedStar(h, {column}) {
283 295 return [
284   - h('span', { style: 'color: #F56C6C' }, '*'),
  296 + h('span', {style: 'color: #F56C6C'}, '*'),
285 297 h('span', ' ' + column.label)
286 298 ];
287 299 },
288 300 changeRadio() {
289   - this.activeSwitch ? this.ratesForm.spec = 2: this.ratesForm.spec = 1;
  301 + this.activeSwitch ? this.ratesForm.spec = 2 : this.ratesForm.spec = 1;
290 302 this.$refs.ratesTable.doLayout();
291 303 if (this.ratesForm.spec == 1) {
292 304 this.ratesForm.rates = [{}]
... ... @@ -334,7 +346,7 @@ export default {
334 346 this.categoryList = this.handleTree(response.data, "id", "parentId");
335 347 });
336 348 },
337   - /** 查询品牌列表 */
  349 + /** 查询品牌列表 */
338 350 getListBrand() {
339 351 // 执行查询
340 352 getBrandList().then((response) => {
... ... @@ -345,30 +357,30 @@ export default {
345 357 this.$emit("closeDialog");
346 358 },
347 359 submit() {
348   - this.$refs[this.activeName].validate((valid) => {
  360 + this.$refs[this.activeName].validate((valid) => {
349 361 if (!valid) {
350 362 return;
351 363 }
352   - let rates = this.ratesForm.rates;
  364 + let rates = this.ratesForm.rates;
353 365  
354   - // 价格元转分
355   - rates.forEach(r=>{
356   - r.marketPrice = r.marketPrice*100;
357   - r.price = r.price*100;
358   - r.costPrice = r.costPrice*100;
359   - })
360   -
361   - // 动态规格调整字段
362   - if (this.activeSwitch) {
  366 + // 价格元转分
363 367 rates.forEach(r => {
364   - let properties = []
  368 + r.marketPrice = r.marketPrice * 100;
  369 + r.price = r.price * 100;
  370 + r.costPrice = r.costPrice * 100;
  371 + })
  372 +
  373 + // 动态规格调整字段
  374 + if (this.activeSwitch) {
  375 + rates.forEach(r => {
  376 + let properties = []
365 377 Array.of(r.spec).forEach(s => {
366 378 let obj;
367   - if (s instanceof Array) {
368   - obj = s;
369   - }else{
370   - obj = Array.of(s);
371   - }
  379 + if (s instanceof Array) {
  380 + obj = s;
  381 + } else {
  382 + obj = Array.of(s);
  383 + }
372 384 obj.forEach((v, i) => {
373 385 let specValue = this.dynamicSpec[i].specValue.find(o => o.name == v);
374 386 let propertie = {};
... ... @@ -377,35 +389,35 @@ export default {
377 389 properties.push(propertie);
378 390 })
379 391 })
380   - r.properties = properties;
381   - })
382   - }else{
383   - rates[0].name = this.baseForm.name;
384   - rates[0].status = this.baseForm.status;
385   - }
386   - let form = this.baseForm
387   - if(form.picUrls instanceof Array){
388   - form.picUrls = form.picUrls.flatMap(m=>m.split(','))
389   - }else if(form.picUrls.split(',') instanceof Array){
390   - form.picUrls = form.picUrls.split(',').flatMap(m=>m.split(','))
391   - }else{
392   - form.picUrls = Array.of(form.picUrls)
393   - }
394   - form.skus = rates;
395   - form.specType = this.ratesForm.spec;
396   - form.categoryId = form.categoryIds[this.baseForm.categoryIds.length - 1];
397   -
398   - if(form.id == null){
399   - createSpu(form).then((response) => {
400   - this.$modal.msgSuccess("新增成功");
401   - this.$emit("closeDialog");
402   - })
403   - }else{
404   - updateSpu(form).then((response) => {
405   - this.$modal.msgSuccess("修改成功");
406   - this.$emit("closeDialog");
407   - })
408   - }
  392 + r.properties = properties;
  393 + })
  394 + } else {
  395 + rates[0].name = this.baseForm.name;
  396 + rates[0].status = this.baseForm.status;
  397 + }
  398 + let form = this.baseForm
  399 + if (form.picUrls instanceof Array) {
  400 + form.picUrls = form.picUrls.flatMap(m => m.split(','))
  401 + } else if (form.picUrls.split(',') instanceof Array) {
  402 + form.picUrls = form.picUrls.split(',').flatMap(m => m.split(','))
  403 + } else {
  404 + form.picUrls = Array.of(form.picUrls)
  405 + }
  406 + form.skus = rates;
  407 + form.specType = this.ratesForm.spec;
  408 + form.categoryId = form.categoryIds[this.baseForm.categoryIds.length - 1];
  409 +
  410 + if (form.id == null) {
  411 + createSpu(form).then((response) => {
  412 + this.$modal.msgSuccess("新增成功");
  413 + this.$emit("closeDialog");
  414 + })
  415 + } else {
  416 + updateSpu(form).then((response) => {
  417 + this.$modal.msgSuccess("修改成功");
  418 + this.$emit("closeDialog");
  419 + })
  420 + }
409 421 });
410 422  
411 423 },
... ... @@ -425,46 +437,46 @@ export default {
425 437 spec.specValue = obj.values;
426 438 this.buildRatesFormRates();
427 439 },
428   - updateType(id){
429   - getSpuDetail(id).then((response) =>{
430   - let data = response.data;
431   - this.baseForm.id=data.id;
432   - this.baseForm.name=data.name;
433   - this.baseForm.sellPoint=data.sellPoint;
434   - this.baseForm.categoryIds=data.categoryIds;
435   - this.baseForm.videoUrl = data.videoUrl;
436   - this.baseForm.sort=data.sort;
437   - this.baseForm.description=data.description;
438   - this.baseForm.picUrls=data.picUrls;
439   - this.baseForm.status=data.status;
440   - this.baseForm.virtualSalesCount=data.virtualSalesCount;
441   - this.baseForm.showStock=data.showStock;
442   - this.baseForm.brandId=data.brandId;
443   - this.ratesForm.spec=data.specType;
444   - data.skus.forEach(r=>{
445   - r.marketPrice = this.divide(r.marketPrice, 100)
446   - r.price = this.divide(r.price, 100)
447   - r.costPrice = this.divide(r.costPrice, 100)
448   - })
449   - if(this.ratesForm.spec == 2){
450   - this.activeSwitch = true;
451   - data.productPropertyViews.forEach(p=>{
452   - let obj = {};
453   - obj.specId = p.propertyId;
454   - obj.specName = p.name;
455   - obj.specValue = p.propertyValues;
456   - this.dynamicSpec.push(obj);
457   - })
458   - data.skus.forEach(s=>{
459   - s.spec = [];
460   - s.properties.forEach(sp=>{
461   - let spec = data.productPropertyViews.find(o=>o.propertyId == sp.propertyId).propertyValues.find(v=>v.id == sp.valueId).name;
462   - s.spec.push(spec)
463   - })
464   - })
465   - }
466   - this.ratesForm.rates=data.skus
  440 + updateType(id) {
  441 + getSpuDetail(id).then((response) => {
  442 + let data = response.data;
  443 + this.baseForm.id = data.id;
  444 + this.baseForm.name = data.name;
  445 + this.baseForm.sellPoint = data.sellPoint;
  446 + this.baseForm.categoryIds = data.categoryIds;
  447 + this.baseForm.videoUrl = data.videoUrl;
  448 + this.baseForm.sort = data.sort;
  449 + this.baseForm.description = data.description;
  450 + this.baseForm.picUrls = data.picUrls;
  451 + this.baseForm.status = data.status;
  452 + this.baseForm.virtualSalesCount = data.virtualSalesCount;
  453 + this.baseForm.showStock = data.showStock;
  454 + this.baseForm.brandId = data.brandId;
  455 + this.ratesForm.spec = data.specType;
  456 + data.skus.forEach(r => {
  457 + r.marketPrice = this.divide(r.marketPrice, 100)
  458 + r.price = this.divide(r.price, 100)
  459 + r.costPrice = this.divide(r.costPrice, 100)
467 460 })
  461 + if (this.ratesForm.spec == 2) {
  462 + this.activeSwitch = true;
  463 + data.productPropertyViews.forEach(p => {
  464 + let obj = {};
  465 + obj.specId = p.propertyId;
  466 + obj.specName = p.name;
  467 + obj.specValue = p.propertyValues;
  468 + this.dynamicSpec.push(obj);
  469 + })
  470 + data.skus.forEach(s => {
  471 + s.spec = [];
  472 + s.properties.forEach(sp => {
  473 + let spec = data.productPropertyViews.find(o => o.propertyId == sp.propertyId).propertyValues.find(v => v.id == sp.valueId).name;
  474 + s.spec.push(spec)
  475 + })
  476 + })
  477 + }
  478 + this.ratesForm.rates = data.skus
  479 + })
468 480 },
469 481  
470 482 },
... ... @@ -557,13 +569,14 @@ export default {
557 569 }
558 570 }
559 571  
560   -.mall-image{
561   - .el-upload--picture-card{
  572 +.mall-image {
  573 + .el-upload--picture-card {
562 574 width: 80px;
563 575 height: 80px;
564 576 line-height: 90px;
565 577 }
566   - .el-upload-list__item{
  578 +
  579 + .el-upload-list__item {
567 580 width: 80px;
568 581 height: 80px;
569 582 }
... ...