You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
8.9 KiB
281 lines
8.9 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
|
|
// +----------------------------------------------------------------------
|
|
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
|
|
// +----------------------------------------------------------------------
|
|
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
|
|
// +----------------------------------------------------------------------
|
|
// | Author: 萤火科技 <admin@yiovo.com>
|
|
// +----------------------------------------------------------------------
|
|
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 .= "<p><img src=\"{$img}\"/></p>";
|
|
}
|
|
return $content;
|
|
}
|
|
} |