Commit a11dd1be282b9c92d70b60458958c4d65690ba1e

Authored by YunaiV
2 parents f03d679f 8de29d30

Merge remote-tracking branch 'origin/feature/1.8.0-uniapp' into feature/1.8.0-uniapp

# Conflicts:
#	yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
#	yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/spu/vo/ProductSpuBaseVO.java
#	yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
#	yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
sql/optional/mall/mall.sql
... ... @@ -298,3 +298,27 @@ INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `
298 298 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2027, 'Banner创建', 'market:banner:create', 3, 2, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
299 299 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2028, 'Banner更新', 'market:banner:update', 3, 3, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
300 300 INSERT INTO `ruoyi-vue-pro`.`system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `status`, `visible`, `keep_alive`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (2029, 'Banner删除', 'market:banner:delete', 3, 4, 2025, '', '', '', 0, b'1', b'1', '', '2022-08-01 14:56:14', '', '2022-08-01 14:56:14', b'0');
  301 +
  302 +alter table product_spu add `code` varchar(128) COMMENT '商品编码';
  303 +alter table product_spu add total_stock int COMMENT '总库存';
  304 +alter table product_spu add warn_stock int COMMENT '预警预存';
  305 +alter table product_spu add show_stock int COMMENT '是否展示库存';
  306 +alter table product_spu add sales_count int COMMENT '商品销量';
  307 +alter table product_spu add virtual_sales_count int COMMENT '虚拟销量';
  308 +alter table product_spu add click_count int COMMENT '商品点击量';
  309 +alter table product_spu add banner_url varchar(128) COMMENT '主图地址';
  310 +alter table product_spu add spec_type int COMMENT '规格类型';
  311 +alter table product_spu add brand_id int COMMENT '商品品牌编号';
  312 +alter table product_spu add video_url varchar(128) COMMENT '商品视频';
  313 +alter table product_spu add min_price int COMMENT '最小价格,单位使用:分';
  314 +alter table product_spu add max_price int COMMENT '最大价格,单位使用:分';
  315 +alter table product_spu add market_price int COMMENT '市场价,单位使用:分';
  316 +
  317 +
  318 +alter table product_sku add `name` varchar(128) COMMENT '商品 SKU 名字';
  319 +alter table product_sku add `stock` int COMMENT '库存';
  320 +alter table product_sku add `weight` double COMMENT '商品重量';
  321 +alter table product_sku add `volume` double COMMENT '商品体积';
  322 +
  323 +
  324 +alter table product_sku DROP `original_price`;
301 325 \ No newline at end of file
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/admin/sku/vo/ProductSkuBaseVO.java
... ... @@ -38,7 +38,6 @@ public class ProductSkuBaseVO {
38 38 private Integer costPrice;
39 39  
40 40 @ApiModelProperty(value = "条形码", example = "haha")
41   - @NotNull(message = "条形码不能为空")
42 41 private String barCode;
43 42  
44 43 @ApiModelProperty(value = "图片地址")
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/property/ProductPropertyServiceImpl.java
... ... @@ -49,7 +49,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
49 49 //插入属性值
50 50 List<ProductPropertyValueCreateReqVO> propertyValueList = createReqVO.getPropertyValueList();
51 51 List<ProductPropertyValueDO> productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
52   - productPropertyValueDOList.stream().forEach(x-> x.setPropertyId(property.getId()));
  52 + productPropertyValueDOList.forEach(x-> x.setPropertyId(property.getId()));
53 53 productPropertyValueMapper.insertBatch(productPropertyValueDOList);
54 54 // 返回
55 55 return property.getId();
... ... @@ -67,7 +67,7 @@ public class ProductPropertyServiceImpl implements ProductPropertyService {
67 67 productPropertyValueMapper.deletePropertyValueByPropertyId(updateReqVO.getId());
68 68 List<ProductPropertyValueCreateReqVO> propertyValueList = updateReqVO.getPropertyValueList();
69 69 List<ProductPropertyValueDO> productPropertyValueDOList = ProductPropertyValueConvert.INSTANCE.convertList03(propertyValueList);
70   - productPropertyValueDOList.stream().forEach(x-> x.setPropertyId(updateReqVO.getId()));
  70 + productPropertyValueDOList.forEach(x-> x.setPropertyId(updateReqVO.getId()));
71 71 productPropertyValueMapper.insertBatch(productPropertyValueDOList);
72 72 }
73 73  
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/sku/ProductSkuServiceImpl.java
... ... @@ -2,9 +2,14 @@ package cn.iocoder.yudao.module.product.service.sku;
2 2  
3 3 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
4 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyCreateReqVO;
5 6 import cn.iocoder.yudao.module.product.controller.admin.property.vo.ProductPropertyRespVO;
  7 +import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueCreateReqVO;
6 8 import cn.iocoder.yudao.module.product.controller.admin.propertyvalue.vo.ProductPropertyValueRespVO;
7   -import cn.iocoder.yudao.module.product.controller.admin.sku.vo.*;
  9 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuBaseVO;
  10 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuCreateReqVO;
  11 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuPageReqVO;
  12 +import cn.iocoder.yudao.module.product.controller.admin.sku.vo.ProductSkuUpdateReqVO;
8 13 import cn.iocoder.yudao.module.product.convert.sku.ProductSkuConvert;
9 14 import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
10 15 import cn.iocoder.yudao.module.product.dal.mysql.sku.ProductSkuMapper;
... ... @@ -84,11 +89,9 @@ public class ProductSkuServiceImpl implements ProductSkuService {
84 89 return productSkuMapper.selectPage(pageReqVO);
85 90 }
86 91  
87   - // TODO @franky:这个方法,貌似实现的还是有点问题哈。例如说,throw 异常,后面还执行逻辑~
88   - // TODO @艿艿 咳咳,throw 那里我是偷懒省略了{},哈哈,我加上,然后我调试下,在优化下
89 92 @Override
90   - public void validateSkus(List<ProductSkuCreateOrUpdateReqVO> list) {
91   - List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> p.getProperties().stream()).collect(Collectors.toList());
  93 + public void validateSkus(List<ProductSkuCreateReqVO> list) {
  94 + List<ProductSkuBaseVO.Property> skuPropertyList = list.stream().flatMap(p -> Optional.of(p.getProperties()).orElse(new ArrayList<>()).stream()).collect(Collectors.toList());
92 95 // 校验规格属性以及规格值是否存在
93 96 List<Long> propertyIds = skuPropertyList.stream().map(ProductSkuBaseVO.Property::getPropertyId).collect(Collectors.toList());
94 97 List<ProductPropertyRespVO> propertyAndValueList = productPropertyService.selectByIds(propertyIds);
... ... @@ -99,8 +102,9 @@ public class ProductSkuServiceImpl implements ProductSkuService {
99 102 skuPropertyList.forEach(p -> {
100 103 ProductPropertyRespVO productPropertyRespVO = propertyMap.get(p.getPropertyId());
101 104 // 如果对应的属性名不存在或属性名下的属性值集合为空,给出提示
102   - if (null == productPropertyRespVO || productPropertyRespVO.getPropertyValueList().isEmpty())
  105 + if (null == productPropertyRespVO || productPropertyRespVO.getPropertyValueList().isEmpty()) {
103 106 throw ServiceExceptionUtil.exception(PROPERTY_NOT_EXISTS);
  107 + }
104 108 // 判断改属性名对应的属性值是否存在,不存在,给出提示
105 109 if (!productPropertyRespVO.getPropertyValueList().stream().map(ProductPropertyValueRespVO::getId).collect(Collectors.toSet()).contains(p.getValueId())) {
106 110 throw ServiceExceptionUtil.exception(ErrorCodeConstants.PROPERTY_VALUE_NOT_EXISTS);
... ...
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/spu/ProductSpuServiceImpl.java
... ... @@ -56,8 +56,10 @@ public class ProductSpuServiceImpl implements ProductSpuService {
56 56 // 校验分类
57 57 categoryService.validateProductCategory(createReqVO.getCategoryId());
58 58 // 校验SKU
59   - List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = createReqVO.getSkus();
60   - productSkuService.validateSkus(skuCreateReqList);
  59 + List<ProductSkuCreateReqVO> skuCreateReqList = createReqVO.getSkus();
  60 + if(createReqVO.getSpecType() == 1) {
  61 + productSkuService.validateSkus(skuCreateReqList);
  62 + }
61 63 // 插入SPU
62 64 ProductSpuDO spu = ProductSpuConvert.INSTANCE.convert(createReqVO);
63 65 ProductSpuMapper.insert(spu);
... ... @@ -76,8 +78,10 @@ public class ProductSpuServiceImpl implements ProductSpuService {
76 78 // 校验分类
77 79 categoryService.validateProductCategory(updateReqVO.getCategoryId());
78 80 // 校验SKU
79   - List<ProductSkuCreateOrUpdateReqVO> skuCreateReqList = updateReqVO.getSkus();
80   - productSkuService.validateSkus(skuCreateReqList);
  81 + List<ProductSkuCreateReqVO> skuCreateReqList = updateReqVO.getSkus();
  82 + if(updateReqVO.getSpecType() == 1) {
  83 + productSkuService.validateSkus(skuCreateReqList);
  84 + }
81 85 // 更新
82 86 ProductSpuDO updateObj = ProductSpuConvert.INSTANCE.convert(updateReqVO);
83 87 ProductSpuMapper.updateById(updateObj);
... ...
yudao-ui-admin/src/views/mall/product/spu/index.vue
1 1 <template>
2 2 <div class="app-container">
3   -
4 3 <!-- 搜索工作栏 -->
5   - <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
  4 + <el-form
  5 + :model="queryParams"
  6 + ref="queryForm"
  7 + size="small"
  8 + :inline="true"
  9 + v-show="showSearch"
  10 + label-width="68px"
  11 + >
6 12 <el-form-item label="商品名称" prop="name">
7   - <el-input v-model="queryParams.name" placeholder="请输入商品名称" clearable @keyup.enter.native="handleQuery"/>
  13 + <el-input
  14 + v-model="queryParams.name"
  15 + placeholder="请输入商品名称"
  16 + clearable
  17 + @keyup.enter.native="handleQuery"
  18 + />
8 19 </el-form-item>
9 20 <el-form-item label="卖点" prop="sellPoint">
10   - <el-input v-model="queryParams.sellPoint" placeholder="请输入卖点" clearable @keyup.enter.native="handleQuery"/>
  21 + <el-input
  22 + v-model="queryParams.sellPoint"
  23 + placeholder="请输入卖点"
  24 + clearable
  25 + @keyup.enter.native="handleQuery"
  26 + />
11 27 </el-form-item>
12 28 <el-form-item label="分类id" prop="categoryId">
13   - <el-input v-model="queryParams.categoryId" placeholder="请输入分类id" clearable @keyup.enter.native="handleQuery"/>
  29 + <el-input
  30 + v-model="queryParams.categoryId"
  31 + placeholder="请输入分类id"
  32 + clearable
  33 + @keyup.enter.native="handleQuery"
  34 + />
14 35 </el-form-item>
15 36 <el-form-item label="价格(分)" prop="price">
16   - <el-input v-model="queryParams.price" placeholder="请输入价格 单位使用:分" clearable @keyup.enter.native="handleQuery"/>
  37 + <el-input
  38 + v-model="queryParams.price"
  39 + placeholder="请输入价格 单位使用:分"
  40 + clearable
  41 + @keyup.enter.native="handleQuery"
  42 + />
17 43 </el-form-item>
18 44 <el-form-item label="库存数量" prop="quantity">
19   - <el-input v-model="queryParams.quantity" placeholder="请输入库存数量" clearable @keyup.enter.native="handleQuery"/>
  45 + <el-input
  46 + v-model="queryParams.quantity"
  47 + placeholder="请输入库存数量"
  48 + clearable
  49 + @keyup.enter.native="handleQuery"
  50 + />
20 51 </el-form-item>
21 52 <el-form-item label="状态" prop="status">
22   - <el-select v-model="queryParams.status" placeholder="请选择上下架状态" clearable size="small">
23   - <el-option label="请选择字典生成" value=""/>
24   - <el-option label="上架" value="0"/>
25   - <el-option label="下架" value="1"/>
  53 + <el-select
  54 + v-model="queryParams.status"
  55 + placeholder="请选择上下架状态"
  56 + clearable
  57 + size="small"
  58 + >
  59 + <el-option label="请选择字典生成" value="" />
  60 + <el-option label="上架" value="0" />
  61 + <el-option label="下架" value="1" />
26 62 </el-select>
27 63 </el-form-item>
28 64 <el-form-item label="创建时间">
29   - <el-date-picker v-model="dateRangeCreateTime" style="width: 240px" value-format="yyyy-MM-dd"
30   - type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"/>
  65 + <el-date-picker
  66 + v-model="dateRangeCreateTime"
  67 + style="width: 240px"
  68 + value-format="yyyy-MM-dd"
  69 + type="daterange"
  70 + range-separator="-"
  71 + start-placeholder="开始日期"
  72 + end-placeholder="结束日期"
  73 + />
31 74 </el-form-item>
32 75 <el-form-item>
33   - <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
  76 + <el-button type="primary" icon="el-icon-search" @click="handleQuery"
  77 + >搜索</el-button
  78 + >
34 79 <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
35 80 </el-form-item>
36 81 </el-form>
... ... @@ -38,257 +83,123 @@
38 83 <!-- 操作工具栏 -->
39 84 <el-row :gutter="10" class="mb8">
40 85 <el-col :span="1.5">
41   - <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
42   - v-hasPermi="['product:spu:create']">新增
  86 + <el-button
  87 + type="primary"
  88 + plain
  89 + icon="el-icon-plus"
  90 + size="mini"
  91 + @click="handleAdd"
  92 + v-hasPermi="['product:spu:create']"
  93 + >新增
43 94 </el-button>
44 95 </el-col>
45 96 <el-col :span="1.5">
46   - <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
47   - :loading="exportLoading"
48   - v-hasPermi="['product:spu:export']">导出
  97 + <el-button
  98 + type="warning"
  99 + plain
  100 + icon="el-icon-download"
  101 + size="mini"
  102 + @click="handleExport"
  103 + :loading="exportLoading"
  104 + v-hasPermi="['product:spu:export']"
  105 + >导出
49 106 </el-button>
50 107 </el-col>
51   - <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
  108 + <right-toolbar
  109 + :showSearch.sync="showSearch"
  110 + @queryTable="getList"
  111 + ></right-toolbar>
52 112 </el-row>
53 113  
54 114 <!-- 列表 -->
55 115 <el-table v-loading="loading" :data="list">
56   - <el-table-column label="主键" align="center" prop="id"/>
57   - <el-table-column label="商品名称" align="center" prop="name"/>
  116 + <el-table-column label="主键" align="center" prop="id" />
  117 + <el-table-column label="商品名称" align="center" prop="name" />
58 118 <!-- <el-table-column label="卖点" align="center" prop="sellPoint"/>-->
59 119 <!-- <el-table-column label="描述" align="center" prop="description"/>-->
60   - <el-table-column label="分类id" align="center" prop="categoryId"/>
  120 + <el-table-column label="分类id" align="center" prop="categoryId" />
61 121 <el-table-column label="商品主图地址" align="center" prop="picUrls">
62 122 <template slot-scope="scope">
63   - <img v-if="scope.row.picUrls" :src="scope.row.picUrls[0]" alt="分类图片" class="img-height"/>
  123 + <img
  124 + v-if="scope.row.picUrls"
  125 + :src="scope.row.picUrls[0]"
  126 + alt="分类图片"
  127 + class="img-height"
  128 + />
64 129 </template>
65 130 </el-table-column>
66   - <el-table-column label="排序字段" align="center" prop="sort"/>
67   - <el-table-column label="点赞初始人数" align="center" prop="likeCount"/>
68   - <el-table-column label="价格 (分)" align="center" prop="price"/>
69   - <el-table-column label="库存数量" align="center" prop="quantity"/>
  131 + <el-table-column label="排序字段" align="center" prop="sort" />
  132 + <el-table-column label="点赞初始人数" align="center" prop="likeCount" />
  133 + <el-table-column label="价格 (分)" align="center" prop="price" />
  134 + <el-table-column label="库存数量" align="center" prop="quantity" />
70 135 <!-- <el-table-column label="状态" align="center" prop="status"/>-->
71   - <el-table-column label="创建时间" align="center" prop="createTime" width="180">
  136 + <el-table-column
  137 + label="创建时间"
  138 + align="center"
  139 + prop="createTime"
  140 + width="180"
  141 + >
72 142 <template slot-scope="scope">
73 143 <span>{{ parseTime(scope.row.createTime) }}</span>
74 144 </template>
75 145 </el-table-column>
76   - <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
  146 + <el-table-column
  147 + label="操作"
  148 + align="center"
  149 + class-name="small-padding fixed-width"
  150 + >
77 151 <template slot-scope="scope">
78   - <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
79   - v-hasPermi="['product:spu:update']">修改
  152 + <el-button
  153 + size="mini"
  154 + type="text"
  155 + icon="el-icon-edit"
  156 + @click="handleUpdate(scope.row)"
  157 + v-hasPermi="['product:spu:update']"
  158 + >修改
80 159 </el-button>
81   - <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
82   - v-hasPermi="['product:spu:delete']">删除
  160 + <el-button
  161 + size="mini"
  162 + type="text"
  163 + icon="el-icon-delete"
  164 + @click="handleDelete(scope.row)"
  165 + v-hasPermi="['product:spu:delete']"
  166 + >删除
83 167 </el-button>
84 168 </template>
85 169 </el-table-column>
86 170 </el-table>
87 171 <!-- 分页组件 -->
88   - <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize"
89   - @pagination="getList"/>
  172 + <pagination
  173 + v-show="total > 0"
  174 + :total="total"
  175 + :page.sync="queryParams.pageNo"
  176 + :limit.sync="queryParams.pageSize"
  177 + @pagination="getList"
  178 + />
  179 +
90 180  
91   - <!-- 对话框(添加 / 修改) -->
92   - <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
93   - <el-form ref="form" :model="form" :rules="rules" label-width="80px">
94   - <el-form-item label="商品名称" prop="name">
95   - <el-input v-model="form.name" placeholder="请输入商品名称"/>
96   - </el-form-item>
97   - <el-form-item label="卖点" prop="sellPoint">
98   - <el-input v-model="form.sellPoint" placeholder="请输入卖点"/>
99   - </el-form-item>
100   - <el-form-item label="描述">
101   - <editor v-model="form.description" :min-height="192"/>
102   - </el-form-item>
103   - <el-form-item label="分类id" prop="categoryIds">
104   - <el-cascader
105   - v-model="form.categoryIds"
106   - placeholder="请输入分类id"
107   - style="width: 100%"
108   - :options="categoryList"
109   - :props="propName"
110   - clearable></el-cascader>
111   - </el-form-item>
112   - <el-form-item label="商品主图地址" prop="picUrls">
113   - <ImageUpload v-model="form.picUrls" :limit="10"/>
114   - </el-form-item>
115   - <el-form-item label="商品规格">
116   - <el-button size="mini" @click="shopTagInput()">添加规格</el-button>
117   - <div v-for="(tag, tagIndex) in skuTags" :key="tagIndex">
118   - <span>{{ tag.name }}</span>
119   - <el-button style="margin-left: 10px" class="button-new-tag" type="text" icon="el-icon-delete"
120   - @click="removeTag(tagIndex)">删除
121   - </el-button>
122   - <br/>
123   - <el-tag
124   - v-for="(tagItem, tagItemIndex) in tag.selectValues"
125   - :key="tagItem"
126   - style="margin-right: 10px"
127   - :disable-transitions="false">
128   - {{ tagItem }}
129   - </el-tag>
130   - <!-- <el-input-->
131   - <!-- class="input-new-tag"-->
132   - <!-- v-if="tagItemInputs[tagIndex] && tagItemInputs[tagIndex].visible"-->
133   - <!-- v-model="tagItemInputs[tagIndex].value"-->
134   - <!-- :ref="`saveTagInput${tagIndex}`"-->
135   - <!-- size="small"-->
136   - <!-- @keyup.enter.native="handleInputConfirm(tagIndex)"-->
137   - <!-- @blur="handleInputConfirm(tagIndex)">-->
138   - <!-- </el-input>-->
139   - </div>
140   - </el-form-item>
141   - <el-form-item label="规格名" v-show="isShowTagInput">
142   - <el-col :span="8">
143   - <el-select v-model="addTagInput.name" filterable allow-create default-first-option placeholder="请选择"
144   - @change="handleTagClick">
145   - <el-option
146   - v-for="item in unUseTags"
147   - :key="item.id"
148   - :label="item.name"
149   - :value="item.name">
150   - </el-option>
151   - </el-select>
152   - </el-col>
153   - </el-form-item>
154   - <el-form-item label="规格值" v-show="isShowTagInput">
155   - <el-col :span="8">
156   - <el-select v-model="addTagInput.selectValues" multiple filterable allow-create default-first-option
157   - placeholder="请选择">
158   - <el-option
159   - v-for="item in dbTagValues"
160   - :key="item.id"
161   - :label="item.name"
162   - :value="item.name">
163   - </el-option>
164   - </el-select>
165   - </el-col>
166   - </el-form-item>
167   - <el-form-item>
168   - <el-button size="mini" type="primary" @click="addTag()" v-show="isShowTagInput">确定</el-button>
169   - <el-button size="mini" @click="hideTagInput()" v-show="isShowTagInput">取消</el-button>
170   - </el-form-item>
171   - <el-form-item v-if="form.skus.length>0">
172   - <el-table
173   - :data="form.skus"
174   - border
175   - style="width: 100%; margin-top: 20px"
176   - :span-method="tableSpanMethod">
177   - <el-table-column v-for="(leftTitle, index) in skuTags" :key="index" :label="leftTitle.name">
178   - <template slot-scope="scope">
179   - {{ scope.row.propertyChildNames[index] }}
180   - </template>
181   - </el-table-column>
182   - <el-table-column v-if="skuTags.length"
183   - prop="picUrl"
184   - label="sku图片"
185   - width="180">
186   - <template slot-scope="scope">
187   - <ImageUpload v-model="scope.row.picUrl" :limit="1">
188   - </ImageUpload>
189   - </template>
190   - </el-table-column>
191   - <el-table-column
192   - prop="prodName"
193   - label="条形码"
194   - width="250" v-if="skuTags.length">
195   - <template slot-scope="scope">
196   - <el-input v-model="scope.row.barCode" type="textarea" :disabled="scope.row.status==1"></el-input>
197   - </template>
198   - </el-table-column>
199   - <el-table-column
200   - prop="price"
201   - label="销售价">
202   - <template slot-scope="scope">
203   - <el-input-number
204   - size="small"
205   - v-model="scope.row.price"
206   - controls-position="right"
207   - :precision="2"
208   - :max="1000000000"
209   - :min="0.01"
210   - :disabled="scope.row.status==1">
211   - </el-input-number>
212   - </template>
213   - </el-table-column>
214   - <el-table-column
215   - prop="oriPrice"
216   - label="成本价">
217   - <template slot-scope="scope">
218   - <el-input-number
219   - size="small"
220   - v-model="scope.row.costPrice"
221   - controls-position="right"
222   - :precision="2"
223   - :max="1000000000"
224   - :min="0.01"
225   - :disabled="scope.row.status==1">
226   - </el-input-number>
227   - </template>
228   - </el-table-column>
229   - <el-table-column
230   - prop="oriPrice"
231   - label="原价">
232   - <template slot-scope="scope">
233   - <el-input-number
234   - size="small"
235   - v-model="scope.row.originalPrice"
236   - controls-position="right"
237   - :precision="2"
238   - :max="1000000000"
239   - :min="0.01"
240   - :disabled="scope.row.status==1">
241   - </el-input-number>
242   - </template>
243   - </el-table-column>
244   - <el-table-column
245   - label="操作">
246   - <template slot-scope="scope">
247   - <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)"
248   - v-if="scope.row.status===0">
249   - 正常
250   - </el-button>
251   - <el-button type="text" size="small" @click="changeSkuStatus(`${scope.$index}`)" v-else>已禁用</el-button>
252   - </template>
253   - </el-table-column>
254   - </el-table>
255   - </el-form-item>
256   - <el-form-item label="排序字段" prop="sort">
257   - <el-input v-model="form.sort" placeholder="请输入排序字段"/>
258   - </el-form-item>
259   - <el-form-item label="点赞初始人数" prop="likeCount">
260   - <el-input v-model="form.likeCount" placeholder="请输入点赞初始人数"/>
261   - </el-form-item>
262   - <el-form-item label="价格 单位使用:分" prop="price">
263   - <el-input v-model="form.price" placeholder="请输入价格 单位使用:分"/>
264   - </el-form-item>
265   - <el-form-item label="库存数量" prop="quantity">
266   - <el-input v-model="form.quantity" placeholder="请输入库存数量"/>
267   - </el-form-item>
268   - <el-form-item label="上下架状态" prop="status">
269   - <el-radio-group v-model="form.status">
270   - <el-radio label="0">上架</el-radio>
271   - <el-radio label="1">下架</el-radio>
272   - </el-radio-group>
273   - </el-form-item>
274   - </el-form>
275   - <div slot="footer" class="dialog-footer">
276   - <el-button type="primary" @click="submitForm">确 定</el-button>
277   - <el-button @click="cancel">取 消</el-button>
278   - </div>
  181 + <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body destroy-on-close>
  182 + <save @closeDialog="open = false; getList()"/>
279 183 </el-dialog>
280 184 </div>
281 185 </template>
282 186  
283 187 <script>
284   -import {createSpu, updateSpu, deleteSpu, getSpu, getSpuPage, exportSpuExcel} from "@/api/mall/product/spu";
  188 +import {
  189 + createSpu,
  190 + updateSpu,
  191 + deleteSpu,
  192 + getSpu,
  193 + getSpuPage,
  194 + exportSpuExcel,
  195 +} from "@/api/mall/product/spu";
285 196 import {
286 197 createProductCategory,
287 198 deleteProductCategory,
288 199 exportCategoryExcel,
289 200 getProductCategory,
290 201 getProductCategoryList,
291   - updateProductCategory
  202 + updateProductCategory,
292 203 } from "@/api/mall/product/category";
293 204 import {
294 205 createProperty,
... ... @@ -296,16 +207,19 @@ import {
296 207 deleteProperty,
297 208 getProperty,
298 209 getPropertyPage,
299   - exportPropertyExcel
  210 + exportPropertyExcel,
300 211 } from "@/api/mall/product/property";
301 212  
302   -import Editor from '@/components/Editor';
303   -import ImageUpload from '@/components/ImageUpload';
  213 +import Editor from "@/components/Editor";
  214 +import ImageUpload from "@/components/ImageUpload";
  215 +import save from "./save";
304 216  
305 217 export default {
306 218 name: "Spu",
307 219 components: {
308   - Editor, ImageUpload
  220 + Editor,
  221 + ImageUpload,
  222 + save,
309 223 },
310 224 data() {
311 225 return {
... ... @@ -316,17 +230,17 @@ export default {
316 230 propertyPageList: [],
317 231 isShowTagInput: false,
318 232 addTagInput: {
319   - name: '',
320   - propertyId: '',
  233 + name: "",
  234 + propertyId: "",
321 235 selectValues: [],
322 236 selectValueIds: [],
323   - selectObect:[],
  237 + selectObect: [],
324 238 },
325 239 skuTags: [],
326 240 propName: {
327 241 checkStrictly: true,
328   - label: 'name',
329   - value: 'id'
  242 + label: "name",
  243 + value: "id",
330 244 },
331 245 categoryList: [],
332 246 // 遮罩层
... ... @@ -378,91 +292,101 @@ export default {
378 292 },
379 293 // 表单校验
380 294 rules: {
381   - sellPoint: [{required: true, message: "卖点不能为空", trigger: "blur"}],
382   - description: [{required: true, message: "描述不能为空", trigger: "blur"}],
383   - categoryIds: [{required: true, message: "分类id不能为空", trigger: "blur"}],
384   - picUrls: [{required: true, message: "商品主图地址", trigger: "blur"}],
385   - sort: [{required: true, message: "排序字段不能为空", trigger: "blur"}],
  295 + sellPoint: [
  296 + { required: true, message: "卖点不能为空", trigger: "blur" },
  297 + ],
  298 + description: [
  299 + { required: true, message: "描述不能为空", trigger: "blur" },
  300 + ],
  301 + categoryIds: [
  302 + { required: true, message: "分类id不能为空", trigger: "blur" },
  303 + ],
  304 + picUrls: [{ required: true, message: "商品主图地址", trigger: "blur" }],
  305 + sort: [
  306 + { required: true, message: "排序字段不能为空", trigger: "blur" },
  307 + ],
386 308 },
387 309 tagIndex: 0,
388 310 };
389 311 },
390 312 created() {
391   -
392 313 this.getList();
393 314 this.getPropertyPageList();
394 315 this.getListCategory();
395 316 },
396 317 methods: {
397 318 getTableSpecData() {
398   - return this.value
399   - },
400   - tableSpanMethod({row, column, rowIndex, columnIndex}) {
401   -
  319 + return this.value;
402 320 },
  321 + tableSpanMethod({ row, column, rowIndex, columnIndex }) {},
403 322 changeSkuStatus(tagIndex) {
404 323 if (this.form.skus[tagIndex].status == 0) {
405 324 this.form.skus[tagIndex].status = 1;
406 325 } else {
407 326 this.form.skus[tagIndex].status = 0;
408 327 }
409   -
410 328 },
411 329 skuAddProdName() {
412 330 if (this.initing) {
413   - return
  331 + return;
414 332 }
415   - let skuList = []
  333 + let skuList = [];
416 334 for (let i = 0; i < this.value.length; i++) {
417   - const sku = Object.assign({}, this.value[i])
  335 + const sku = Object.assign({}, this.value[i]);
418 336 if (!sku.properties) {
419   - return
  337 + return;
420 338 }
421   - sku.skuName = ''
422   - let properties = sku.properties.split(';')
  339 + sku.skuName = "";
  340 + let properties = sku.properties.split(";");
423 341 for (const propertiesKey in properties) {
424   - sku.skuName += properties[propertiesKey].split(':')[1] + ' '
  342 + sku.skuName += properties[propertiesKey].split(":")[1] + " ";
425 343 }
426   - sku.prodName = this.prodName + ' ' + sku.skuName
427   - skuList.push(sku)
  344 + sku.prodName = this.prodName + " " + sku.skuName;
  345 + skuList.push(sku);
428 346 }
429   - this.$emit('input', skuList)
430   - },
431   - handleTagClose(tagIndex, tagItemIndex) {
432   -
  347 + this.$emit("input", skuList);
433 348 },
  349 + handleTagClose(tagIndex, tagItemIndex) {},
434 350 //确定添加sku规格
435 351 addTag() {
436   -
437 352 let skus = this.unUseTags.map(function (item, index) {
438   - return item.name
  353 + return item.name;
439 354 });
440 355 let index = skus.indexOf(this.addTagInput.name);
441 356  
442 357 this.addTagInput.propertyId = this.unUseTags[index].id;
443 358 for (let i = 0; i < this.addTagInput.selectValues.length; i++) {
444   - for (let j = 0; j < this.unUseTags[index].propertyValueList.length; j++) {
445   - if (this.addTagInput.selectValues[i] === this.unUseTags[index].propertyValueList[j].name) {
446   - this.addTagInput.selectValueIds.push(this.unUseTags[index].propertyValueList[j].id)
  359 + for (
  360 + let j = 0;
  361 + j < this.unUseTags[index].propertyValueList.length;
  362 + j++
  363 + ) {
  364 + if (
  365 + this.addTagInput.selectValues[i] ===
  366 + this.unUseTags[index].propertyValueList[j].name
  367 + ) {
  368 + this.addTagInput.selectValueIds.push(
  369 + this.unUseTags[index].propertyValueList[j].id
  370 + );
447 371 this.addTagInput.selectObect.push({
448   - id:this.unUseTags[index].propertyValueList[j].id,
449   - name:this.unUseTags[index].propertyValueList[j].name,
450   - })
  372 + id: this.unUseTags[index].propertyValueList[j].id,
  373 + name: this.unUseTags[index].propertyValueList[j].name,
  374 + });
451 375 }
452 376 }
453 377 }
454   - let addTagInput = JSON.parse(JSON.stringify(this.addTagInput))
  378 + let addTagInput = JSON.parse(JSON.stringify(this.addTagInput));
455 379 this.skuTags.push(addTagInput);
456 380  
457 381 // if (this.skuTags.length > 1) {
458 382 this.skuTags = this.skuTags.sort((a, b) => a.propertyId - b.propertyId);
459   - this.skuTags.forEach(function (item,index) {
460   - item.selectObect = item.selectObect.sort((a, b) => a.id - b.id)
461   - })
  383 + this.skuTags.forEach(function (item, index) {
  384 + item.selectObect = item.selectObect.sort((a, b) => a.id - b.id);
  385 + });
462 386  
463   - for (let i = 0; i <this.skuTags.length ; i++) {
464   - let selectValueIds=[];
465   - let selectValues=[];
  387 + for (let i = 0; i < this.skuTags.length; i++) {
  388 + let selectValueIds = [];
  389 + let selectValues = [];
466 390 for (let j = 0; j < this.skuTags[i].selectObect.length; j++) {
467 391 selectValueIds.push(this.skuTags[i].selectObect[j].id);
468 392 selectValues.push(this.skuTags[i].selectObect[j].name);
... ... @@ -489,17 +413,23 @@ export default {
489 413 propertyNames.push(skuTags[i].name);
490 414 }
491 415  
492   - let skuAll = sku1s.reduce((x, y) => {
493   - let arr = [];
494   - x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
495   - return arr;
496   - }, [[]])
  416 + let skuAll = sku1s.reduce(
  417 + (x, y) => {
  418 + let arr = [];
  419 + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y]))));
  420 + return arr;
  421 + },
  422 + [[]]
  423 + );
497 424  
498   - let skuIdAll = skuIds.reduce((x, y) => {
499   - let arr = [];
500   - x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
501   - return arr;
502   - }, [[]])
  425 + let skuIdAll = skuIds.reduce(
  426 + (x, y) => {
  427 + let arr = [];
  428 + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y]))));
  429 + return arr;
  430 + },
  431 + [[]]
  432 + );
503 433  
504 434 for (let i = 0; i < skuAll.length; i++) {
505 435 let han = {
... ... @@ -508,33 +438,32 @@ export default {
508 438 propertyChildNames: skuAll[i],
509 439 propertyChildIds: skuIdAll[i],
510 440 properties: [],
511   - picUrl: '',
512   - costPrice: '',
513   - originalPrice: '',
514   - spuId: '',
515   - prodName: '',
516   - price: '',
517   - barCode: '',
518   - status: '0',
519   - }
  441 + picUrl: "",
  442 + costPrice: "",
  443 + originalPrice: "",
  444 + spuId: "",
  445 + prodName: "",
  446 + price: "",
  447 + barCode: "",
  448 + status: "0",
  449 + };
520 450 this.form.skus.push(han);
521 451 }
522   - this.form.skus.forEach(x => {
  452 + this.form.skus.forEach((x) => {
523 453 x.properties = [];
524 454 for (let i = 0; i < x.propertyIds.length; i++) {
525 455 x.properties.push({
526 456 propertyId: x.propertyIds[i],
527   - valueId: x.propertyChildIds[i]
528   - })
  457 + valueId: x.propertyChildIds[i],
  458 + });
529 459 }
530   - })
531   -
  460 + });
532 461 },
533 462 hideTagInput() {
534 463 this.isShowTagInput = false;
535 464 this.addTagInput = {
536   - name: '',
537   - propertyId: '',
  465 + name: "",
  466 + propertyId: "",
538 467 selectValues: [],
539 468 selectValueIds: [],
540 469 selectObect: [],
... ... @@ -542,12 +471,12 @@ export default {
542 471 },
543 472 shopTagInput() {
544 473 if (this.unUseTags.length <= 0) {
545   - return this.$message.error("规格已经添加完毕")
  474 + return this.$message.error("规格已经添加完毕");
546 475 }
547 476 this.isShowTagInput = true;
548 477 this.addTagInput = {
549   - name: '',
550   - propertyId: '',
  478 + name: "",
  479 + propertyId: "",
551 480 selectValues: [],
552 481 selectValueIds: [],
553 482 selectObect: [],
... ... @@ -556,8 +485,8 @@ export default {
556 485 //删除已选的规格
557 486 removeTag(row) {
558 487 let skus = this.allhistoryTags.map(function (item, index) {
559   - return item.name
560   - })
  488 + return item.name;
  489 + });
561 490 let index = skus.indexOf(this.skuTags[row].name);
562 491 this.unUseTags.push(this.allhistoryTags[index]);
563 492 this.skuTags.splice(row, 1);
... ... @@ -566,38 +495,37 @@ export default {
566 495 handleTagClick(row) {
567 496 for (let i = 0; i < this.propertyPageList.length; i++) {
568 497 if (row == this.propertyPageList[i].name) {
569   - this.dbTagValues = this.propertyPageList[i].propertyValueList
  498 + this.dbTagValues = this.propertyPageList[i].propertyValueList;
570 499 }
571 500 }
572 501 },
573 502 /** 查询规格 */
574 503 getPropertyPageList() {
575 504 // 执行查询
576   - getPropertyPage().then(response => {
  505 + getPropertyPage().then((response) => {
577 506 this.propertyPageList = response.data.list;
578 507  
579 508 this.unUseTags = this.propertyPageList.map(function (item, index) {
580   - return item
581   - })
  509 + return item;
  510 + });
582 511 this.allhistoryTags = JSON.parse(JSON.stringify(this.unUseTags));
583 512 });
584 513 },
585 514 /** 查询分类 */
586 515 getListCategory() {
587 516 // 执行查询
588   - getProductCategoryList().then(response => {
  517 + getProductCategoryList().then((response) => {
589 518 this.categoryList = this.handleTree(response.data, "id", "parentId");
590   -
591 519 });
592 520 },
593 521 /** 查询列表 */
594 522 getList() {
595 523 this.loading = true;
596 524 // 处理查询参数
597   - let params = {...this.queryParams};
598   - this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  525 + let params = { ...this.queryParams };
  526 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime");
599 527 // 执行查询
600   - getSpuPage(params).then(response => {
  528 + getSpuPage(params).then((response) => {
601 529 this.list = response.data.list;
602 530 this.total = response.data.total;
603 531 this.loading = false;
... ... @@ -610,7 +538,6 @@ export default {
610 538 },
611 539 /** 表单重置 */
612 540 reset() {
613   -
614 541 this.form = {
615 542 id: undefined,
616 543 name: undefined,
... ... @@ -652,7 +579,7 @@ export default {
652 579 handleUpdate(row) {
653 580 this.reset();
654 581 const id = row.id;
655   - getSpu(id).then(response => {
  582 + getSpu(id).then((response) => {
656 583 let dataSpu = response.data;
657 584 this.form = {
658 585 id: dataSpu.id,
... ... @@ -680,11 +607,15 @@ export default {
680 607 },
681 608 getDataHandle() {
682 609 let that = this;
683   - let productPropertyViews = JSON.parse(JSON.stringify(this.form.productPropertyViews));
684   - productPropertyViews = productPropertyViews.sort((a, b) => a.propertyId - b.propertyId);
685   - productPropertyViews.forEach(item => {
  610 + let productPropertyViews = JSON.parse(
  611 + JSON.stringify(this.form.productPropertyViews)
  612 + );
  613 + productPropertyViews = productPropertyViews.sort(
  614 + (a, b) => a.propertyId - b.propertyId
  615 + );
  616 + productPropertyViews.forEach((item) => {
686 617 item.propertyValues = item.propertyValues.sort((a, b) => a.v1 - b.v1);
687   - })
  618 + });
688 619 let skuIds = [];
689 620 for (let i = 0; i < productPropertyViews.length; i++) {
690 621 let han = {
... ... @@ -692,17 +623,21 @@ export default {
692 623 propertyId: productPropertyViews[i].propertyId,
693 624 selectValues: [],
694 625 selectValueIds: [],
695   - }
696   - for (let j = 0; j < productPropertyViews[i].propertyValues.length; j++) {
  626 + };
  627 + for (
  628 + let j = 0;
  629 + j < productPropertyViews[i].propertyValues.length;
  630 + j++
  631 + ) {
697 632 han.selectValues.push(productPropertyViews[i].propertyValues[j].v2);
698 633 han.selectValueIds.push(productPropertyViews[i].propertyValues[j].v1);
699 634 }
700   - skuIds.push(han)
  635 + skuIds.push(han);
701 636 }
702 637 this.skuTags = skuIds;
703 638 this.unUseTags = this.allhistoryTags.filter((v) =>
704   - skuIds.every((val) => val.name != v.name)
705   - )
  639 + skuIds.every((val) => val.name != v.name)
  640 + );
706 641 this.getHandleTable();
707 642 },
708 643 getHandleTable() {
... ... @@ -718,17 +653,23 @@ export default {
718 653 propertyIds.push(skuTags[i].propertyId);
719 654 propertyNames.push(skuTags[i].name);
720 655 }
721   - let skuAll = sku1s.reduce((x, y) => {
722   - let arr = [];
723   - x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
724   - return arr;
725   - }, [[]])
  656 + let skuAll = sku1s.reduce(
  657 + (x, y) => {
  658 + let arr = [];
  659 + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y]))));
  660 + return arr;
  661 + },
  662 + [[]]
  663 + );
726 664  
727   - let skuIdAll = skuIds.reduce((x, y) => {
728   - let arr = [];
729   - x.forEach(m => y.forEach(y => arr.push(m.concat([y]))))
730   - return arr;
731   - }, [[]])
  665 + let skuIdAll = skuIds.reduce(
  666 + (x, y) => {
  667 + let arr = [];
  668 + x.forEach((m) => y.forEach((y) => arr.push(m.concat([y]))));
  669 + return arr;
  670 + },
  671 + [[]]
  672 + );
732 673  
733 674 for (let i = 0; i < skuAll.length; i++) {
734 675 let han = {
... ... @@ -745,33 +686,32 @@ export default {
745 686 price: this.form.skusList[i].price,
746 687 barCode: this.form.skusList[i].barCode,
747 688 status: this.form.skusList[i].status,
748   - }
  689 + };
749 690 this.form.skus.push(han);
750 691 }
751   - this.form.skus.forEach(x => {
  692 + this.form.skus.forEach((x) => {
752 693 x.properties = [];
753 694 for (let i = 0; i < x.propertyIds.length; i++) {
754 695 x.properties.push({
755 696 propertyId: x.propertyIds[i],
756   - valueId: x.propertyChildIds[i]
757   - })
  697 + valueId: x.propertyChildIds[i],
  698 + });
758 699 }
759   - })
760   -
  700 + });
761 701 },
762 702 /** 提交按钮 */
763 703 submitForm() {
764   -
765   - this.$refs["form"].validate(valid => {
  704 + this.$refs["form"].validate((valid) => {
766 705 if (!valid) {
767 706 return;
768 707 }
769   - this.form.picUrls = this.form.picUrls.split(',');
770   - this.form.categoryId = this.form.categoryIds[(this.form.categoryIds.length - 1)];
  708 + this.form.picUrls = this.form.picUrls.split(",");
  709 + this.form.categoryId =
  710 + this.form.categoryIds[this.form.categoryIds.length - 1];
771 711 this.form.status = Number(this.form.status);
772 712 // 修改的提交
773 713 if (this.form.id != null) {
774   - updateSpu(this.form).then(response => {
  714 + updateSpu(this.form).then((response) => {
775 715 this.$modal.msgSuccess("修改成功");
776 716 this.open = false;
777 717 this.getList();
... ... @@ -779,7 +719,7 @@ export default {
779 719 return;
780 720 }
781 721 // 添加的提交
782   - createSpu(this.form).then(response => {
  722 + createSpu(this.form).then((response) => {
783 723 this.$modal.msgSuccess("新增成功");
784 724 this.open = false;
785 725 this.getList();
... ... @@ -789,32 +729,38 @@ export default {
789 729 /** 删除按钮操作 */
790 730 handleDelete(row) {
791 731 const id = row.id;
792   - this.$modal.confirm('是否确认删除商品spu编号为"' + id + '"的数据项?').then(function () {
793   - return deleteSpu(id);
794   - }).then(() => {
795   - this.getList();
796   - this.$modal.msgSuccess("删除成功");
797   - }).catch(() => {
798   - });
  732 + this.$modal
  733 + .confirm('是否确认删除商品spu编号为"' + id + '"的数据项?')
  734 + .then(function () {
  735 + return deleteSpu(id);
  736 + })
  737 + .then(() => {
  738 + this.getList();
  739 + this.$modal.msgSuccess("删除成功");
  740 + })
  741 + .catch(() => {});
799 742 },
800 743 /** 导出按钮操作 */
801 744 handleExport() {
802 745 // 处理查询参数
803   - let params = {...this.queryParams};
  746 + let params = { ...this.queryParams };
804 747 params.pageNo = undefined;
805 748 params.pageSize = undefined;
806   - this.addBeginAndEndTime(params, this.dateRangeCreateTime, 'createTime');
  749 + this.addBeginAndEndTime(params, this.dateRangeCreateTime, "createTime");
807 750 // 执行导出
808   - this.$modal.confirm('是否确认导出所有商品spu数据项?').then(() => {
809   - this.exportLoading = true;
810   - return exportSpuExcel(params);
811   - }).then(response => {
812   - this.$download.excel(response, '商品spu.xls');
813   - this.exportLoading = false;
814   - }).catch(() => {
815   - });
816   - }
817   - }
  751 + this.$modal
  752 + .confirm("是否确认导出所有商品spu数据项?")
  753 + .then(() => {
  754 + this.exportLoading = true;
  755 + return exportSpuExcel(params);
  756 + })
  757 + .then((response) => {
  758 + this.$download.excel(response, "商品spu.xls");
  759 + this.exportLoading = false;
  760 + })
  761 + .catch(() => {});
  762 + },
  763 + },
818 764 };
819 765 </script>
820 766 <style lang="scss">
... ...
yudao-ui-admin/src/views/mall/product/spu/save.vue 0 → 100644
  1 +<template>
  2 + <div class="container">
  3 + <el-tabs v-model="activeName" class="tabs">
  4 + <!-- 基础设置 -->
  5 + <el-tab-pane label="基础设置" name="base">
  6 + <el-form ref="baseForm" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
  7 + <el-form-item label="商品名称" prop="name">
  8 + <el-input v-model="baseForm.name" placeholder="请输入商品名称"/>
  9 + </el-form-item>
  10 + <el-form-item label="卖点" prop="sellPoint">
  11 + <el-input v-model="baseForm.sellPoint" placeholder="请输入卖点"/>
  12 + </el-form-item>
  13 + <el-form-item label="分类id" prop="categoryIds">
  14 + <el-cascader
  15 + v-model="baseForm.categoryIds"
  16 + placeholder="请输入分类id"
  17 + style="width: 100%"
  18 + :options="categoryList"
  19 + :props="propName"
  20 + clearable
  21 + ></el-cascader>
  22 + </el-form-item>
  23 + <el-form-item label="商品主图" prop="bannerUrl">
  24 + <ImageUpload v-model="baseForm.bannerUrl" :limit="1"/>
  25 + </el-form-item>
  26 + <el-form-item label="商品轮播图" prop="picUrls">
  27 + <ImageUpload v-model="baseForm.picUrls" :limit="10"/>
  28 + </el-form-item>
  29 + <el-form-item label="排序字段" prop="sort">
  30 + <el-input v-model="baseForm.sort" placeholder="请输入排序字段"/>
  31 + </el-form-item>
  32 + </el-form>
  33 + </el-tab-pane>
  34 +
  35 + <!-- 价格库存 -->
  36 + <el-tab-pane label="价格库存" name="rates" class="rates">
  37 + <el-form :model="ratesForm" :rules="rules.ratesForm">
  38 + <el-form-item label="商品规格">
  39 + <el-radio-group v-model="ratesForm.spec" @change="changeRadio">
  40 + <el-radio :label="0">单规格</el-radio>
  41 + <el-radio :label="1">多规格</el-radio>
  42 + </el-radio-group>
  43 + </el-form-item>
  44 +
  45 + <!-- 动态添加规格属性 -->
  46 + <div v-show="ratesForm.spec === 1">
  47 + <div
  48 + v-for="(specs, index) in dynamicSpec"
  49 + :key="index"
  50 + class="dynamic-spec"
  51 + >
  52 + <!-- 删除按钮 -->
  53 + <el-button
  54 + type="danger"
  55 + icon="el-icon-delete"
  56 + circle
  57 + class="spec-delete"
  58 + @click="dynamicSpec.splice(index, 1)"
  59 + ></el-button>
  60 +
  61 + <div class="spec-header">
  62 + 规格项:
  63 + <el-select v-model="specs.specId" filterable placeholder="请选择" @change="changeSpec">
  64 + <el-option
  65 + v-for="item in propertyPageList"
  66 + :key="item.id"
  67 + :label="item.name"
  68 + :value="item.id">
  69 + </el-option>
  70 + </el-select>
  71 + </div>
  72 + <div class="spec-values">
  73 + <template v-for="(v, i) in specs.specValue">
  74 + <el-input v-model="v.name" class="spec-value" :key="i"/>
  75 + </template>
  76 + <!-- <el-button
  77 + type="primary"
  78 + icon="el-icon-plus"
  79 + circle
  80 + @click="dialogForSpec = true; currentSpec = index"
  81 + ></el-button> -->
  82 + </div>
  83 + </div>
  84 + <el-button type="primary" @click="dynamicSpec.push({specValue: []}); ratesForm.rates = []"
  85 + >添加规格项目
  86 + </el-button
  87 + >
  88 + </div>
  89 +
  90 + <!-- 规格明细 -->
  91 + <el-form-item label="规格明细">
  92 + <el-table :data="ratesForm.rates" border style="width: 100%" ref="rates">
  93 +
  94 + <template v-if="ratesForm.spec == 1">
  95 + <el-table-column :key="index" v-for="(item, index) in dynamicSpec.filter(v=>v.specName != undefined)"
  96 + :label="item.specName">
  97 + <template slot-scope="scope">
  98 + <el-input
  99 + v-if="scope.row.spec"
  100 + v-model="scope.row.spec[index]"
  101 + disabled
  102 + ></el-input>
  103 + </template>
  104 + </el-table-column>
  105 + </template>
  106 +
  107 + <el-table-column label="规格图片" width="120px">
  108 + <template slot-scope="scope">
  109 + <ImageUpload v-model="scope.row.picUrl" :limit="1" :isShowTip="false"
  110 + style="width: 100px; height: 50px"/>
  111 + </template>
  112 + </el-table-column>
  113 + <el-table-column label="市场价(元)">
  114 + <template slot-scope="scope">
  115 + <el-input
  116 + v-model="scope.row.marketPrice"
  117 + type="number"
  118 + ></el-input>
  119 + </template>
  120 + </el-table-column>
  121 + <el-table-column label="销售价(元)" re>
  122 + <template slot-scope="scope">
  123 + <el-input v-model="scope.row.price" type="number"></el-input>
  124 + </template>
  125 + </el-table-column>
  126 + <el-table-column label="成本价">
  127 + <template slot-scope="scope">
  128 + <el-input
  129 + v-model="scope.row.costPrice"
  130 + type="number"
  131 + ></el-input>
  132 + </template>
  133 + </el-table-column>
  134 + <el-table-column label="库存">
  135 + <template slot-scope="scope">
  136 + <el-input v-model="scope.row.stock" type="number"></el-input>
  137 + </template>
  138 + </el-table-column>
  139 + <el-table-column label="体积">
  140 + <template slot-scope="scope">
  141 + <el-input v-model="scope.row.volume" type="number"></el-input>
  142 + </template>
  143 + </el-table-column>
  144 + <el-table-column label="重量">
  145 + <template slot-scope="scope">
  146 + <el-input v-model="scope.row.weight" type="number"></el-input>
  147 + </template>
  148 + </el-table-column>
  149 + <el-table-column label="条码">
  150 + <template slot-scope="scope">
  151 + <el-input v-model="scope.row.barCode"></el-input>
  152 + </template>
  153 + </el-table-column>
  154 + </el-table>
  155 + </el-form-item>
  156 + </el-form>
  157 + </el-tab-pane>
  158 +
  159 + <!-- 商品详情 -->
  160 + <el-tab-pane label="商品描述" name="third">
  161 + <editor v-model="baseForm.description" :min-height="400"/>
  162 + </el-tab-pane>
  163 +
  164 + <!-- 销售设置 -->
  165 + <el-tab-pane label="销售设置" name="fourth">
  166 + <el-form ref="baseForm" :model="baseForm" :rules="rules" label-width="100px" style="width: 95%">
  167 + <el-form-item label="库存数量" prop="totalStock">
  168 + <el-input v-model="baseForm.totalStock" placeholder="请输入库存数量"/>
  169 + </el-form-item>
  170 + <el-form-item label="上下架状态" prop="status">
  171 + <el-radio-group v-model="baseForm.status">
  172 + <el-radio :label="0">上架</el-radio>
  173 + <el-radio :label="1">下架</el-radio>
  174 + </el-radio-group>
  175 + </el-form-item>
  176 + </el-form>
  177 + </el-tab-pane>
  178 + </el-tabs>
  179 +
  180 + <div class="buttons">
  181 + <el-button type="info" round @click="cancel">取消</el-button>
  182 + <el-button type="success" round @click="submit">确认</el-button>
  183 + </div>
  184 +
  185 + </div>
  186 +</template>
  187 +
  188 +<script>
  189 +import {getProductCategoryList} from "@/api/mall/product/category";
  190 +import {createSpu,} from "@/api/mall/product/spu";
  191 +import {getPropertyPage,} from "@/api/mall/product/property";
  192 +import Editor from "@/components/Editor";
  193 +import ImageUpload from "@/components/ImageUpload";
  194 +
  195 +export default {
  196 + components: {
  197 + Editor,
  198 + ImageUpload
  199 + },
  200 + data() {
  201 + return {
  202 + activeName: "base",
  203 + propName: {
  204 + checkStrictly: true,
  205 + label: "name",
  206 + value: "id",
  207 + },
  208 + // 基础设置
  209 + baseForm: {
  210 + name: null,
  211 + sellPoint: null,
  212 + categoryIds: null,
  213 + sort: null,
  214 + description: null,
  215 + bannerUrl: null,
  216 + picUrls: [],
  217 + totalStock: null,
  218 + status: 0
  219 + },
  220 + categoryList: [],
  221 + // 价格库存
  222 + ratesForm: {
  223 + spec: 0,
  224 + // 规格明细
  225 + rates: [{}]
  226 + },
  227 + dynamicSpec: [
  228 + // {
  229 + // specId: 86,
  230 + // specName: "颜色",
  231 + // specValue:[{
  232 + // name: "红色",
  233 + // id: 225,
  234 + // }]
  235 + // },
  236 + ],
  237 + propertyPageList: [],
  238 + specValue: null,
  239 +
  240 + // 表单校验
  241 + rules: {
  242 + description: [
  243 + {required: true, message: "描述不能为空", trigger: "blur"},
  244 + ],
  245 + categoryIds: [
  246 + {required: true, message: "分类id不能为空", trigger: "blur"},
  247 + ],
  248 + bannerUrl: [{required: true, message: "商品主图地址", trigger: "blur"}],
  249 + sort: [
  250 + {required: true, message: "排序字段不能为空", trigger: "blur"},
  251 + ],
  252 + },
  253 + };
  254 + },
  255 + created() {
  256 + this.getListCategory();
  257 + this.getPropertyPageList();
  258 + },
  259 + methods: {
  260 + changeRadio() {
  261 +
  262 + this.$refs.rates.doLayout()
  263 + if (this.ratesForm.spec == 0) {
  264 + this.ratesForm.rates = [{}]
  265 + } else {
  266 + this.ratesForm.rates = []
  267 + if (this.dynamicSpec.length > 0) {
  268 + this.buildRatesFormRates()
  269 + }
  270 + }
  271 + },
  272 + // 构建规格明细笛卡尔积
  273 + buildRatesFormRates() {
  274 + let rates = [];
  275 + this.dynamicSpec.map(v => v.specValue.map(m => m.name))
  276 + .reduce((last, current) => {
  277 + const array = [];
  278 + last.forEach(par1 => {
  279 + current.forEach(par2 => {
  280 + let v
  281 + if (par1 instanceof Array) {
  282 + v = par1.concat(par2)
  283 + } else {
  284 + v = [par1, par2];
  285 + }
  286 + array.push(v)
  287 + });
  288 + });
  289 + return array;
  290 + })
  291 + .forEach(v => {
  292 + rates.push({spec: v})
  293 + });
  294 + this.ratesForm.rates = rates
  295 + },
  296 + /** 查询分类 */
  297 + getListCategory() {
  298 + // 执行查询
  299 + getProductCategoryList().then((response) => {
  300 + this.categoryList = this.handleTree(response.data, "id", "parentId");
  301 + });
  302 + },
  303 + cancel() {
  304 + this.$emit("closeDialog");
  305 + },
  306 + submit() {
  307 + let rates = this.ratesForm.rates;
  308 + // 动态规格调整字段
  309 + if (this.ratesForm.spec == 1) {
  310 + rates.forEach(r => {
  311 + let properties = []
  312 + if(r.spec instanceof Array){
  313 + r.spec.forEach((v, i) => {
  314 + let specValue = this.dynamicSpec[i].specValue.find(o => o.name == v);
  315 + let propertie = {};
  316 + propertie.propertyId = this.dynamicSpec[i].specId;
  317 + propertie.valueId = specValue.id;
  318 + properties.push(propertie);
  319 + })
  320 + }else{
  321 + let specValue = this.dynamicSpec[0].specValue.find(o => o.name == r.spec);
  322 + let propertie = {};
  323 + propertie.propertyId = this.dynamicSpec[0].specId;
  324 + propertie.valueId = specValue.id;
  325 + properties.push(propertie);
  326 + }
  327 + r.properties = properties;
  328 + })
  329 + }
  330 + this.baseForm.skus = rates;
  331 + this.baseForm.specType = this.ratesForm.spec;
  332 + this.baseForm.categoryId = this.baseForm.categoryIds[this.baseForm.categoryIds.length - 1];
  333 + createSpu(this.baseForm).then((response) => {
  334 + console.log(response)
  335 + this.$modal.msgSuccess("新增成功");
  336 + this.$emit("closeDialog");
  337 + });
  338 +
  339 + },
  340 + /** 查询规格 */
  341 + getPropertyPageList() {
  342 + // 执行查询
  343 + getPropertyPage().then((response) => {
  344 + this.propertyPageList = response.data.list;
  345 + });
  346 + },
  347 + changeSpec(val) {
  348 + let obj = this.propertyPageList.find(o => o.id == val);
  349 + let dynamicSpec = this.dynamicSpec;
  350 + let spec = dynamicSpec.find(o => o.specId == val)
  351 + spec.specId = obj.id;
  352 + spec.specName = obj.name;
  353 + spec.specValue = obj.propertyValueList;
  354 + this.dynamicSpec = dynamicSpec;
  355 + this.buildRatesFormRates();
  356 + }
  357 + },
  358 +};
  359 +</script>
  360 +
  361 +<style lang="scss">
  362 +.spec-dialog {
  363 + width: 400px;
  364 + height: 300px;
  365 +}
  366 +
  367 +.dynamic-spec {
  368 + background-color: #f2f2f2;
  369 + width: 85%;
  370 + margin: auto;
  371 + margin-bottom: 10px;
  372 +
  373 + .spec-header {
  374 + padding: 30px;
  375 + padding-bottom: 20px;
  376 +
  377 + .spec-name {
  378 + display: inline;
  379 +
  380 + input {
  381 + width: 30%;
  382 + }
  383 + }
  384 + }
  385 +
  386 + .spec-values {
  387 + width: 84%;
  388 + padding: 25px;
  389 + margin: auto;
  390 + padding-top: 5px;
  391 +
  392 + .spec-value {
  393 + display: inline-block;
  394 + margin-right: 10px;
  395 + margin-bottom: 10px;
  396 + width: 13%;
  397 +
  398 + }
  399 + }
  400 +
  401 + .spec-delete {
  402 + float: right;
  403 + margin-top: 10px;
  404 + margin-right: 10px;
  405 + }
  406 +}
  407 +
  408 +.tabs {
  409 + height: 500px;
  410 + border-bottom: 2px solid #f2f2f2;
  411 +
  412 + .el-tab-pane {
  413 + height: 445px;
  414 + overflow-y: auto;
  415 + }
  416 +}
  417 +
  418 +// 库存价格图片样式修改
  419 +.rates {
  420 + .component-upload-image {
  421 + margin: auto;
  422 + }
  423 +
  424 + .el-upload--picture-card {
  425 + width: 100px;
  426 + height: 50px;
  427 + line-height: 60px;
  428 + margin: auto;
  429 + }
  430 +
  431 + .el-upload-list__item {
  432 + width: 100px !important;
  433 + height: 50px !important;
  434 + }
  435 +}
  436 +
  437 +.buttons {
  438 + margin-top: 20px;
  439 + height: 36px;
  440 +
  441 + button {
  442 + float: right;
  443 + margin-left: 15px;
  444 + }
  445 +}
  446 +</style>
... ...