一个商品SKU是怎么生成的

article/2025/10/3 9:45:33

首先说一说什么是SKU。。。。。。。自己百度去。。。

类似京东上面,未来人类S5这个台笔记本(没错,我刚入手了)

都是S5这个型号,但是因为CPU,显卡,内存,硬盘等不同,价格也不一样。CPU,显卡,内存,硬盘等属性组合成的一个唯一的商品,就可以用一个SKU来表示,像图上就有10个SKU。一系列的SKU可以归到一个SPU下进行管理。

那么一个SKU是怎么生成的呢?下面结合自己的一些经验,说说一些电商平台的大致产品结构以及SKU的生成方式。

1.阿里速卖通平台,阿里国际站

这两个平台同一个爸爸,基本差不多。要创建一个商品需要先选一个类目,类目下面挂了一堆的属性,属性上又挂了一堆的属性值。属性分为销售属性和非销售属性(销售属性就是类似颜色,尺寸这些单个SKU独有的,非销售属性就是多个SKU共有的,比如同一个品牌型号“未来人类S5”)。非销售属性有必填和非必填,可以是单选,多选,文本等。销售属性就是构成SKU的关键。比如说有销售属性颜色和尺寸,颜色属性下有很多属性值(红,黄,蓝等等),尺寸(1,2,3,4等等)也是。当颜色选了红,黄,尺寸选了1,2,那么就应该生成2x2=4个SKU,每个SKU有各自的价格,库存等。保存SKU的时候会与对应的销售属性相关联。
大致的数据模型如下

当然,实际比这更加复杂(比如产品的图片,单个SKU的图片,多个SKU共同的图片,非销售属性可以自定义添加分类不具有的。。。)

2.eBay
跟上面两个平台类似,创建一个产品也要先选一个分类,分类下面也是有很多属性,属性有很多属性值。。。,不同的地方是eBay没有区分销售属性和非销售属性(或者说全部是非销售属性),也允许添加自定义属性和属性值。eBay上SKU是手动添加的,SKU上的属性(SKU上的属性暂且都叫做销售属性)也是自定义的。比如说添加了一个SKU A,价格和数量这两个是必须的,还可以手动加个颜色属性,然后填上属性值红色。当然,若果增加一个SKU B,那么这个SKU也会有颜色这个属性,属性值可以自定义。最后校验这些SKU的属性值组合起来是否唯一。

这样的优势就是可以随意控制SKU的数量,如果按照上面两个平台的规则,这里应该有4x4x1=16个SKU。这样自由度更高会不会使结构更加复杂呢?当然是NO,用上面的数据模型就可以搞定

3.Lazada,Linio平台
国际惯例,先选一个类目,类目下面一堆属性,有必填和非必填,属性下一堆属性值。最大的区别就是,一个产品只有一个SKU,属性不支持自定义。比如说要添加一个商品,有两种颜色,那么只能创建两个产品,这两个产品可能只有图片不一样(颜色不一样,可能没有颜色这个属性来选)

4.Wish平台
比较奇特,没有分类,产品有固定的属性,比如标题,描述,运费等。一个产品下可以有多个SKU,SKU的生成取决于固定的两大类属性,两个大类为:颜色和尺寸。比如颜色这个属性就是归类于颜色这个类,其他的属性(品牌,型号,容量等等归为尺寸这个大类)。尺寸类的属性值支持自定义,但只能选一个尺寸类属性(比如选了品牌就不能选容量,选了品牌后可以添加任意值)。两类属性不是必须同时存在,比如颜色选了红,可以不选尺寸类的属性,反之也一样。

忘记说了,一个SKU是靠一串唯一编码来标识的,比如1234A,1234B。一般来说一个平台下不会存在两个相同的SKU,或这一个店铺下不会存在两个相同的SKU。

大致的逻辑和数据模型就这些,接下来说说开发实现方面。

数据库大致就依靠上面的数据模型进行设计,编辑的时候,后端按照这些关联关系取出数据给到前端(我这边前后端未分离,页面还是后端渲染,但我还是把数据格式化为JSON再渲染到前端),保存的时候再进行相关的逻辑校验。因为后端的一些逻辑操作涉及后公司内部的业务,这里就不细说了。说说前端的具体细节,以速卖通的为例,用的是vue,前端拿到的数据如下

属性数据,(变量properties)

sku数据(变量skus)

实现后的粗糙界面

data: {properties: properties,skus: skus}

遍历properties,得到材质,颜色,发货地,套餐这些属性对象,接着遍历这些对象里的values属性,得到属性值对象,根据属性对象的selectedValues判断属性值是否选上(因为我是后端渲染的js变量,所以初始化的时候selectedValues里的数据直接引用的属性值对象,如果是非后端渲染的话,要根据skus里的属性和属性值去初始化selectedValues的数据,并且存的是属性值对象的引用)

<tr v-for="(index,item) in properties"><td><strong>{{item.Name}}:</strong></td><td><label v-for="value in item.values"><input type="checkbox" :value="value" v-model="item.selectedValues"/>{{value.Name}}</label><table class="list_table" v-if="item.Name!='发货地'&&item.selectedValues.length>0"><tbody><tr><th>{{item.Name}}</th><th>自定义名称</th><th v-if="item.Name=='颜色'">图片(无图片可以不填)</th></tr><tr v-for="selectedValue in item.selectedValues"><td>{{selectedValue.Name}}</td><td><input type="text" v-model="selectedValue.DefinitionName" maxlength="20"/></td><td v-if="item.Name=='颜色'"><div style="float: left"><input type="file"  style="width: 63px;"/></div><div style="float: right"><a href="" rel="link" target="_blank"><img :src="selectedValue.ImageUrl" width="30" height="35"/></a></div></td></tr></tbody></table></td></tr>

因为selectedValues通过v-model绑定,当选中或取消一个属性值的时候后,selectedValues也会随着改变,selectedValues里的数据是直接引用属性值而不是拷贝一份数据,所以修改selectedValues中的数据也会直接反映到属性值上,实现了属性值的自定义。

那么怎么根据选中的属性值生成SKU呢?
SKU表格处的表头是要根据选中的属性动态更新的,可以这样做

<tr><th v-for="item in properties" v-if="item.selectedValues.length>0">{{item.Name}}</th><th><span class="c_red">*</span>零售价</th><th><span class="c_red">*</span>库存</th><th>商品编码</th></tr>

如果属性里的属性值都没有被选中(selectedValues.length==0),就不在表头显示这个属性。

SKU的初始显示

<tr v-for="sku in skus"><td v-for="item in properties" v-if="item.selectedValues.length>0">{{getValueName(sku,item)}}</td><td>US $<input type="text" v-model="sku.SkuPrice" class="w50" maxlength="9"/><span name="productUnitTips"></span></td><td><input type="text" v-model="sku.StockQuantity" class="w50" maxlength="9"/></td><td><input type="text" v-model="sku.SkuCode" class="w180" maxlength="20"/></td>
</tr>

也是利用selectedValues.length让SKU的属性值列数与表头列数保持一致。因为SKU对象里的保存的是属性值Id和属性Id,需要一个方法去获取属性值的值

getValueName: function (sku, property) {var valueName = "";$.each(sku.values,function () {var _this = this;if (this.propertyId == property.Id) {$.each(property.selectedValues, function () {if (_this.valueId == this.Id) {valueName = this.Name;return false;}});}});return valueName;}

你没有看错,这是JQ。。。

接下来就是SKU表格的更新了,我的做法是变更整块区域,就是给skus重新赋值。赋的新值从哪来呢?

将选中的属性值放到一个数组中

               var ori = [];$.each(vm.properties,function (index, item) {var selectValues = this.selectedValues;if (selectValues.length > 0) {ori.push(selectValues);}});

得到这种结构的数组

[[{'PropertyId': 10,'Id': 477,'Name': '铝','DefinitionName': '','ImageUrl': ''},{'PropertyId': 10,'Id': 529,'Name': '帆布','DefinitionName': '','ImageUrl': ''}],[{'PropertyId': 200000828,'Id': 201655809,'Name': '壳+贴膜','DefinitionName': '','ImageUrl': ''},{'PropertyId': 200000828,'Id': 201655810,'Name': '壳+挂绳','DefinitionName': '','ImageUrl': ''}]
]

求笛卡尔积后(后面有求笛卡尔积参考链接)

var ret = descartes(ori);
[[{'PropertyId': 10,'Id': 477,'Name': '铝','DefinitionName': '','ImageUrl': ''},{'PropertyId': 200000828,'Id': 201655809,'Name': '壳+贴膜','DefinitionName': '','ImageUrl': ''}],[{'PropertyId': 10,'Id': 477,'Name': '铝','DefinitionName': '','ImageUrl': ''},{'PropertyId': 200000828,'Id': 201655810,'Name': '壳+挂绳','DefinitionName': '','ImageUrl': ''}],[{'PropertyId': 10,'Id': 529,'Name': '帆布','DefinitionName': '','ImageUrl': ''},{'PropertyId': 200000828,'Id': 201655809,'Name': '壳+贴膜','DefinitionName': '','ImageUrl': ''}],[{'PropertyId': 10,'Id': 529,'Name': '帆布','DefinitionName': '','ImageUrl': ''},{'PropertyId': 200000828,'Id': 201655810,'Name': '壳+挂绳','DefinitionName': '','ImageUrl': ''}]
]

大前端也用上了算法有木有,这里需要弄明白拿到的是什么数据,需要的是什么数据,然后就去想实现就OK了。
想要的数据已经拿到,重新构建skus

         for (var i = 0; i < ret.length; i++) {var sku = {SkuCode: "", SkuPrice: "", StockQuantity: ""};sku.values = [];$.each(ret[i],function () {sku.values.push({propertyId: this.PropertyId, valueId: this.Id});});vmSkus.push(sku);}

到此,更新SKU表格的代码已经实现,数据驱动视图更新,很清晰。但是什么时候去触发这个更新呢(何时去重新构建skus)? 很简单嘛,就是勾选或取消勾选属性值的时候去触发更新操作。勾选或取消勾选我们能直接从selectedValues.length上得到反馈,然后使用vue 的watch就可以实现了。但是selectedValues是properties数组中元素的一个属性,vue的watch是无法用在数组元素的某一个字段上的(至少目前我发现是这样的),那么暴力一点,直接watch整个properties数组并且加上deep:true。这样是可以实现,但是当修改自定义属性的时候也会触发变更(业务会提刀来见的)。

最终解决方案

computed:{allCheckedLength:function(){var length=0;$.each(this.properties,function(){length+=this.selectedValues.length;});return length;}}
watch: {'allCheckedLength': {handler: 'reBuild'}}

reBuild就是重新构建的方法。

demo

Java 笛卡尔积算法的简单实现
Cartesian product of multiple arrays in JavaScript


http://chatgpt.dhexx.cn/article/Cu0tDbmg.shtml

相关文章

商品SKU

前言 最近项目开发涉及商品SKU&#xff0c;商品SKU计算原理就是笛卡尔积&#xff0c;下面对相关内容做一下总结。 一、什么是SKU SKUStock Keeping Unit(库存量单位)&#xff0c;即库存进出计量的单位&#xff0c;可以是以件&#xff0c;盒&#xff0c;托盘等为单位。针对电商而…

深度学习(二)---算法岗面试题

● 神经网络为什么用交叉熵 参考回答&#xff1a; 通过神经网络解决多分类问题时&#xff0c;最常用的一种方式就是在最后一层设置n个输出节点&#xff0c;无论在浅层神经网络还是在CNN中都是如此&#xff0c;比如&#xff0c;在AlexNet中最后的输出层有1000个节点&#xff0c…

深度学习面试题常见问答

目录 有哪些方法可以避免过拟合? 造成过拟合的原因&#xff1a; 解决办法&#xff1a; dropout在训练时和推理时的区别是什么&#xff1f; L1和L2正则化的区别&#xff1f;为什么L1比L2更稀疏&#xff1f; Batch Size大小如何影响收敛速度&#xff1f; BN的原理&#x…

机器学习、深度学习笔试题面试题整理

机器学习、深度学习笔试题 面试题总结 整理看到的内容&#xff0c;以免忘记 里面添加参考的链接&#xff0c;感谢各位大佬 感受野如何计算&#xff1f; 参考链接&#xff1a;https://blog.csdn.net/a841454735/article/details/88558906 感受野指的是一个特定的 CNN 特征&am…

深度学习(三)----算法岗面试题

● 神经网络为啥用交叉熵。 参考回答&#xff1a; 通过神经网络解决多分类问题时&#xff0c;最常用的一种方式就是在最后一层设置n个输出节点&#xff0c;无论在浅层神经网络还是在CNN中都是如此&#xff0c;比如&#xff0c;在AlexNet中最后的输出层有1000个节点&#xff0c;…

深度学习(二)-----算法岗面试题

● 深度学习了解多少&#xff0c;有看过底层代码吗&#xff1f;caffe,tf? ● 除了GMM-HMM&#xff0c;你了解深度学习在语音识别中的应用吗&#xff1f; 参考回答&#xff1a; 讲了我用的过DNN-HMM&#xff0c;以及与GMM-HMM的联系与区别&#xff1b;然后RNNCTC&#xff0c;这…

深度学习面试题-2

1. 下列哪一项属于特征学习算法&#xff08;representation learning algorithm&#xff09;&#xff1f; A K近邻算法 B 随机森林 C 神经网络 D 都不属于 正确答案是&#xff1a;C&#xff0c; 您的选择是&#xff1a;C 解析&#xff1a;神经网络会将数据转化为更适合解决目…

深度学习面试题总结1-20

1.CNN的卷积核是单层还是多层的&#xff1f; 描述网络模型中某层的厚度&#xff0c;通常用名词通道channel数或者特征图feature map数。不过人们更习惯把作为数据输入的前层的厚度称之为通道数&#xff08;比如RGB三色图层称为输入通道数为3&#xff09;&#xff0c;把作为卷积…

深度学习计算机视觉常见的29道面试题及解析

点击上方&#xff0c;选择星标或置顶&#xff0c;不定期资源大放送&#xff01; 阅读大概需要15分钟 Follow小博主&#xff0c;每天更新前沿干货 作者丨我要鼓励娜扎知乎 来源丨https://zhuanlan.zhihu.com/p/89587997 编辑丨极市平台 导读 正值秋招进行时&#xff0c;本文收集…

深度学习面试题-3

1. 梯度爆炸问题是指在训练深度神经网络的时候&#xff0c;梯度变得过大而损失函数变为无穷。在RNN中&#xff0c;下面哪种方法可以较好地处理梯度爆炸问题&#xff1f; A 用改良的网络结构比如LSTM和GRUs B 梯度裁剪 C Dropout D 所有方法都不行 正确答案是&#xff1a;B&am…

深度学习算法面试题总结(38题)

原文链接:https://blog.csdn.net/attitude_yu/article/details/80963323 1. 什么是凸集、凸函数、凸学习问题&#xff1f; 凸集&#xff1a;若对集合C中任意两点u和v&#xff0c;连接他们的线段仍在集合C中&#xff0c;那么集合C是凸集。 公式表示为&#xff1a;αu(1-α)v∈C…

深度学习笔试、面试题 一

1、神经网络模型&#xff08;Neural Network&#xff09;因受人类大脑的启发而得名&#xff0c;神经网络由许多神经元&#xff08;Neuron&#xff09;组成&#xff0c;每个神经元接受一个输入&#xff0c;对输入进行处理后给出一个输出&#xff0c;如下图所示。请问下列关于神经…

面试笔试整理3:深度学习机器学习面试问题准备(必会)

第一部分&#xff1a;深度学习 1、神经网络基础问题 &#xff08;1&#xff09;Backpropagation&#xff08;要能推倒&#xff09;   后向传播是在求解损失函数L对参数w求导时候用到的方法&#xff0c;目的是通过链式法则对参数进行一层一层的求导。这里重点强调&#xff…

机器学习与深度学习常见面试题

为了帮助参加校园招聘、社招的同学更好的准备面试&#xff0c;SIGAI整理出了一些常见的机器学习、深度学习面试题。理解它们&#xff0c;对你通过技术面试非常有帮助&#xff0c;当然&#xff0c;我们不能只限于会做这些题目&#xff0c;最终的目标是真正理解机器学习与深度学习…

深度学习最全面试题总结(二)

&#x1f468;‍&#x1f4bb;作者简介&#xff1a; CSDN、阿里云人工智能领域博客专家&#xff0c;新星计划计算机视觉导师&#xff0c;百度飞桨PPDE&#xff0c;专注大数据与AI知识分享。✨公众号&#xff1a;GoAI的学习小屋 &#xff0c;免费分享书籍、简历、导图等&#xf…

大厂必考深度学习面试题及参考答案

目录 一&#xff0c;滤波器与卷积核二&#xff0c;卷积层和池化输出大小计算 2.1&#xff0c;CNN 中术语解释2.2&#xff0c;卷积输出大小计算&#xff08;简化型&#xff09;2.3&#xff0c;理解边界效应与填充 padding参考资料三&#xff0c;深度学习框架的张量形状格式四&am…

深度学习面试必备的25个问题

作者 | Tomer Amit 译者 | 弯月&#xff0c;编辑 | 屠敏 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 在本文中&#xff0c;我将分享有关深度学习的25个问题&#xff0c;希望能够帮助你为面试做好准备。 1.为什么必须在神经网络中引入非线性&#xff1f; 答&am…

深度学习算法面试题总结

1. 什么是凸集、凸函数、凸学习问题? 凸集:若对集合C中任意两点u和v,连接他们的线段仍在集合C中,那么集合C是凸集。 公式表示为:αu+(1-α)v∈C α∈[0, 1] 凸函数:凸集上的函数是凸函数。凸函数的每一个局部极小值也是全局极小值( f(x) = 0.5x^2 )。 公式表示为:f(αu…

用python计算n的阶乘的方法!(含示例代码)

前言&#xff1a; 今天为大家的内容是&#xff1a;用python计算n的阶乘的方法&#xff01;&#xff08;含示例代码&#xff09;希望通过本文内容能够对各位有所帮助&#xff0c;要是喜欢的话记得点赞转发收藏关注不迷路哦&#xff01;&#xff01;&#xff01; 提示&#xff…

python计算n的阶乘

1.程序 n int(input())def fact(n):if n 0 | n 1:return 1elif n > 1:return n * fact(n - 1)print(fact(n)) 2.分析 首先&#xff0c;阶乘本身就是一个递归问题&#xff0c;那最好的方法就是写一个递归函数&#xff0c;即函数调用自身&#xff0c;递归函数一定要有基…