什么是SPU、SKU、ARPU
這是一篇存檔性筆記,我自己存檔一下對這3個詞的理解。如果你已經明了了這3個詞的意思,請直接忽略之
首先,搞清楚商品與單品的區別。例如,iphone是一個單品,但是在淘寶上當很多商家同時出售這個產品的時候,iphone就是一個商品了。
商品:淘寶叫item,京東叫product,商品特指與商家有關的商品,每個商品有一個商家編碼,每個商品下面有多個顏色,款式,可以有多個SKU。
SPU = Standard Product Unit (標准化產品單元)
SPU是商品信息聚合的最小單位,是一組可復用、易檢索的標准化信息的集合,該集合描述了一個產品的特性。通俗點講,屬性值、特性相同的商品就可以稱為一個SPU。
例如,iphone4就是一個SPU,N97也是一個SPU,這個與商家無關,與顏色、款式、套餐也無關。以化妝品為例,下圖是拍拍商城給出的SPU信息:
在商品信息電子化過程中,商品的特性可以由多個“屬性及對應的屬性值對”進行描述。“屬性及對應的屬性值對”完全相同的商品,可以抽象成為一個SPU。同 時,這些“屬性及對應的屬性值對”也在SPU中固化下來,逐步標准化。基於SPU的商品信息結構,可以實現豐富的應用,比如商品信息與資訊、評論、以及其 它SPU的整合。
P.s:從這個意義上講,我認為比較購物的產品庫以SPU為標准來建立是最合適的。
SKU=stock keeping unit(庫存量單位)
SKU即庫存進出計量的單位, 可以是以件、盒、托盤等為單位。在服裝、鞋類商品中使用最多最普遍。 例如紡織品中一個SKU通常表示:規格、顏色、款式。
也有人解釋說SKU就是庫存的最小單位,在服裝行業,正常情況是“單款單色單碼”,國內品牌有把“單款單色”當做一個SKU、也有把“單款”的幾個色當一個SKU、也有把一塊面料的幾個個款式當一個SKU,這些都是誤讀。
同時,引申出另外一個概念:SKC:單款、單色。如果一定要打比方的話:SKC是一個桔子,SKU是一瓣桔子,但不管怎么說,一個桔子是桔子,一瓣桔子也是桔子。
不過,SKU是物理上不可分割的最小存貨單元。在使用時要根據不同業態,不同管 理模式來處理。比如一香煙是50條,一條里有十盒,一盒中有20支,這些單位就要根據不同的需要來設定SKU。比如倉儲批發式大賣場,一定是按照一箱來設 定的。普通大賣場一定是按照條來設定的。煙酒專賣店一定是按照盒來設定的。過去上海等地的街邊小店一定是按一支來設定的。這樣一支就是煙的最小零售單位。 但要根據自己的業態和服務模式來設定。
P.s:關於什么是SKU、SKC,可以參考阿福先生的這篇博客。
【總結一下】:SPU是標准化產品單元,區分品種;SKU是庫存量單位,區分單品;商品特指與商家有關的商品,可對應多個SKU。
ARPU=Average Revenue Per User(每用戶平均收入)
ARPU注重的是一個時間段內運營商從每個用戶所得到的利潤。因此,高端的用戶越多,ARPU越高。在這個時間段里,從運營商的運營情況來看,ARPU值高說明利潤高,這段時間效益好。
http://www.ikent.me/blog/3017
首先說一說什么是SKU
SKU=Stock Keeping Unit(庫存量單位),即庫存進出計量的基本單元,可以是以件,盒,托盤等為單位。
SKU這是對於大型連鎖超市DC(配送中心)物流管理的一個必要的方法。現在已經被引申為產品統一編號的簡稱,每種產品均對應有唯一的SKU號。
單品:對一種商品而言,當其品牌、型號、配置、等級、花色、包裝容量、單位、生產日期、保質期、用途、價格、產地等屬性中任一屬性與其他商品存在不同時,可稱為一個單品。
https://baike.baidu.com/item/SKU/5016808?fr=aladdin
類似京東上面,未來人類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,前端拿到的數據如下


實現后的粗糙界面

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">  </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就是重新構建的方法。
作者:若邪Y
鏈接:https://www.jianshu.com/p/1aa9bc5a1158
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。