PHP 商品详情页 sku多选规格时的算法,类似京东,点击任何规格,打开新的商品页

属性名表数据 attr:[id,attr_name]
1: 颜色
2: 尺码
3: 款式

属性值表数据 attr_values:[id, attr_id, attr_value]
1: 1: 红色
2: 1: 蓝色
3: 2: 41码
4: 2: 42码
5: 3: 欧版
6: 3: 美版

spu表 [spu_id, name]
1
sku表 [sku_id, spu_id, name ]
100 1 abc
101 1 xdxx
102 1 xdxdf
103 1 xdxx
104 1 xxgdx
105 1 xaxsafx
106 1 xsdxfx
107 1 xfdxsx

sku属性值关联表 sku_attr:[id, sku_id, attr_value_id]
1: 100: 1
2: 100: 3
3: 100: 5
4: 101: 1
5: 101: 3
6: 101: 6
7: 102: 1
8: 102: 4
9: 102: 5
10: 103: 1
11: 103: 4
12: 103: 6
13: 104: 2
14: 104: 3
15: 104: 5
16: 105: 2
17: 105: 3
18: 105: 6
19: 106: 2
20: 106: 4
21: 106: 5
22: 107: 2
23: 107: 4
24: 107: 6

sku集合 手写数据,非程序组装
sku_id:100 红色+41+欧版 1:3:5
sku_id:101 红色+41+美版 1:3:6
sku_id:102 红色+42+欧版 1:4:5
sku_id:103 红色+42+美版 1:4:6
sku_id:104 蓝色+41+欧版 2:3:5
sku_id:105 蓝色+42+欧版 2:4:5
sku_id:106 蓝色+41+美版 2:3:6
sku_id:107 蓝色+42+美版 2:4:6

商品详情选项:
颜色:红色 蓝色
尺码:41 42
款式:欧版 美版

第一种情况:
当打开sku 100 时,规格选项如下
颜色:红色(已选中) 蓝色(打开104)
尺码:41(已选中) 42(打开102)
款式:欧版(已选中) 美版(打开101)

第二种情况:
当打开sku 101 时,规格选项如下
颜色:红色(已选中) 蓝色(打开106)
尺码:41(已选中) 42(打开107)
款式:欧版(打开100) 美版(已选中)

请问实现这种效果,代码应该怎么写,脑袋有点大,头发都白了,最好是 PHP

经过2天的研究,将上述代码改良后,终于实现想要的效果,附上代码,希望能帮到有需要的小伙伴:

<?php
$attr = [
    [
        'attr_id'        => 1,
        'attr_name'      => '颜色',
        'attr_values'     => [
            ['id' => 1, 'value' => '红色', 'checked' => 0, 'url' => ''],
            ['id' => 2, 'value' => '蓝色', 'checked' => 0, 'url' => ''],
        ]
    ],
    [
        'attr_id'        => 2,
        'attr_name'      => '尺码',
        'attr_values'     => [
            ['id' => 3, 'value' => 41, 'checked' => 0, 'url' => ''],
            ['id' => 4, 'value' => 42, 'checked' => 0, 'url' => ''],
            ['id' => 7, 'value' => 43, 'checked' => 0, 'url' => ''],
            ['id' => 8, 'value' => 44, 'checked' => 0, 'url' => ''],
        ]
    ],
    [
        'attr_id'        => 3,
        'attr_name'      => '款式',
        'attr_values'     => [
            ['id' => 5, 'value' => '欧版', 'checked' => 0, 'url' => ''],
            ['id' => 6, 'value' => '美版', 'checked' => 0, 'url' => ''],
        ]
    ],
    [
        'attr_id'        => 4,
        'attr_name'      => '年龄段',
        'attr_values'     => [
            ['id' => 9, 'value' => '0-10',   'checked' => 0, 'url' => ''],
            ['id' => 10, 'value' => '10-20', 'checked' => 0, 'url' => ''],
        ]
    ],
];

$sku_id = 100;  //当前sku
$curr_sku_attr = [   //当前sku的属性集合 排序后
    0 => '1:1', //红色
    1 => '2:3', //41
    2 => '3:5', //欧版
    3 => '4:9'
];
$sku_list = [//spu下所有sku集合
    100 => ['1:1','2:3','3:5','4:9'],//红色 41 欧版 0-10
    101 => ['1:2','2:3','3:5','4:9'],//蓝色 41 欧版 0-10
    102 => ['1:1','2:4','3:5','4:9'],//红色 42 欧版 0-10
    103 => ['1:2','2:4','3:5','4:9'],//蓝色 42 欧版 0-10
    108 => ['1:1','2:7','3:5','4:9'],//红色 43 欧版 0-10
    109 => ['1:2','2:7','3:5','4:9'],//蓝色 43 欧版 0-10
    110 => ['1:1','2:8','3:5','4:9'],//红色 44 欧版 0-10
    111 => ['1:2','2:8','3:5','4:9'],//蓝色 44 欧版 0-10
    104 => ['1:1','2:3','3:6','4:9'],//红色 41 美版 0-10
    105 => ['1:2','2:3','3:6','4:9'],//蓝色 41 美版 0-10
    106 => ['1:1','2:4','3:6','4:9'],//红色 42 美版 0-10
    107 => ['1:2','2:4','3:6','4:9'],//蓝色 42 美版 0-10
    112 => ['1:1','2:7','3:6','4:9'],//红色 43 美版 0-10
    113 => ['1:2','2:7','3:6','4:9'],//蓝色 43 美版 0-10
    114 => ['1:1','2:8','3:6','4:9'],//红色 44 美版 0-10
    114 => ['1:2','2:8','3:6','4:9'],//蓝色 44 美版 0-10
    115 => ['1:1','2:3','3:5','4:10'],//红色 41 欧版 10-20
    116 => ['1:2','2:3','3:5','4:10'],//蓝色 41 欧版 10-20 
    117 => ['1:1','2:4','3:5','4:10'],//红色 42 欧版 10-20 
    118 => ['1:2','2:4','3:5','4:10'],//蓝色 42 欧版 10-20 
    119 => ['1:1','2:7','3:5','4:10'],//红色 43 欧版 10-20 
    120 => ['1:2','2:7','3:5','4:10'],//蓝色 43 欧版 10-20 
    121 => ['1:1','2:8','3:5','4:10'],//红色 44 欧版 10-20 
    122 => ['1:2','2:8','3:5','4:10'],//蓝色 44 欧版 10-20 
    123 => ['1:1','2:3','3:6','4:10'],//红色 41 美版 10-20 
    124 => ['1:2','2:3','3:6','4:10'],//蓝色 41 美版 10-20 
    125 => ['1:1','2:4','3:6','4:10'],//红色 42 美版 10-20 
    126 => ['1:2','2:4','3:6','4:10'],//蓝色 42 美版 10-20 
    127 => ['1:1','2:7','3:6','4:10'],//红色 43 美版 10-20 
    128 => ['1:2','2:7','3:6','4:10'],//蓝色 43 美版 10-20 
    129 => ['1:1','2:8','3:6','4:10'],//红色 44 美版 10-20 
    130 => ['1:2','2:8','3:6','4:10'],//蓝色 44 美版 10-20
];

//剔除当前sku的第一个属性,用剩余属性对比所有sku列表,包含当前剩余属性的sku留下
//[2:3],[3:5] 100,101
foreach($curr_sku_attr as $key => $csa){
    $tmp_attrs = $curr_sku_attr;
    unset($tmp_attrs[$key]);//剔除当前属性,用其他剩余属性与sku集合中的所有属性做对比,
    foreach($sku_list as $sku_key => $sku_val){
        $tmp_arr = array_intersect($sku_val, $tmp_attrs);//剔除当前属性后的其他属性与sku属性做交集 
        $result = array_diff($tmp_attrs, $tmp_arr);//用差集函数对两个属性组做对比,完全一样,返回空,表示此sku可用
        if (empty($result)){
            unset($sku_list[$sku_key]);
        }
    }
}
//循环所有属性 与剩余sku的属性做对比,确定每个属性对应的sku
foreach ($attr as &$att){
//     //第一次循环时 1:1,1:2,哪个数据不在当前sku的属性集合中,谁就可以点击,然后再匹配对应的sku,绑定对应sku的url
    foreach ($att['attr_values'] as $atkey => &$atval){
        $at_str = $att['attr_id'].':'.$atval['id'];
        if (in_array($at_str, $curr_sku_attr)){
            $atval['checked'] = 1;
        }else{
            foreach($sku_list as $skukey => $skuval){
                if (in_array($at_str, $skuval) !== false){
                    $atval['url'] = '/item/'.$skukey;
                }
            }
        }
    }
}
print_r($attr);

结果可以直接传给前端进行输出到页面,无需进行js处理,可以在上述基础上增加 库存字段,前端输出时,做一个库存字段判断,小于1时,不可点击即可
输出结果如下:


Array
(
    [0] => Array
        (
            [attr_id] => 1
            [attr_name] => 颜色
            [attr_values] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [value] => 红色
                            [checked] => 1
                            [url] => 
                        )

                    [1] => Array
                        (
                            [id] => 2
                            [value] => 蓝色
                            [checked] => 0
                            [url] => /item/130
                        )

                )

        )

    [1] => Array
        (
            [attr_id] => 2
            [attr_name] => 尺码
            [attr_values] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [value] => 41
                            [checked] => 1
                            [url] => 
                        )

                    [1] => Array
                        (
                            [id] => 4
                            [value] => 42
                            [checked] => 0
                            [url] => /item/126
                        )

                    [2] => Array
                        (
                            [id] => 7
                            [value] => 43
                            [checked] => 0
                            [url] => /item/128
                        )

                    [3] => Array
                        (
                            [id] => 8
                            [value] => 44
                            [checked] => 0
                            [url] => /item/130
                        )

                )

        )

    [2] => Array
        (
            [attr_id] => 3
            [attr_name] => 款式
            [attr_values] => Array
                (
                    [0] => Array
                        (
                            [id] => 5
                            [value] => 欧版
                            [checked] => 1
                            [url] => 
                        )

                    [1] => Array
                        (
                            [id] => 6
                            [value] => 美版
                            [checked] => 0
                            [url] => /item/130
                        )

                )

        )

    [3] => Array
        (
            [attr_id] => 4
            [attr_name] => 年龄段
            [attr_values] => Array
                (
                    [0] => Array
                        (
                            [id] => 9
                            [value] => 0-10
                            [checked] => 1
                            [url] => 
                        )

                    [1] => Array
                        (
                            [id] => 10
                            [value] => 10-20
                            [checked] => 0
                            [url] => /item/130
                        )
                )
        )
)