ftdsy-attr 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +3 -0
- package/.idea/52Attr.iml +12 -0
- package/.idea/dictionaries +6 -0
- package/.idea/modules.xml +8 -0
- package/dist/ftdsy-attr.js +1740 -0
- package/dist/ftdsy-attr.js.map +1 -0
- package/dist/index.html +12 -0
- package/package.json +27 -0
- package/rollup.config.js +52 -0
- package/src/config/platform.js +101 -0
- package/src/main.js +590 -0
- package/src/platform/1688.js +0 -0
- package/src/platform/dy.js +156 -0
- package/src/platform/jd.js +0 -0
- package/src/platform/ks.js +0 -0
- package/src/platform/pdd.js +152 -0
- package/src/platform/sph.js +0 -0
- package/src/platform/tb.js +321 -0
- package/src/platform/tm.js +0 -0
- package/src/platform/xhs.js +0 -0
- package/src/platform/xp.js +0 -0
- package/src/tools/property.js +351 -0
- package/src/utils/utils.js +111 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
|
|
2
|
+
import utils from "../utils/utils.js";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
|
|
6
|
+
// 匹配文本输入
|
|
7
|
+
matchInputProperty(propertyItem, goodsProperties, goods) {
|
|
8
|
+
|
|
9
|
+
// 进行包含匹配
|
|
10
|
+
let result = goodsProperties.findIndex(item => item.attr_name.includes(propertyItem.property_name))
|
|
11
|
+
if (result != -1) {
|
|
12
|
+
// 能进行模糊匹配到, 直接文本直接赋值
|
|
13
|
+
let goodsProperty = goodsProperties[result]
|
|
14
|
+
goodsProperties.splice(result, 1) // 从匹配数据中移除
|
|
15
|
+
|
|
16
|
+
if (typeof goodsProperty.value === 'string') {
|
|
17
|
+
// 值为字符串
|
|
18
|
+
return goodsProperty.value
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (typeof goodsProperty.value === 'object') {
|
|
22
|
+
// 对象/数组
|
|
23
|
+
if (goodsProperty.value instanceof Array) {
|
|
24
|
+
// 数组
|
|
25
|
+
let property_values = []
|
|
26
|
+
let reg = /(.*?)\[(\d+)%\]/
|
|
27
|
+
goodsProperty.value.forEach(valueItem => {
|
|
28
|
+
|
|
29
|
+
if (typeof valueItem === 'string' && reg.test(valueItem)) {
|
|
30
|
+
// 为字符串,并且为 '其他材质[100%]'格式数据
|
|
31
|
+
let values = reg.exec(valueItem)
|
|
32
|
+
|
|
33
|
+
if (propertyItem.property_name.includes('含量')) {
|
|
34
|
+
// 含量,只取含量,不取材质
|
|
35
|
+
property_values.push(values[2])
|
|
36
|
+
} else if (propertyItem.property_name.includes('材质成分')) {
|
|
37
|
+
// 材质成分,直接赋值
|
|
38
|
+
property_values.push(values[0])
|
|
39
|
+
} else if (propertyItem.property_name.includes('材质')) {
|
|
40
|
+
// 材质,只取材质,不取含量
|
|
41
|
+
property_values.push(values[1])
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
return property_values.length ? property_values[0] : ''
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 没有进行模糊匹配到,进行特殊处理
|
|
51
|
+
|
|
52
|
+
if (propertyItem.property_name.includes('CCC') || propertyItem.property_name.includes('3C')) {
|
|
53
|
+
// 玩具3C认证
|
|
54
|
+
result = goodsProperties.findIndex(item => item.attr_name.includes('CCC') || item.attr_name.includes('3C'))
|
|
55
|
+
if (result != -1) {
|
|
56
|
+
let goodsProperty = goodsProperties[result]
|
|
57
|
+
goodsProperties.splice(result, 1) // 从匹配数据中移除
|
|
58
|
+
return goodsProperty.value
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (propertyItem.property_name.includes('型号') && goods.cate_path.includes('3C数码配件')) {
|
|
63
|
+
|
|
64
|
+
return goods.goods_sn
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (propertyItem.property_name.includes('生产厂家') && goods.cate_path.includes('3C数码配件')) {
|
|
68
|
+
return '国内'
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return ''
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 匹配单选
|
|
76
|
+
* @param {Boolean} isTemplate 是否模板匹配,true时以模板属性为主
|
|
77
|
+
* */
|
|
78
|
+
matchSingleSelectProperty(isTemplate, propertyItem, goodsProperties) {
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
// 子属性 使用’condition_values‘,正常属性 使用’property_values‘
|
|
82
|
+
let property_values = propertyItem.show_condition.length ? propertyItem.condition_values : propertyItem.property_values
|
|
83
|
+
|
|
84
|
+
if (property_values.length == 1) {
|
|
85
|
+
// 只有一个选项, 直接选
|
|
86
|
+
return property_values[0]
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// 模糊匹配
|
|
90
|
+
let index = goodsProperties.findIndex(item => item.attr_name.includes(propertyItem.property_name))
|
|
91
|
+
if (index != -1) {
|
|
92
|
+
let attr = goodsProperties[index]
|
|
93
|
+
let valueItem = this.matchSingleSelectPropertyValue(property_values, attr)
|
|
94
|
+
if (valueItem) {
|
|
95
|
+
goodsProperties.splice(i, 1)
|
|
96
|
+
return valueItem
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 使用相似度进行匹配
|
|
101
|
+
for (var i = 0; i < goodsProperties.length; i++) {
|
|
102
|
+
|
|
103
|
+
let attr = goodsProperties[i]
|
|
104
|
+
let result = utils.getStringSimilarity(propertyItem.property_name, attr.attr_name)
|
|
105
|
+
|
|
106
|
+
if (result >= 50) {
|
|
107
|
+
// 相似程度大于等50,进行匹配属性值
|
|
108
|
+
|
|
109
|
+
let valueItem = this.matchSingleSelectPropertyValue(property_values, attr)
|
|
110
|
+
if (valueItem) {
|
|
111
|
+
goodsProperties.splice(i, 1)
|
|
112
|
+
return valueItem
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 指定修改
|
|
118
|
+
if (['产地'].includes(propertyItem.property_name)) {
|
|
119
|
+
//
|
|
120
|
+
let valueItem = propertyItem.property_values.find(item => item.name.includes('中国'))
|
|
121
|
+
if (valueItem) {
|
|
122
|
+
return valueItem
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
return {}
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* 匹配单选值
|
|
132
|
+
* @param {Array} propertyValues 属性值可选列表
|
|
133
|
+
* @param {Object} goodsAttr 参考属性值
|
|
134
|
+
* */
|
|
135
|
+
matchSingleSelectPropertyValue(propertyValues, goodsAttr) {
|
|
136
|
+
|
|
137
|
+
if (!goodsAttr || !Object.keys(goodsAttr).length) {
|
|
138
|
+
// 参考值为空
|
|
139
|
+
return {}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
let valueItem = propertyValues.find(item => item.name === goodsAttr.value)
|
|
143
|
+
if (valueItem) {
|
|
144
|
+
// 属性值全匹配正确
|
|
145
|
+
return valueItem
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 属性值全字符匹配失败,进行字符包含匹配
|
|
149
|
+
valueItem = propertyValues.find(item => item.name.includes(goodsAttr.value) || goodsAttr.value.includes(item.name))
|
|
150
|
+
if (valueItem) {
|
|
151
|
+
// 字符包含匹配正确
|
|
152
|
+
return valueItem
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// 字符包含匹配失败,进行字符相似度匹配
|
|
156
|
+
let similarity = 0
|
|
157
|
+
propertyValues.forEach(item => {
|
|
158
|
+
|
|
159
|
+
let result = utils.getStringSimilarity(item.name, goodsAttr.value)
|
|
160
|
+
if (result >= 50 && result > similarity) {
|
|
161
|
+
|
|
162
|
+
// 相似度大于50, 并且比之前相似度大(取最大相似值)
|
|
163
|
+
similarity = result
|
|
164
|
+
valueItem = item
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
if (valueItem) {
|
|
168
|
+
// 相似度匹配大于50, 获取最相似的值)
|
|
169
|
+
return valueItem
|
|
170
|
+
}
|
|
171
|
+
return {}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
/* 匹配多选 */
|
|
176
|
+
matchMultipleSelectProperty(propertyItem, goodsProperties) {
|
|
177
|
+
|
|
178
|
+
// 子属性 使用’condition_values‘,正常属性 使用’property_values‘
|
|
179
|
+
let property_values = propertyItem.show_condition.length ? propertyItem.condition_values : propertyItem.property_values
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
if (['面料分类','面料材质'].includes(propertyItem.property_name)) {
|
|
184
|
+
// 多选 面料材质
|
|
185
|
+
let index = goodsProperties.findIndex(item => ['面料分类','面料材质'].includes(item.attr_name))
|
|
186
|
+
|
|
187
|
+
if (index != -1) {
|
|
188
|
+
let attr = goodsProperties[index]
|
|
189
|
+
goodsProperties.splice(index, 1)
|
|
190
|
+
|
|
191
|
+
let value = []
|
|
192
|
+
if (attr.value instanceof Array) {
|
|
193
|
+
// 数组(原商品属性多选),字符串数组
|
|
194
|
+
attr.value.forEach(attrValue => {
|
|
195
|
+
|
|
196
|
+
if (propertyItem.select_max_num > value.length) {
|
|
197
|
+
// 未到限制多选数量,进行匹配
|
|
198
|
+
let valueItem = property_values.find(valueItem => valueItem.name === attrValue)
|
|
199
|
+
if (valueItem) {
|
|
200
|
+
// 有匹配到属性值, 并且未到最大选中值
|
|
201
|
+
valueItem.isSelect = true
|
|
202
|
+
value.push(valueItem)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
} else {
|
|
207
|
+
// 对象(原商品属性单选)
|
|
208
|
+
if (propertyItem.select_max_num > value.length) {
|
|
209
|
+
let valueItem = property_values.find(value => value.name === attr.value)
|
|
210
|
+
if (valueItem) {
|
|
211
|
+
// 有匹配到属性值, 并且未到最大选中值
|
|
212
|
+
valueItem.isSelect = true
|
|
213
|
+
value.push(valueItem)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return value
|
|
219
|
+
}
|
|
220
|
+
return []
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
return []
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
/* 匹配组合多选(’材质成分‘) */
|
|
229
|
+
matchMaterialQualityProperty(propertyItem, goodsProperties) {
|
|
230
|
+
|
|
231
|
+
// 子属性 使用’condition_values‘,正常属性 使用’property_values‘
|
|
232
|
+
let property_values = propertyItem.show_condition.length ? propertyItem.condition_values : propertyItem.property_values
|
|
233
|
+
|
|
234
|
+
let valueList = []
|
|
235
|
+
|
|
236
|
+
// console.log("匹配材质成分", propertyItem.property_name)
|
|
237
|
+
// console.log(JSON.stringify(goodsProperties))
|
|
238
|
+
// 模糊匹配
|
|
239
|
+
let index = goodsProperties.findIndex(item => item.attr_name.includes(propertyItem.property_name))
|
|
240
|
+
if (index != -1) {
|
|
241
|
+
let attr = goodsProperties[index]
|
|
242
|
+
|
|
243
|
+
let attrValue = []
|
|
244
|
+
console.log(attr.value, typeof attr.value)
|
|
245
|
+
if (typeof attr.value === 'string') {
|
|
246
|
+
// 字符串
|
|
247
|
+
attrValue = attr.value.split(',')
|
|
248
|
+
} else {
|
|
249
|
+
// 数组
|
|
250
|
+
attrValue = [...attr.value]
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (attrValue) {
|
|
254
|
+
attrValue.forEach(item => {
|
|
255
|
+
if (item instanceof String) {
|
|
256
|
+
let t = item.lastIndexOf('[')
|
|
257
|
+
if (t != -1) {
|
|
258
|
+
let attValue = item.slice(0, t)
|
|
259
|
+
let attContent = item.slice(t + 1, item.length - 1).replace('%', '')
|
|
260
|
+
|
|
261
|
+
let valueItem = property_values.find(item => item.name === attValue)
|
|
262
|
+
if (valueItem) {
|
|
263
|
+
// 属性值全匹配正确
|
|
264
|
+
valueItem.content = Number(attContent) ? Number(attContent) : 0
|
|
265
|
+
valueItem.isSelect = true
|
|
266
|
+
valueList.push(valueItem)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
})
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
return valueList
|
|
277
|
+
},
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
/* 计算属性各项属性数量,与选择数量 */
|
|
282
|
+
calculateCategroyProperty(propertiesDatas) {
|
|
283
|
+
|
|
284
|
+
let requiredTotal = 0
|
|
285
|
+
let selectCount = 0
|
|
286
|
+
propertiesDatas.required_list.forEach(item => {
|
|
287
|
+
|
|
288
|
+
if (item.show) {
|
|
289
|
+
requiredTotal++
|
|
290
|
+
|
|
291
|
+
if (item.property_type == 1 && item.property_value) {
|
|
292
|
+
// 文本
|
|
293
|
+
selectCount++
|
|
294
|
+
} else if (item.property_type == 2 && item.property_value && Object.keys(item.property_value).length) {
|
|
295
|
+
// 单选
|
|
296
|
+
selectCount++
|
|
297
|
+
} else if (item.property_type == 3 && item.property_value.length) {
|
|
298
|
+
// 多选
|
|
299
|
+
selectCount++
|
|
300
|
+
} else if (item.property_type == 4 && item.property_value && item.property_unit) {
|
|
301
|
+
// 规格输入
|
|
302
|
+
selectCount++
|
|
303
|
+
} else if (item.property_type == 5 && item.property_value) {
|
|
304
|
+
// 日期选择
|
|
305
|
+
selectCount++
|
|
306
|
+
} else if (item.property_type == 6 && item.property_value.length) {
|
|
307
|
+
// 组合多选
|
|
308
|
+
selectCount++
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
propertiesDatas.require_total = requiredTotal
|
|
314
|
+
propertiesDatas.require_count = selectCount
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
/* 获取子属性 */
|
|
319
|
+
getChildrenProperty(list, parentItem, children_list) {
|
|
320
|
+
|
|
321
|
+
let index = children_list.length - 1
|
|
322
|
+
while (index >= 0){
|
|
323
|
+
let childrenItem = children_list[index]
|
|
324
|
+
|
|
325
|
+
let result = childrenItem.show_condition.findIndex(conditionItem => conditionItem.parent_property_id == parentItem.property_id)
|
|
326
|
+
if (result != -1) {
|
|
327
|
+
// 当前子属性,为当前属性的子属性
|
|
328
|
+
|
|
329
|
+
if (childrenItem.show_condition.length == 1) {
|
|
330
|
+
// 子属性只有一个显示条件,直接添加
|
|
331
|
+
children_list.splice(index, 1) // 移除属性列表
|
|
332
|
+
|
|
333
|
+
childrenItem.property_required = parentItem.property_required // 子属性设置为必须项
|
|
334
|
+
list.push(childrenItem)
|
|
335
|
+
if (childrenItem.has_children) {
|
|
336
|
+
// 需要重新调用赋值,打破当前循序重新开始遍历子属性
|
|
337
|
+
this.getChildrenProperty(list, childrenItem, children_list)
|
|
338
|
+
break
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
} else {
|
|
342
|
+
// 子属性有多个显示条件
|
|
343
|
+
childrenItem.property_required = parentItem.property_required // 先设置子属性为必填项,后续非必填筛选完成后,分别添加到列表最后面
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
index--
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 获取2个字符串的相似度
|
|
5
|
+
* @param {string} str1 字符串1
|
|
6
|
+
* @param {string} str2 字符串2
|
|
7
|
+
* @returns {number} 相似度
|
|
8
|
+
*/
|
|
9
|
+
getStringSimilarity(str1, str2) {
|
|
10
|
+
let sameNum = 0
|
|
11
|
+
//寻找相同字符
|
|
12
|
+
for (let i = 0; i < str1.length; i++) {
|
|
13
|
+
for(let j =0;j<str2.length;j++){
|
|
14
|
+
if(str1[i]===str2[j]){
|
|
15
|
+
sameNum ++
|
|
16
|
+
break
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//判断2个字符串哪个长度比较长
|
|
21
|
+
let length = str1.length > str2.length ? str1.length : str2.length
|
|
22
|
+
return (sameNum/length) * 100 || 0
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/* 调用计算公式 */
|
|
27
|
+
evil(str) {
|
|
28
|
+
var fn = Function
|
|
29
|
+
return new fn('return ' + str)()
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
/* 检测值,true: 正常,false: 未选 */
|
|
34
|
+
checkValue(value) {
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
|
|
38
|
+
if (!value) {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (value === '' || value === null || value === undefined) {
|
|
43
|
+
return false
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (value instanceof Array) {
|
|
47
|
+
return value.length > 0
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (value instanceof Object) {
|
|
51
|
+
return Object.keys(value).length > 0
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 其他情况
|
|
55
|
+
return true
|
|
56
|
+
|
|
57
|
+
} catch (error) {
|
|
58
|
+
//TODO handle the exception
|
|
59
|
+
console.log(error)
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 判断字符串中是否包含某些字符
|
|
69
|
+
*
|
|
70
|
+
* @param {String} text 检测字符串
|
|
71
|
+
* @param {Array} arr 检测内容字符串数组
|
|
72
|
+
* @param {string} type 检测方式,includeOne:包含一个,includeAll:包含全部,默认为 includeOne
|
|
73
|
+
* */
|
|
74
|
+
isTextInclude(text, arr, type = 'includeOne') {
|
|
75
|
+
if (Object.prototype.toString.call(text) !== '[object String]') throw new Error('text 参数错误有误,只能是String类型')
|
|
76
|
+
if (Object.prototype.toString.call(arr) !== '[object Array]') throw new Error('arr 参数错误有误,只能是Array类型')
|
|
77
|
+
if (type === 'includeOne') {
|
|
78
|
+
return arr.some(i => text.indexOf(i) > -1)
|
|
79
|
+
} else if (type === 'includeAll') {
|
|
80
|
+
return arr.filter(i => text.indexOf(i) > -1).length === arr.length
|
|
81
|
+
} else {
|
|
82
|
+
throw new Error('type 参数错误有误,只能是includeOne或includeAll')
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 获取文本长度
|
|
90
|
+
*
|
|
91
|
+
* @param {String} text 待检查的字符串
|
|
92
|
+
* @param {Number} max 当text不是字符时返回的数字
|
|
93
|
+
* */
|
|
94
|
+
getTextLength(text, max = 0) {
|
|
95
|
+
if (Object.prototype.toString.call(text) === '[object String]') {
|
|
96
|
+
let length = 0
|
|
97
|
+
for (let i = 0; i < text.length; i++) {
|
|
98
|
+
if (text.charAt(i).match(/[^\x00-\xff]/gi) != null) {
|
|
99
|
+
length += 2
|
|
100
|
+
} else {
|
|
101
|
+
length += 1
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return length
|
|
105
|
+
} else if (max === undefined) {
|
|
106
|
+
throw new Error('getTextLength 参数必须为字符串')
|
|
107
|
+
}
|
|
108
|
+
return max
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
}
|