最近在做商品sku的时候遇到了一些困惑,记录一下,以备日后会看。

先说一说需求:
1.根据选中的SKU,显示对应的SKU图片,没有选中的SKU时,默认展示SPU商品图,单击放大预览;
2.每个属性下属性值有多个时,默认不选,只有一个时,默认选中;
3.后台没有设置SKU时,则无属性值展示;
4.选中交互:选中某一个属性下属性值时,检查其他属性的属性值,哪些不能组合为一个SKU,不能组合的属性值只读,原选中的则取消选中。
已上就是给出的文字需求,在需求讨论的时候产品定了调调,通过既定的属性去确定一个sku,即所有未选择的属性假定一个初始值。一听心里乐了,所有选中的属性都已知,排序之后再匹配不就是轻松确定sku了嘛,美滋滋。
/**
* 获取商品sku属性(初始默认选中,已经被否了呀)
*/
public function goods_sku_version_1 (){
$goodsId = $this->post['goods_id'] or $this->response(201, 'goods_id不能为空');
$catId = mall_database_execute('goods')
->where(['goods_id' => $goodsId, 'is_on_sale'=> 1, 'is_delete' => 0])
->getField('goods_type')
or $this->response(208, '商品不存在');
//构建查询条件
$where = ['gs.goods_id'=> $goodsId];
$attrArr = [];
if (!empty($this->post['attr_id'])){
$attrArr = explode(',', $this->post['attr_id']);
sort($attrArr); //升序
$where['gs.attr_id_arr'] = implode(',', $attrArr);
}
//获取sku信息
$this->rows['info'] = mall_database_execute('goods_sku')->alias('AS gs')
->where($where)
->find() or $this->response(208, 'sku不存在');
if (empty($this->post['attr_id'])) $attrArr = explode(',', $this->rows['info']['attr_id_arr']);
//获取顶级sku列表
$this->rows['attribute'] = mall_database_execute('goods_sku_list')->alias('AS gsl')
->field('ga.attr_id, ga.attr_type, ga.attr_name, gsl.attr_values_arr')
->join(mall_database_table('goods_attribute').' AS ga ON ga.attr_id = gsl.attr_id', 'LEFT')
->where([
'gsl.goods_id' => $goodsId,
'gsl.status' => 1
])
->select() ? : '';
if (!empty($this->rows['attribute'])){
//通过二定一待,确定sku
foreach ($this->rows['attribute'] as $k=>&$v){
$newAttrArr = $attrArr;
$newAttrArr[$k] = '%';
$str = implode(',', $newAttrArr);
$v['option'] = mall_database_execute('goods_sku')
->field('goods_sku_id,attr_id_arr,status'
)
->where([
'goods_id' => $goodsId,
'attr_id_arr' => ['LIKE', $str]
])
->select();
if (!empty($v['option'])){
foreach ($v['option'] as &$vo){
$newAttrArr = explode(',', $vo['attr_id_arr']);
$attrInfo = mall_database_execute('goods_attribute')
->field('attr_id, attr_type, attr_name')
->where([
'attr_id' => $newAttrArr[$k]
])
->find();
unset($vo['attr_id_arr']);
$vo = array_merge($attrInfo, $vo);
}
}
}
}
$this->response();
}本以为这样就完事了,结果没过多久需求就改了,不假定每个属性的初始值,根据用户当前选择动态匹配sku,GG。这个方案一开始没想明白的点在于,基于用户当前选择,推算所有属性的节点是否还有可选的可能(可用sku),之前想到过这一层面,想着偷懒完成需求即可,便没有深究。
/**
* 基于用户当前属性选择状态,获取sku,及推算每个属性的可选状态
*/
public function goods_sku(){
$goodsId = $this->post['goods_id'];
//检测商品是否存在
mall_database_execute('goods')
->where(['goods_id' => $goodsId, 'is_on_sale'=> 1, 'is_delete' => 0])
->getField('goods_id')
or $this->response(208, '商品不存在');
$where = [
'goods_id' => $goodsId,
'status' => 1
];
//获取所有可选sku的属性组合
$allSkuLists = array_column(mall_database_execute('goods_sku')
->field('attr_id_arr')
->where($where)
->select(), 'attr_id_arr');
$this->rows['sku_num'] = count($allSkuLists);
if (!empty($this->post['attr_id'])){
$attrArr = explode(',', $this->post['attr_id']);
foreach ($attrArr as &$vv){
if ($vv == '') $vv = '%';
}
$where['old_id_arr'] = ['LIKE', implode(',', $attrArr)];
}
//查询一个当前用户选择状态下满足条件的组合(先这样,等产品出了可能组合排序规则再完善)
$this->rows['info'] = mall_database_execute('goods_sku')
->field('goods_sku_id,price,goods_number,attr_value,goods_thumb')
->where($where)
->find() ? : '';
if ($this->rows['info']['goods_thumb']) $this->rows['info']['goods_thumb'] = change_file_path($this->rows['info']['goods_thumb']);
//获取规格
$attribute = mall_database_execute('goods_sku_list')->alias('AS gsl')
->field('ga.attr_id, ga.attr_type, ga.attr_name, gsl.attr_values_arr')
->join(mall_database_table('goods_attribute').' AS ga ON ga.attr_id = gsl.attr_id', 'LEFT')
->where([
'gsl.goods_id' => $goodsId,
'gsl.status' => 1
])
->order('attr_type asc, attr_id asc')
->select();
if (!empty($attribute)){
//遍历获取所有规格的属性,并假定每种属性都不可选
foreach ($attribute as $k=>&$v){
$v['option'] = mall_database_execute('goods_attribute')
->field('attr_id,attr_type,attr_name,2 as status')
->where([
'attr_id' => ['IN', $v['attr_values_arr']],
'status' => 1
])
->order('attr_id asc')
->select();
unset($v['attr_values_arr']);
if (!empty($allSkuLists)){
//遍历所有属性判断基于用户选择状态下属性是否有可选方案
foreach ($v['option'] as &$vo){
//获取用户当前选择
$checkSku = explode(',', $this->post['attr_id']);
//把当前属性与用户选择进行组合
$checkSku[$k] = $vo['attr_id'];
//遍历所有可能的组合列表,查找是否有匹配当前的组合
foreach ($allSkuLists as $vov){
//判断条件:如果我有的你都有那就对了
$intersect = array_intersect($checkSku, explode(',', $vov));
asort($intersect);
asort($checkSku);
//序列化后做比较
if (implode(',', $intersect) == implode(',', array_filter($checkSku))) $vo['status'] = '1';
}
}
}
}
}
$this->rows['attribute'] = $attribute ? : '';
$this->response();
}附上表结构:
CREATE TABLE `fd_goods_sku` ( `goods_sku_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', `goods_id` int(11) NOT NULL, `old_id_arr` varchar(255) NOT NULL DEFAULT '' COMMENT '没排序之前的id组合', `attr_id_arr` varchar(255) NOT NULL DEFAULT '0' COMMENT '属性id', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1正常,2失效', `price` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '售价,单位分', `goods_number` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '库存', `attr_value` varchar(255) NOT NULL DEFAULT '' COMMENT '商品自定义属性', `goods_thumb` varchar(255) NOT NULL DEFAULT '', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`goods_sku_id`), KEY `goods_id` (`goods_id`,`goods_sku_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2208 DEFAULT CHARSET=utf8mb4 COMMENT='商品sku表'; CREATE TABLE `fd_goods_sku_list` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `goods_id` int(10) unsigned NOT NULL, `attr_id` varchar(255) NOT NULL DEFAULT '' COMMENT '属性id', `attr_values_arr` varchar(255) NOT NULL DEFAULT '' COMMENT '属性值id', `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '1正常,2失效', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=599 DEFAULT CHARSET=utf8mb4 COMMENT='商品已选属性表';
以上仅作记录,如大神们有更好方案请不吝赐教。
