2、页面组成

2.1 页面全局变量

NSMutableArray datas; //规格明细列表:排列组合的数据源
NSMutableArray
sectionMenuArr; //记录选中的大类型;
NSMutableDictionary itemArrDic; //map 存放key:为id , 值为已选的规格类型对象
itemSelectedArrDic
NSMutableDictionary
itemSelectedArrDic; //已选的规格类型下的规格属性数组。
itemSelectedArrDic

2.2 构建一个树结构

根据提交给服务器的组合字符窜如 “11:167918-101:123253-102:123258”, 这个是一个有三个层级表示的SKU 组合。
举例:天猫购买手机,加入购物车的时候选择 内存:64g + 颜色:白色 + 套餐类型: 官方标配
其中包含内容:1)规格大类型要先排好序 ,属性要一一对应类型。 三个层级的SKU组合应该比较常见。通过这里,我们构件一个model实体。结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface ConditionFilter : NSObject<NSCopying,NSMutableCopying>

@property(nonatomic,assign) NSInteger value; // id值
@property(nonatomic,strong) NSString *name; //名称

@property(nonatomic,copy) NSArray<ConditionFilter> *statusItem; //子级
@property(nonatomic,assign) NSInteger state; //选中状态: 1已选择 0未选择
@property(nonatomic,strong) NSString * propertyCatId; //规格类型: 一级分类的id
@property(nonatomic,strong) NSString * propertyId; //规格属性: 二级分类id

@property(nonatomic,strong) NSString * pid; //父节点编号(随机生成)
@property(nonatomic,strong) NSString * nodeId; //节点编号(随机生成)
@property(nonatomic,strong) ConditionFilter *parent; //父节点(父只有一个)
@property(nonatomic,assign) BOOL extend; //是否展开
@property(nonatomic,assign) NSInteger level;//当前层级

@end

2.3 根据已选的规格类型 自由排列组合 出明细列表各项组合数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#pragma mark - 从最后一个层级算起;往父类赋值;(核心: 给statusItem赋值)
-(void)configDataSectionReload
{
//先把已选择的大类,过滤出已选择的属性项的大类
NSMutableArray *hasChooseSectionMenuArr = [[NSMutableArray alloc] init];
for(ConditionFilter *sectionMenu in self.sectionMenuArr){
NSArray * itemChooseArr = [self.itemSelectedArrDic objectForKey:@(sectionMenu.value)];
if(itemChooseArr.count){
[hasChooseSectionMenuArr addObject:@(sectionMenu.value)];
}
}

//确定树的层级:为选择的已选大类型个数。并绑定子节点集合statusItem
NSMutableArray *childArr = nil;
for (NSInteger level = hasChooseSectionMenuArr.count; level>0; level -- ) {

NSNumber *cellSectionTag = [hasChooseSectionMenuArr objectAtIndex:level-1];
//可变集合的copy 和 mutableCopy 是一样;深拷贝,地址不一样;如果不用copy会造成多个地方引用地址对象;值会随着关联;
NSMutableArray *itemSelectArr = [[self.itemSelectedArrDic objectForKey:cellSectionTag] mutableCopy];

for(NSInteger i=0; i< itemSelectArr.count; i++){
ConditionFilter *item = [itemSelectArr objectAtIndex:i];
item.level = level; //标记等级
item.extend = NO;
item.nodeId = nil;
item.pid = nil;

//(这里使用拷贝),为子节点赋值。
item.statusItem = [[NSMutableArray alloc] initWithArray:childArr copyItems:YES];
}

childArr = [itemSelectArr mutableCopy]; //(防止对childArr的来源数据源污染,这里使用拷贝)(fillParentNodeId 会对数据源childArr 进行污染;如改变对象的name等设置)
}

//清空
[self.datas removeAllObjects];

//填充子节点绑定父节点pid; childArr是形成的一颗树结构。
[self fillParentNodeId:childArr parentNode:nil];
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#pragma mark - 从前往后赋值( 给子节点绑定标识父类parent),用于拼装properties 组合的id字符窜
-(void)fillParentNodeId:(NSArray *)itemArr parentNode:(ConditionFilter *)parent
{
for(NSInteger i =0 ;i < itemArr.count; i++){
ConditionFilter *filter = [itemArr objectAtIndex:i];
filter.pid = parent.nodeId;
filter.parent = parent; //绑定父级节点

NSString *nodeStr = [NSString uniqueStringForMessage];
filter.nodeId = nodeStr;
filter.extend = filter.statusItem.count;

if(self.dataShowLayoutStyle == LayoutComposeStyle){ //排列组合样式;

if(filter.statusItem.count == 0){
//根据statusItem等于0 设置层级为1级的时候name值 组合成: 白色+XL , 白色+L 格式;赋值给最后一个层级models的name属性
NSMutableArray *allJoinNamesArr = [[NSMutableArray alloc] init];
[allJoinNamesArr addObject:filter.name];
ConditionFilter *parent = filter.parent;
while (parent) {
[allJoinNamesArr insertObject:parent.name atIndex:0];
parent = parent.parent;
}
NSString *allJoinName = [allJoinNamesArr componentsJoinedByString:@"+"];
filter.name = allJoinName; //拼接UI显示的name
filter.level = 1; //排列组合样式都为1级UI显示的间距.(label显示时候的左边距)
[self.datas addObject:filter]; //只添加最后一个层级;
}

}else{ //树层级 样式(全部添加)

[self.datas addObject:filter];
}
//递归
[self fillParentNodeId:filter.statusItem parentNode:filter];
}
}

2.4 自由排列组合 ,把各项值 赋值到规格明细表中

先把各项值赋值给SKUModel ,存到根据排列组合字符窜为key ,存放到map中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//设置SKU值
NSArray *skuArr = [response.responseObject objectForKey:@"sku"];
for(NSInteger i=0 ;i <self.datas.count; i++){
ConditionFilter *filter = [self.datas objectAtIndex:i];
NSString *storeCellKey = filter.name;

NSString *properties = [self processPropertiesByFilter:filter];
//找到sku 设置信息;
for(SkuDetailModel *sku in skuArr){
if([sku.properties isEqualToString:properties]){

SKUModel *writeSku = [[SKUModel alloc] init];
writeSku.properties = sku.properties;
writeSku.groupPrice = sku.groupPrice;
writeSku.price = sku.price;
writeSku.image = sku.image;
[self.writeFieldBoxDic setObject:writeSku forKey:storeCellKey];

break;
}
}
}

2.5 properties的自由组合id值拼接

循环取出其父节点. 记录大类型:属性 格式。 根据key 排序,拼接成 A:aa - B:bb - C:cc 格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#pragma mark - 处理每行规格填写的 普通价和拼团价 返回 sku的组合properties值
-(NSString *)processPropertiesByFilter:(ConditionFilter *)filter
{
NSMutableDictionary *mDic = [[NSMutableDictionary alloc] init];
[mDic setObject:filter.propertyId forKey:filter.propertyCatId];

ConditionFilter *parent = filter.parent;
while (parent) {
[mDic setObject:parent.propertyId forKey:parent.propertyCatId];
parent = parent.parent;
}

//排序
NSArray *keyArr = [mDic.allKeys sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {

NSNumber *num1 = [NSNumber numberWithInteger:[obj1 integerValue]];
NSNumber *num2 = [NSNumber numberWithInteger:[obj2 integerValue]];
NSComparisonResult result = [num1 compare:num2];
return result == NSOrderedDescending; // 升序
}];

NSMutableArray *joinStrArr = [[NSMutableArray alloc] init];
for(NSString *key in keyArr){
NSString *str = [NSString stringWithFormat:@"%@:%@",key,[mDic objectForKey:key]];
[joinStrArr addObject:str];
}
NSString *properties = [joinStrArr componentsJoinedByString:@"-"];
return properties;
}

2.6 列表的UI显示: tableView相关委托

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

//共两个分组。第一个分组展示选择的规格类型。 第二个分组是规格明细表单项
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.sectionMenuArr.count + 1;
}

//当为第二个分组时,显示的行数为排列组合数
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(section == self.sectionMenuArr.count){
return self.datas.count;
}
return 1;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.section == self.sectionMenuArr.count){
//排列组合的Cell显示

//排列组合的名字
ConditionFilter *filter = [self.datas objectAtIndex:indexPath.row];
cell.nameLabel.text = filter.name;

//某一排列组合名称对应的 skuModel 记录的表单值和properties值
SKUModel *sku = [self.writeFieldBoxDic objectForKey:filter.name];
}
}

2.7 修改规格明细 的表单值

修改每一个明细项的时候,可对应根据TextFieldValueChange 事件变化,把值赋值给每一项排列组合的key对应的skuModel中。
skuModel对象: {“price”:100,”groupPrice”:88,”properties”:”11:167918-101:123253-102:123259”}
准备一个字典或map:writeFieldBoxDic 根据排列组合的字符窜 “A+B+C”作为key, skuModel作为value 存储;
writeFieldBoxDic {
“A+B+C”: skuModel

}
cell 取值显示的时候,根据key 取得 skuModel 的值;field值改变得时候,根据key取得skuModel. 存在直接修改model的属性,不存在则创建一个新的skuModel 存到writeFieldBoxDic中;

2.8 提交的表单条件判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-(void)submitAction
{
BOOL needReturnFlag = NO; //是否需要阻止提醒;
NSMutableArray *skuArr = [[NSMutableArray alloc] init];
for(NSInteger i=0; i<self.datas.count; i++){
ConditionFilter *filter = [self.datas objectAtIndex:i];
SKUModel *sku = [self.writeFieldBoxDic objectForKey:filter.name];
if(sku){
[skuArr addObject:[sku mj_JSONObject]];
if(sku.price == nil || sku.groupPrice == nil){
needReturnFlag = YES;
break;
}
}else{
needReturnFlag = YES;
}
}
if(needReturnFlag || skuArr.count == 0){
[MBProgressHUD showMessage:@"所有规格普通价需填写完整!"];
return ;
}

//...保存到服务器
}

百度脑图:店铺商品 与 产品库 功能操作关系图

评论