前言
前段時(shí)間剛接到產(chǎn)品需求琢唾,需要改版商城楞件,其中就涉及到類似天貓京東那樣的商品SKU兴蒸,而且需要兼容多種規(guī)格视粮,還需要無庫存的規(guī)格是沒法是不可選中的,自己也想了一些橙凳,總覺得方案不完美蕾殴,于是各種Google,好多都是JS的方案岛啸,看了下代碼钓觉,也覺得對于計(jì)算速度沒有多大提升,于是放棄上網(wǎng)查找了坚踩,就準(zhǔn)備開始自己寫完這塊
簡述
先舉一個(gè)簡單的例子
屬性 | 具體分類 |
---|---|
顏色 | 紅色荡灾,綠色 |
尺寸 | XL L |
肌膚類型 | 干性,油性 |
口味 | 原味 薄荷 |
先從view層封裝瞬铸,將需要設(shè)計(jì)的頁面分為四個(gè)自定義的view
-
StoreStandardButton (單個(gè)規(guī)格的按鈕批幌,有選中,非選中嗓节,不可用三種狀態(tài)荧缘,對應(yīng)就是上述表中的紅色,綠色拦宣,XL之類的單個(gè)屬性)
-
StoreStandardView(同種屬性的所有規(guī)格列表截粗,對應(yīng)的就是顏色這一欄,雖有的單個(gè)規(guī)格:紅色鸵隧,綠色)
-
StoreStandardInfoView(所有的不同PropListView組成的所有屬性集合的view)
-
StoreStandardAlertView(講商品基本信息桐愉,庫存,InfoListView以及一些其他信息和按鈕封裝在一起)
按照上述的封裝原則封裝完畢后就可以展示我們購買商品時(shí)彈出的那個(gè)選擇規(guī)格確認(rèn)框了掰派,但是我的思路不一定是最好的,只是當(dāng)時(shí)是這么做的左痢,就按照這個(gè)思路來寫了
思路靡羡,SKU實(shí)現(xiàn)
需要的類創(chuàng)建完畢后系洛,相對復(fù)雜的地方就來了,組合查詢略步,怎么實(shí)現(xiàn)組合查詢呢描扯?
后臺只提供了所有SKU組合情況,形如下面的情況:
- 652332_3232_3223_19趟薄,庫存:5绽诚,價(jià)格:3
- 652331_3232_3223_19, 庫存:3,價(jià)格:2
……
前面的652332_3232_3223_19是規(guī)格的組合杭煎,后面對應(yīng)的庫存和價(jià)格恩够,中間的數(shù)字都是各自規(guī)格的id
那么查詢的方案全部都要APP端來實(shí)現(xiàn)了,我的做法就是逐一遍歷羡铲,因?yàn)镾KU的情況不會很多蜂桶,所以就算遍歷這點(diǎn)計(jì)算量也不會很大,而且按照上述的封裝思路后也切,很多工作都可以交給對應(yīng)的對象去執(zhí)行扑媚,代碼寫起來思路會清晰很多,最后實(shí)現(xiàn)的代碼也比較簡潔雷恃。
大致思路如下:
-
每次點(diǎn)擊一個(gè)StoreStandardButton后疆股,將之前選中的規(guī)格和現(xiàn)在的拼成新的規(guī)格組合
-
讓StoreStandardInfoView去檢查選中新規(guī)格后哪些規(guī)格StoreStandardButton不可點(diǎn)擊了
-
StoreStandardInfoView讓每一個(gè)StoreStandardView去檢查那些按鈕不可點(diǎn)擊,同種屬性的StoreStandardView不用再檢測(例如選完紅色后倒槐,不用再去檢查顏色的StoreStandardView)
-
StoreStandardView逐個(gè)檢測StoreStandardButton是否可點(diǎn)擊
經(jīng)過上述遍歷后旬痹,可以遍歷完所有的情況了,但是有些情況是可以不用遍歷的
- 同種屬性組的button都不用檢查
- 已經(jīng)選中的規(guī)格不用檢查
上面四步的具體實(shí)現(xiàn)代碼如下:
1.拼成新的規(guī)格組合导犹,讓StoreStandardInfoView去檢查
-(void)getClickBtnNotificaiton:(NSNotification *)info
{
StoreStandardButton *btn = (StoreStandardButton *)info.object;
if (!self.selectStandards) {
self.selectStandards = [[NSMutableArray alloc] init];
}
BOOL hasContain = false;
for ( int i = 0; i < self.selectStandards.count; i++) {
int a = [self.selectStandards[i] intValue];
if (a == btn.model.propId) {
hasContain = true;
}
}
if (!hasContain) {
//去掉同行的其他屬性
MeDetailSizeAndColor *model = _arr[btn.listIndex];
for (MeDetailSizeAndColorProps *prop in model.props) {
if ([_selectStandards containsObject:@(prop.propId)]) {
self.selectStandards = [[self.selectStandards bk_reject:^BOOL(id obj) {
int t = [obj intValue];
return t==prop.propId;
}] mutableCopy];
}
}
[self.selectStandards addObject:@(btn.model.propId)];
[self.infoView checkWithSelectStandards:self.selectStandards detailInventory:_detailArr listIndex:btn.listIndex];
}
if(self.selectStandards.count == _arr.count)
{
//規(guī)格選擇完畢顯示單個(gè)庫存
for (MeDetailDetailInventory *pro in self.detailArr) {
BOOL eqaul = true;
for (int tm = 0; tm<self.selectStandards.count; tm++) {
int value = [self.selectStandards[tm] intValue];
if(![pro.id containSubString:[NSString stringWithFormat:@"%d_",value]])
{
eqaul = false;
}
}
if (eqaul == true) {
self.proNum = pro.count;
self.price = [NSString stringWithFormat:@"%.2lf",pro.price];
self.priceLab.text = [NSString stringWithFormat:@"¥%@",self.price];
}
}
}
else
{
//未選擇完顯示總規(guī)格
self.proNum = self.num;
}
//刷新庫存UI
_stockNumL.text = [NSString stringWithFormat:@"(總庫存%ld件)",self.proNum];
if(self.proNum < self.sum)
{
self.sum = self.proNum;
self.countTf.text = [NSString stringWithFormat:@"%ld",self.sum];
}
}
2.StoreStandardView檢查的實(shí)現(xiàn)
for (int i = 0; i < self.subviews.count; i++) {
UIView *view = self.subviews[i];
if ([view isKindOfClass:[StoreStandardView class]]) {
StoreStandardView *tempView = (StoreStandardView *)view;
if (tempView.listIndex != listIndex) {
//如果點(diǎn)擊的button不是當(dāng)前view的button唱凯;點(diǎn)擊當(dāng)前行的話不用檢查當(dāng)前行的是否可點(diǎn)擊
[tempView checkSelectStandards:selectString detailInventory:arr];
}
}
}
3.每一個(gè)button檢查的實(shí)現(xiàn)
BOOL hasSelected = false;
int sign = 0;
//非選中狀態(tài)的按鈕全部置灰
for (UIView *subview in self.subviews) {
if ([subview isKindOfClass:[StoreStandardButton class]]) {
StoreStandardButton *btn = (StoreStandardButton *)subview;
if (!btn.selected) {
btn.enabled = false;
}
else
{
hasSelected = true;
sign = btn.model.propId;
}
}
}
//去掉同行選中的其他屬性
NSArray *lastArray = [NSArray arrayWithArray:string];
if (hasSelected) {
lastArray = [lastArray bk_reject:^BOOL(id obj) {
int t= [obj intValue];
return t==sign;
}];
}
//判斷可點(diǎn)擊的按鈕
for (UIView *view in self.subviews) {
if ([view isKindOfClass:[StoreStandardButton class]]) {
StoreStandardButton *btn = (StoreStandardButton *)view;
if (!btn.enabled) {
int proid = btn.model.propId;
for (MeDetailDetailInventory *model in arr) {
if (model.count > 0) {
NSString *pros = model.id;
BOOL canClick = true;
for (int a = 0; a< lastArray.count; a++) {
int t = [lastArray[a] intValue];
NSString *idString = [NSString stringWithFormat:@"%d_",t];
if (![pros containSubString:idString]) {
canClick = false;
break;
}
}
if (canClick) {
if ([pros containSubString:[NSString stringWithFormat:@"%d_",btn.model.propId]]) {
btn.enabled = canClick;
break;
}
}
} //if model.count
} //for_arr
}//btn.enable
}
}
組合查詢的代碼關(guān)鍵就是上述的這些代碼了。
至此谎痢,就完成SKU組合查找了磕昼。
問題
問題一, 如果一個(gè)規(guī)格沒有了节猿,例如紅色沒了票从,一進(jìn)去就應(yīng)該讓紅色不能點(diǎn)擊
思路,建立一個(gè)Map滨嘱,然后逐一遍歷所有的規(guī)格峰鄙,單個(gè)規(guī)格的所有庫存都加上去,最后遍歷Map太雨,將庫存為零的規(guī)格給設(shè)置為不可點(diǎn)擊吟榴,具體的做法是給所有的button發(fā)個(gè)通知人,讓button自己檢查
NSMutableDictionary *muDict = [NSMutableDictionary dictionary];
for (MeDetailDetailInventory *model in _detailArr) {
NSArray *tArr = [model.id componentsSeparatedByString:@"_"];
for (NSString *proString in tArr) {
if (proString && proString.length > 0) {
if ([muDict objectForKey:proString]) {
NSInteger numOri = [[muDict objectForKey:proString] integerValue];
numOri+=model.count;
[muDict setObject:@(numOri) forKey:proString];
}
else
{
[muDict setObject:@(model.count) forKey:proString];
}
}
}
}
__block NSMutableArray *noCountArr = [NSMutableArray array];
[muDict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSInteger skuCount = [obj integerValue];
if (skuCount == 0) {
[noCountArr addObject:key];
}
}];
if (noCountArr > 0) {
//某一單一規(guī)格囊扳,對應(yīng)的所有商品都沒有
[[NSNotificationCenter defaultCenter] postNotificationName:ButtonNoCountNotificaiton object:noCountArr];
}
button檢查的代碼如下:
-(void)getNoCountNotificaiton:(NSNotification *)info
{
NSArray *arr = info.object;
NSString *t = [NSString stringWithFormat:@"%d",self.model.propId];
if ([arr containsObject:t]) {
self.enabled = false;
}
}
問題二吩翻,如果只有一個(gè)組合可選兜看,那么默認(rèn)選上
具體的做法也是給所有button發(fā)個(gè)通知,告訴那些button需要被選中
-(void)checkOnlyOneProp
{
NSArray *uniArr = [_detailArr bk_select:^BOOL(MeDetailDetailInventory* obj) {
return obj.count > 0;
}];
if (uniArr.count == 1) {
MeDetailDetailInventory *inventModel = uniArr[0];
[self setSelectType:inventModel.id];
_stockNumL.text = [NSString stringWithFormat:@"(總庫存%ld件)",inventModel.count];
}
}
-(void)setSelectType:(NSString *)prods
{
[[NSNotificationCenter defaultCenter] postNotificationName:ButtonSelectNotification object:prods];
}
后續(xù)
剩下的都是一些跟需求相關(guān)的細(xì)節(jié)了狭瞎,基本上一天的時(shí)間寫完這個(gè)東西的细移,沒有想象中那么難,不過總覺得這種寫法很low熊锭,如果有更好的方案弧轧,歡迎不吝賜教。如果有什么不明白的地方歡迎和我交流~~~~