前言
前段时间刚接到产品需求,需要改版商城,其中就涉及到类似天猫京东那样的商品SKU,而且需要兼容多种规格,还需要无库存的规格是没法是不可选中的,自己也想了一些,总觉得方案不完美,于是各种Google,好多都是JS的方案,看了下代码,也觉得对于计算速度没有多大提升,于是放弃上网查找了,就准备开始自己写完这块
简述
先举一个简单的例子
属性 | 具体分类 |
---|---|
颜色 | 红色,绿色 |
尺寸 | XL L |
肌肤类型 | 干性,油性 |
口味 | 原味 薄荷 |
先从view层封装,将需要设计的页面分为四个自定义的view
-
StoreStandardButton (单个规格的按钮,有选中,非选中,不可用三种状态,对应就是上述表中的红色,绿色,XL之类的单个属性)
-
StoreStandardView(同种属性的所有规格列表,对应的就是颜色这一栏,虽有的单个规格:红色,绿色)
-
StoreStandardInfoView(所有的不同PropListView组成的所有属性集合的view)
-
StoreStandardAlertView(讲商品基本信息,库存,InfoListView以及一些其他信息和按钮封装在一起)
按照上述的封装原则封装完毕后就可以展示我们购买商品时弹出的那个选择规格确认框了,但是我的思路不一定是最好的,只是当时是这么做的,就按照这个思路来写了
思路,SKU实现
需要的类创建完毕后,相对复杂的地方就来了,组合查询,怎么实现组合查询呢?
后台只提供了所有SKU组合情况,形如下面的情况:
- 652332_3232_3223_19,库存:5,价格:3
- 652331_3232_3223_19, 库存:3,价格:2
……
前面的652332_3232_3223_19是规格的组合,后面对应的库存和价格,中间的数字都是各自规格的id
那么查询的方案全部都要APP端来实现了,我的做法就是逐一遍历,因为SKU的情况不会很多,所以就算遍历这点计算量也不会很大,而且按照上述的封装思路后,很多工作都可以交给对应的对象去执行,代码写起来思路会清晰很多,最后实现的代码也比较简洁。
大致思路如下:
-
每次点击一个StoreStandardButton后,将之前选中的规格和现在的拼成新的规格组合
-
让StoreStandardInfoView去检查选中新规格后哪些规格StoreStandardButton不可点击了
-
StoreStandardInfoView让每一个StoreStandardView去检查那些按钮不可点击,同种属性的StoreStandardView不用再检测(例如选完红色后,不用再去检查颜色的StoreStandardView)
-
StoreStandardView逐个检测StoreStandardButton是否可点击
经过上述遍历后,可以遍历完所有的情况了,但是有些情况是可以不用遍历的
- 同种属性组的button都不用检查
- 已经选中的规格不用检查
上面四步的具体实现代码如下:
1.拼成新的规格组合,让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)
{
//规格选择完毕显示单个库存
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
{
//未选择完显示总规格
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检查的实现
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) {
//如果点击的button不是当前view的button;点击当前行的话不用检查当前行的是否可点击
[tempView checkSelectStandards:selectString detailInventory:arr];
}
}
}
3.每一个button检查的实现
BOOL hasSelected = false;
int sign = 0;
//非选中状态的按钮全部置灰
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;
}];
}
//判断可点击的按钮
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
}
}
组合查询的代码关键就是上述的这些代码了。
至此,就完成SKU组合查找了。
问题
问题一, 如果一个规格没有了,例如红色没了,一进去就应该让红色不能点击
思路,建立一个Map,然后逐一遍历所有的规格,单个规格的所有库存都加上去,最后遍历Map,将库存为零的规格给设置为不可点击,具体的做法是给所有的button发个通知人,让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) {
//某一单一规格,对应的所有商品都没有
[[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;
}
}
问题二,如果只有一个组合可选,那么默认选上
具体的做法也是给所有button发个通知,告诉那些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];
}
后续
剩下的都是一些跟需求相关的细节了,基本上一天的时间写完这个东西的,没有想象中那么难,不过总觉得这种写法很low,如果有更好的方案,欢迎不吝赐教。如果有什么不明白的地方欢迎和我交流~~~~
网友评论