1 <script lang="ts">
2 import {Component, Prop, Vue, Watch} from "vue-property-decorator";
3 import config from "@/config";
4 import {queryProductSpecsListApi, queryProductSpecsValueListApi} from "@/apis/productSpecs";
5 import {ISpecs, ISpecsValue} from "@/apis/productSpecs/types";
6 import {Message} from "element-ui";
7 import {IProduct} from "@/apis/product/types";
8
9 @Component({})
10 export default class ProductSpecs extends Vue {
11 config = config;
12 // 新增修改表单
13 @Prop(Object) modelForm!: IProduct;
14 // 新增修改表单rules
15 @Prop(Object) rules!: any;
16 // 新增修改表单
17 modelSpecsForm: any = {}
18 //商品规格下拉数据
19 productSpecsValueList: ISpecsValue[] = [];
20 //商品规格属性下拉数据
21 productSpecsList: ISpecs[] = [];
22
23 //列出的属性 二维数组
24 specsList: any[] = [];
25 //选中的规格属性
26 checkedSpecs: any[] = [];
27 //列表 规格列数组
28 tableColumnList:any[] = [];
29
30 //列表数据
31 tableData: any[] = []
32
33 @Watch('modelForm')
34 onChangeValue(newVal: any, oldVal: any) {
35 console.log(newVal, '监听数据')
36 if (newVal.productSkuVoList) {
37 let SkuVoList: any = [];
38 for (let skuItem of newVal.productSkuVoList) {
39 let obj = skuItem;
40 let sku = JSON.parse(skuItem.spData);
41 sku.forEach((e: any, i: number) => {
42 obj[`specs${i}`] = e.value
43 })
44 SkuVoList = [...SkuVoList, ...sku]
45 this.tableData.push(obj)
46 }
47 this.specsList = [];
48 this.productSpecsValueList.forEach(async (SpecsValue) => {
49 for (let Item of SkuVoList) {
50 if (SpecsValue.specsName == Item.key) {
51 let obj: any = SpecsValue;
52 let svIndex = this.specsList.findIndex(specs => specs.specsValueId == SpecsValue.id);
53 if (svIndex == -1) {
54 await this.getProductSpecsList(SpecsValue.id || '');
55 obj.specsName = Item.key;
56 obj.specsValueId = SpecsValue.id;
57 obj.list = this.productSpecsList;
58 this.specsList.push(obj);
59 }
60 obj.list.forEach((e: any, i: number) => {
61 if (e.name == Item.value)
62 this.checkedSpecs.push(e.id)
63 })
64 }
65 }
66 })
67 this.tableColumnList=this.specsList;
68 }
69 }
70
71 /**
72 * 商品规格
73 */
74 getProductSpecsValueList() {
75 queryProductSpecsValueListApi({}).then(e => {
76 this.productSpecsValueList = e;
77 return e;
78 })
79 }
80
81 /**
82 * 商品规格属性
83 */
84 async getProductSpecsList(id: string) {
85 await queryProductSpecsListApi({specsValueId: id}).then(e => {
86 this.productSpecsList = e;
87 })
88 }
89
90 /**
91 * 商品规格 选择
92 *
93 */
94 handleSpecsValue(value: any) {
95 this.modelSpecsForm.id = '';
96 this.productSpecsList = [];
97 this.getProductSpecsList(value);
98 }
99
100 /**
101 * 商品规格列出
102 *
103 */
104 handleSpecs() {
105 let svIndex = this.productSpecsValueList.findIndex(e => e.id == this.modelSpecsForm.specsValueId);
106 if (svIndex != -1) {
107 let obj = {
108 specsValueId: this.modelSpecsForm.specsValueId,
109 specsName: this.productSpecsValueList[svIndex].specsName,
110 list: [],
111 }
112
113 this.modelSpecsForm.id.forEach((id: any) => {
114 let sIndex = this.productSpecsList.findIndex(e => e.id == id);
115 if (sIndex != -1) {
116 let o = this.productSpecsList[sIndex];
117 o.specsName = obj.specsName
118 obj.list.push(o as never)
119 }
120 })
121 let index = this.specsList.findIndex((e: any) => e.specsValueId == this.modelSpecsForm.specsValueId);
122 if (index != -1) {
123 this.tableData = [];
124 this.modelForm.productSkuDtoList = [];
125 this.specsList.splice(index, 1, obj);
126 } else
127 this.specsList.push(obj);
128 }
129
130 }
131
132
133 /**
134 *选择规格属性
135 */
136 handleCheckedSpecs(value: any) {
137 this.tableData = [];
138 this.modelForm.productSkuDtoList = [];
139 }
140
141 /**
142 * 添加规格属性
143 */
144 handleAddCheckboxName(specsValueIndex: number) {
145 let specsValue = this.productSpecsValueList[specsValueIndex];
146 let index = this.specsList.findIndex((e: any) => e.specsValueId == specsValue.id);
147 this.specsList[index].list.push({
148 specsName: this.specsList[index].specsName,
149 specsValueId: this.specsList[index].specsValueId,
150 name: this.specsList[index].checkboxName,
151 id: ((index + this.specsList[index].list.length) * this.specsList[index].list.length)
152 })
153 this.specsList[index].checkboxName = '';
154
155 }
156
157 /**
158 * 多维数组组合
159 */
160 // @ts-ignore
161 doExchange(arr: any) {
162 let len = arr.length;
163 // 当数组大于等于2个的时候
164 if (len >= 2) {
165 // 第一个数组的长度
166 let len1 = arr[0].length;
167 // 第二个数组的长度
168 let len2 = arr[1].length;
169 // 2个数组产生的组合数
170 let lenBoth = len1 * len2;
171 // 申明一个新数组
172 let items = new Array(lenBoth);
173 // 申明新数组的索引
174 let index = 0;
175 for (let i = 0; i < len1; i++) {
176 for (let j = 0; j < len2; j++) {
177 if (arr[0][i] instanceof Array) {
178 items[index] = arr[0][i].concat(arr[1][j]);
179 } else {
180 items[index] = [arr[0][i]].concat(arr[1][j]);
181 }
182 index++;
183 }
184 }
185 let newArr = new Array(len - 1);
186 for (let i = 2; i < arr.length; i++) {
187 newArr[i - 1] = arr[i];
188 }
189 newArr[0] = items;
190 return this.doExchange(newArr);
191 } else {
192 return arr[0];
193 }
194 }
195 /**
196 * 生成sku
197 */
198 handleSKU() {
199 //列表
200 this.tableData = [];
201 //选择的sku 二维数组
202 let SKUList = new Array();
203 //过滤重复选择的数据
204 let s = new Set( this.checkedSpecs);
205 this.checkedSpecs= Array.from(s)
206
207 this.specsList.forEach((item, index) => {
208 item.isChecked=false;
209 let specs: any = []
210 item.list.forEach((sku: any) => {
211 this.checkedSpecs.forEach((checkedId: any) => {
212 let o: any = {id: '', specsValueId: item.specsValueId||'', skuName: item.specsName};
213 if (sku.id == checkedId) {
214 item.isChecked=true;
215 o.id = sku.id;
216 o[`specs${index}`] = sku.name;
217 o.name = sku.name;
218 specs.push(o);
219 }
220 })
221 })
222 if(specs.length>0)
223 SKUList.push(specs);
224 })
225
226 if (SKUList) {
227 this.tableColumnList=this.specsList.filter(e=>e.isChecked==true);
228 //多维数组组合
229 let newArr = this.doExchange(SKUList) as any;
230 //组装sku key value List
231 let spList = new Array();
232 //组合完成 列表数据
233 let productSkuList = [];
234 //组合需要数据
235 for (let newArrElement of newArr) {
236 //列表对象
237 let obj = {spData: null, skuPic: '', skuPrice: '', stock: '', productId: this.modelForm.id} as any;
238
239 if (!newArrElement.length) {
240 for (let skuListElement of this.specsList) {
241 for (let skuVoListElement of skuListElement.list) {
242 if (skuVoListElement.specsValueId == newArrElement.specsValueId && skuVoListElement.name == newArrElement.name) {
243 //规格列 key,value
244 obj.specs0 = newArrElement.name;
245 //spData key value
246 spList.push({key: skuListElement.specsName, value: newArrElement.name});
247 continue;
248 }
249 }
250 }
251 } else {
252 for (let i = 0; i < newArrElement.length; i++) {
253 for (let skuListElement of this.specsList) {
254 for (let skuVoListElement of skuListElement.list) {
255 if (skuVoListElement.specsValueId == newArrElement[i].specsValueId && skuVoListElement.name == newArrElement[i].name) {
256 //规格列 key,value
257 obj[`specs${i}`] = newArrElement[i].name
258 //spData key value
259 spList.push({key: skuListElement.specsName, value: newArrElement[i].name});
260 continue;
261 }
262 }
263 }
264 }
265 }
266 obj.spData = JSON.stringify(spList);
267 productSkuList.push(obj)
268 spList = [];
269 }
270 this.tableData = productSkuList;
271 this.modelForm.productSkuDtoList = this.tableData;
272 console.log(this.tableData, 'productSkuDtoList')
273 }
274
275 }
276
277 /**
278 * 上传前检验
279 * @param file
280 */
281 beforeUpload(file: File) {
282 if (file.type != "image/png" && file.type != "image/jpg" && file.type != "image/jpeg") {
283 Message.error("请选择正确格式")
284 return false
285 }
286 }
287
288 /**
289 * 下一步,上一步
290 * @param number
291 *
292 */
293 handleNext(tab: string) {
294 this.$emit('Next', this.modelForm,tab)
295 }
296
297 created() {
298 this.getProductSpecsValueList();
299 }
300 }
301 </script>
302
303 <template>
304 <div class="divBox">
305 <el-form ref="form" :model="modelForm" label-width="180px" :rules="rules">
306 <el-row :gutter="24">
307 <el-form-item label="商品规格:" prop="productSkuDtoList">
308 <el-col :span="8">
309 <el-select v-model="modelSpecsForm.specsValueId" clearable filterable placeholder="请选择规格"
310 @change="handleSpecsValue">
311 <el-option
312 v-for="(item,index) in productSpecsValueList"
313 :key="index"
314 :label="item.specsName"
315 :value="item.id">
316 </el-option>
317 </el-select>
318 </el-col>
319 <el-col :span="15">
320 <el-select v-model="modelSpecsForm.id" clearable filterable multiple
321 collapse-tags placeholder="请选择规格属性">
322 <el-option
323 v-for="(item,index) in productSpecsList"
324 :key="index"
325 :label="item.name"
326 :value="item.id"
327 :disabled="item.disabled">
328 </el-option>
329 </el-select>
330 <el-button style="margin-left: 20px" :disabled="!modelSpecsForm.id" size="small" type="primary" plain
331 @click="handleSpecs">
332 列出规格属性
333 </el-button>
334 </el-col>
335 </el-form-item>
336 </el-row>
337 <el-row :gutter="24">
338 <el-col :span="21" :offset="3">
339 <div class="specsLine" v-for="(k,index) in specsList" :key="index">
340 <div class="title">
341 {{ k.specsName }}
342 </div>
343 <div class="dec">
344 <el-row :gutter="24">
345 <el-col :span="12">
346 <el-checkbox-group v-model="checkedSpecs" @change="handleCheckedSpecs">
347 <el-checkbox v-for="(c,i) in k.list" :label="c.id" :key="i">{{ c.name }}</el-checkbox>
348 </el-checkbox-group>
349 </el-col>
350 <el-col :span="7">
351 <el-input v-model="k.checkboxName" maxlength="8"
352 :placeholder="`请输入${ k.specsName}属性名称`"></el-input>
353 </el-col>
354 <el-col :span="3">
355 <el-button :disabled="!k.checkboxName" size="small" type="primary" plain
356 @click="handleAddCheckboxName(index)">
357 添加规格属性
358 </el-button>
359 </el-col>
360 </el-row>
361 </div>
362 </div>
363 </el-col>
364 </el-row>
365 <el-row :gutter="24">
366 <el-col :span="21" :offset="3">
367 <el-button :disabled="checkedSpecs.length==0" size="small" type="primary" plain @click="handleSKU">
368 生成SKU
369 </el-button>
370 </el-col>
371 </el-row>
372 <el-row v-if="tableData.length>0">
373 <el-form-item label="商品属性:">
374 </el-form-item>
375 <el-table :data="tableData">
376 <template v-for="(item,index) in tableColumnList">
377 <el-table-column :label="item.specsName" width="200" align="center">
378 <template #default="scope">
379 <span> {{ scope.row[`specs${index}`] }}</span>
380 </template>
381 </el-table-column>
382 </template>
383 <el-table-column label="图片" align="center" width="200" >
384 <template #default="scope">
385 <span>
386 <picture-upload ref="fileUpload" :limit="1" v-model="scope.row.skuPic"
387 :before-upload="beforeUpload">
388
389 </picture-upload>
390 </span>
391 </template>
392 </el-table-column>
393 <el-table-column label="售价" align="center" width="250" prop="skuPrice">
394 <template #default="scope">
395 <span>
396 <el-input maxlength="12"
397 oninput="value=value.replace(/^\D*([0-9]\d*\.?\d{0,2})?.*$/,'$1')" style="width: 80%"
398 v-model="scope.row.skuPrice" placeholder="请输入售价"></el-input>
399 </span>
400 </template>
401 </el-table-column>
402 <el-table-column label="库存" align="center" width="250" prop="stock">
403 <template #default="scope">
404 <span>
405 <el-input oninput="value=value.replace(/[^\d]/g,'')" style="width:80%" v-model="scope.row.stock"
406 placeholder="请输入库存"></el-input>
407 </span>
408 </template>
409 </el-table-column>
410 <el-table-column label="产品编号" align="center">
411 <template #default="scope">
412 <span>
413 {{ (scope.$index + 1) > 10 ? (scope.$index + 1) : '0' + (scope.$index + 1) }}
414 </span>
415 </template>
416 </el-table-column>
417 </el-table>
418 </el-row>
419
420 <el-form-item>
421 <el-button size="small" type="primary" plain @click="handleNext('first')">上一步</el-button>
422 <el-button size="small" type="primary" plain @click="handleNext('third')">下一步</el-button>
423 </el-form-item>
424 </el-form>
425 </div>
426 </template>
427
428 <style lang="scss" scoped>
429 .specsLine {
430 padding: 10px;
431
432 .dec {
433 padding-top: 3px;
434 font-size: 22px;
435 }
436 }
437 </style>
![]()
- skuPic: ""
- skuPrice: ""
- spData: "[{\"key\":\"款式\",\"value\":\"男款\"},{\"key\":\"颜色\",\"value\":\"红色\"}]"
- specs0: "男款"
- specs1: "红色"
- stock: ""