series = $series; $this->brands = $brands; $data = array_merge($brands,$series); $tree = $this->buildTree($data); $formattedTree = $this->formatTree($tree); $data = Attributes::order('sort_order')->select(); $res = []; foreach ($data as $datum){ $datum->options = json_decode($datum->options); $re = $datum->toArray(); $out = [ 'id' => $re['id'], 'label' => $re['name'], 'type' => $re['input_type'], 'options' => $re['options'], 'name' => $re['field_key'], 'value' => $value_map[$re['id']] ?? null, ]; $res [] =$out; } $out = [ 'brands' => $formattedTree, 'extend' => $res ]; return $this->return_json($out); } public function car() { $data = request()->post(); $build = Cars::where('is_active',1); $attr = $data['attr'] ?? null; $brand = $data['brand'] ?? null; if ($attr){ $ids = $this->getAttrIds($attr); $build->whereIn('id',$ids); } if ($brand){ $build->whereIn('series_id',$brand); } $list = $build->paginate(); $res = []; $car_ids = []; foreach ($list->items() as $item){ $out = $item->toArray(); $car_ids [] = $item['id']; $images = explode(',',$out['cover_image']); $images = array_map(function($url) { return cdnurl($url, true); // true 表示生成绝对路径 }, $images); $out['cover_image'] = $images; $res [] = $out; } $attr_value = AttributeValue::whereIn('car_id',$car_ids)->select(); $attr_array = []; foreach ($attr_value as $item){ $attr_array [] = $item->toArray(); } $attr_field = Attributes::order('sort_order')->select(); $attr_field_array = []; foreach ($attr_field as $datum){ $datum->options = json_decode($datum->options,true); $re = $datum->toArray(); $out = [ 'id' => $re['id'], 'label' => $re['name'], 'type' => $re['input_type'], 'options' => $re['options'], 'name' => $re['field_key'], 'sort_order' => $re['sort_order'], ]; $attr_field_array [] =$out; } $car_attr_map = $this->mapAllCarAttributesSorted($attr_array,$attr_field_array); foreach ($res as &$re){ if (isset($car_attr_map[$re['id']])){ $re['attr'] = $car_attr_map[$re['id']]; } } return $this->return_json( [ 'total' => $list->total(), 'items' => $res ] ); } function mapAllCarAttributesSorted(array $carAttributes, array $attributeDefs): array { // 把属性定义按 id 映射为键,并附带 sort_order $defMap = []; foreach ($attributeDefs as $def) { $defMap[$def['id']] = $def; } // 先聚合 car_id 下的属性条目 $cars = []; foreach ($carAttributes as $attr) { $carId = $attr['car_id']; $attributeId = $attr['attribute_id']; $value = $attr['value']; if (!isset($defMap[$attributeId])) continue; $def = $defMap[$attributeId]; $label = $def['label']; $type = $def['type']; $sortOrder = $def['sort_order']; $key = null; if ($type === 'checkbox') { foreach ($def['options'] as $opt) { if ((string)$opt['value'] === (string)$value) { $key = $opt['key']; break; } } } elseif ($type === 'range') { $key = $value . $def['options']['unit']; } if (!is_null($key)) { $cars[$carId][] = [ 'label' => $label, 'key' => $key, 'sort_order' => $sortOrder ]; } } // 对每个 car_id 下的属性按 sort_order 排序,并转成 label => key 格式 $result = []; foreach ($cars as $carId => $items) { usort($items, function($a, $b) { return $a['sort_order'] <=> $b['sort_order']; }); foreach ($items as $item) { $result[$carId][$item['label']] = $item['key']; } } return $result; } private function getAttrIds($attrs) { $attrDB = Attributes::field('id,field_key,input_type')->select(); $attr_array = []; foreach ($attrDB as $item){ $attr_array[] = $item->toArray(); } $attr_map = array_column($attr_array,null,'field_key'); $car_id = []; foreach ($attrs as $key=>$item) { if (isset($attr_map[$key])){ $field = $attr_map[$key]; if ($field['input_type'] == 'checkbox'){ $ids = AttributeValue::where('attribute_id',$field['id']) ->whereIn('value',$item)->column('DISTINCT car_id'); if ($car_id){ $car_id = array_intersect($car_id,$ids); }else{ $car_id = $ids; } }elseif ($field['input_type'] == 'range'){ $ids = AttributeValue::where('attribute_id',$field['id']) ->where('value','>=',$item['start']) ->where('value','<=',$item['end']) ->column('DISTINCT car_id'); if ($car_id){ $car_id = array_intersect($car_id,$ids); }else{ $car_id = $ids; } } } } return array_values(array_unique($car_id)); } }