// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\common\library\collector\provider\driver; use app\common\enum\goods\SpecType as GoodsSpecTypeEnum; use app\common\library\collector\provider\Driver; use cores\exception\BaseException; /** * 京东商品采集驱动 * Class Jd * @package app\common\library\collector\provider\driver */ class Jd extends Driver { // API地址 const API_URL = 'https://api09.99api.com/jd/detail'; /** * 获取商品详情 * @param string $itemId * @return array * @throws BaseException */ public function detail(string $itemId): array { $result = $this->curlGet(self::API_URL, $itemId); return $this->formatGoods($result['data']); } /** * 格式化商品数据 * @param array $original * @return array */ private function formatGoods(array $original): array { $data = []; // 商品规格 (SKU数量为1时是单规格,大于1是多规格) $data['spec_type'] = \count($original['item']['sku']) > 1 ? GoodsSpecTypeEnum::MULTI : GoodsSpecTypeEnum::SINGLE; $data['goods_name'] = $original['item']['name']; $data['goodsImages'] = $this->goodsImages($original['item']['images']); $data['content'] = $this->goodsContent($original['item']['descImgs']); // 商品价格 $price = $original['item']['price']; // 规格组封面图 $clothesColor = $original['item']['clothesColor'] ?? []; // 整理多规格数据 if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) { $skuProps = $this->skuProps($original['item']['skuProps']); $saleProp = $this->saleProp($original['item']['saleProp'], \count($skuProps)); $specList = $this->createSpecList($saleProp, $skuProps); $data['specData']['specList'] = $specList; $data['specData']['skuList'] = $this->createSkuList($original['item']['sku'], $specList, $price, $clothesColor); } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) { $data['goods_price'] = $price; $data['line_price'] = '0.00'; $data['stock_num'] = 100; // 库存默认100 $data['goods_weight'] = 1; // 重量默认1kg } return $data; } /** * 创建标准的商品SKU数据 * @param array $originalSkuList 商品SKU列表 * @param array $specList 商品规格 * @param string $price 商品价格 * @param array $clothesColor 规格组封面图 * @return array */ private function createSkuList(array $originalSkuList, array $specList, string $price, array $clothesColor): array { // 根据规格数据生成完整的SKU数据 (因为originalSkuList会有不存在的sku) $cartesian = $this->cartesian($specList); // 整理商品SKU列表 $skuList = []; foreach ($cartesian as $spec) { // 设置skuKeys数据 $skuKeys = []; foreach ($spec as $specValue) { $skuKeys[] = [ 'groupKey' => $specValue['groupKey'], 'valueKey' => $specValue['key'] ]; } // 查找已存在的SKU $originalSku = $this->findOriginalSku($originalSkuList, $spec); // 整理SKU数据 $skuList[] = [ 'image_id' => 0, 'goods_price' => $price, 'line_price' => '0.00', 'stock_num' => 100, // 库存默认100 'goods_weight' => 1, // 重量默认1kg 'goods_sku_no' => $originalSku ? $originalSku['skuId'] : '', 'skuKeys' => $skuKeys, 'imageUrl' => $this->findClothesColor($clothesColor, $spec), ]; } return $skuList; } /** * 查找SKU封面图 * @param array $clothesColor * @param array $spec * @return string */ private function findClothesColor(array $clothesColor, array $spec): string { foreach ($spec as $skuValue) { if ($skuValue['groupKey'] != 0) { continue; } foreach ($clothesColor as $item) { if ($skuValue['spec_value'] === $item['color']) { return $this->imageUrl($item['imagePath']); } } } return ''; } /** * 格式化图片url * @param string $url * @return string */ private function imageUrl(string $url): string { if (empty($url)) { return ''; } // 京东商品规格图不使用缩略图处理 if (\strpos($url, 's40x40_jfs')) { $url = str_replace('s40x40_jfs', 's750x750_jfs', $url); } // 补全url协议 if (\substr($url, 0, 2) === '//') { return "https:{$url}"; } if (\substr($url, 0, 4) != 'http') { return "https://{$url}"; } // http替换为https return str_replace('http://', 'https://', $url); } /** * 查找已存在的SKU * @param array $originalSkuList * @param array $spec * @return false|mixed */ private function findOriginalSku(array $originalSkuList, array $spec) { foreach ($originalSkuList as $item) { $temp = 0; foreach ($spec as $specValue) { if ($item[$specValue['groupKey'] + 1] == $specValue['spec_value']) { $temp++; } } if ($temp === \count($spec)) { return $item; } } return false; } /** * 生成完整的SKU列表(笛卡尔积运算) * @param array $specList * @param array $tmp * @param array $nArr * @return int */ private function cartesian(array $specList, array $tmp = [], array $nArr = []) { foreach (array_shift($specList)['valueList'] as $v) { $tmp[] = $v; if ($specList) { $nArr = $this->cartesian($specList, $tmp, $nArr); } else { $nArr[] = $tmp; } array_pop($tmp); } return $nArr; } /** * 创建标准的商品规格数据(树状) * @param array $saleProp 规格组 * @param array $skuProps 规格值 * @return array */ private function createSpecList(array $saleProp, array $skuProps): array { $specList = []; foreach ($saleProp as $specName) { $groupKey = \count($specList); $valueList = []; foreach ($skuProps[$groupKey] as $specValue) { $valueList[] = [ 'key' => \count($valueList), 'groupKey' => $groupKey, 'spec_value' => $specValue, ]; } $specList[] = [ 'key' => $groupKey, 'spec_name' => $specName, 'valueList' => $valueList, ]; } return $specList; } /** * 格式化商品规格组 * @param array $saleProp * @param int $count * @return array */ private function saleProp(array $saleProp, int $count): array { ksort($saleProp); return \array_slice($saleProp, 0, $count); } /** * 格式化规格值 * @param array $skuProps * @return array */ private function skuProps(array $skuProps): array { return \array_values(array_filter($skuProps, function ($item) { \is_array($item) && $item = \array_values(\array_filter($item)); return $item ?: null; })); } /** * 格式化商品主图 * @param array $images * @return array */ private function goodsImages(array $images): array { return array_map(function (string $imageUrl) { return $this->imageUrl($imageUrl); }, \array_slice($images, 0, 10)); } /** * 格式化商品详情 * @param array $descImgs * @return string */ private function goodsContent(array $descImgs): string { $content = ''; foreach ($descImgs as $img) { $content .= "
"; } return $content; } }