checkStatusFail($recordId)) { foreach ($urls as $url) { try { // 采集第三方商品数据 $original = $this->collector($url, $storeId); if ($original['spec_type'] == 20) { $original['spec_type'] = 10; $skuList = array_column($original['specData']['skuList'], null, "goods_sku_no"); $goods_price = $skuList[$original['goods_sku_no']]['goods_price'] ?? 0; $original['goods_price'] = $goods_price; $original['line_price'] = $goods_price; $original['data_type'] = 1; $original['link'] = $url; unset($original['specData']); } // 下载远程商品图片 $original = $this->thirdPartyImages($original, $form['imageStorage'], $storeId); } catch (\Throwable $e) { tre($e->getTraceAsString()); $this->errorLog[] = ['url' => trim($url), 'message' => $e->getMessage()]; continue; } // 生成商品数据(用于写入数据库) $data = $this->createData($original, $form, $storeId); // 事务处理:添加商品 $model = new GoodsModel(); $model->transaction(function () use ($model, $data, $storeId) { // 添加商品 $model->save($data); $model->where('goods_id', (int)$model['goods_id'])->update(['spu_id' => (int)$model['goods_id']]); // 新增商品与分类关联 GoodsCategoryRelModel::increased((int)$model['goods_id'], $data['categoryIds'], $storeId); // 新增商品与图片关联 GoodsImageModel::increased((int)$model['goods_id'], $data['imagesIds'], $storeId); // 新增商品与规格关联 GoodsSpecRelModel::increased((int)$model['goods_id'], $data['newSpecList'], $storeId); // 新增商品sku信息 GoodsSkuModel::add((int)$model['goods_id'], $data['spec_type'], $data['newSkuList'], $storeId); }); // 记录采集成功 $this->successCount++; } } // 更新采集记录 $this->updateRecord($recordId, \count($urls)); return true; } /** * 后台单个采集 * [single description] * @param string $url [description] * @param array $form [description] * @param int $storeId [description] * @return [type] [description] */ public function single1(string $url, array $form, int $storeId): bool { try { //var_dump($url); // 采集第三方商品数据 $original = $this->collector1($url, $storeId); if ($original['spec_type'] == 20) { $original['spec_type'] = 10; unset($original['specData']); } $original['goods_price'] = $form['goods_price'] ?? 0.00; $original['line_price'] = $form['goods_price'] ?? 0.00; $original['cost_price'] = $form['cost_price'] ?? 0.00; $original['stock_num'] = $form['stock_num'] ?? 0; $original['remark'] = $form['remark'] ?? ""; $original['cmmdty_model'] = $form['cmmdty_model'] ?? ""; $original['goods_no'] = $form['goods_no'] ?? ""; $original['region'] = $form['region'] ?? ""; $original['region_text'] = $form['region_text'] ?? ""; $original['delivery_time'] = $form['delivery_time'] ?? ""; $original['is_check'] = $form['is_check'] ?? 0; $original['goods_source'] = $form['goods_source'] ?? ""; $original['data_type'] = 1; $original['link'] = $url; // echo "
";
            // print_r($original);
            // exit();
            // 下载远程商品图片
            $original = $this->thirdPartyImages($original, $form['imageStorage'], $storeId);
        } catch (\Throwable $e) {
            // var_dump($e->getMessage());
            // exit;
            tre($e->getTraceAsString());
            $this->errorLog[] = ['url' => trim($url), 'message' => $e->getMessage()];
            return false;
        }
        // 生成商品数据(用于写入数据库)
        $data = $this->singleCreateData($original, $form, $storeId);
        // echo "
";
        // print_r($data);
        // exit();
        // 事务处理:添加商品
        $model = new GoodsModel();
        $model->transaction(function () use ($model, $data, $storeId) {
            // 添加商品
            $model->save($data);
            $model->where('goods_id', (int)$model['goods_id'])->update(['spu_id' => (int)$model['goods_id']]);
            // 新增商品与分类关联
            GoodsCategoryRelModel::increased((int)$model['goods_id'], $data['categoryIds'], $storeId);
            // 新增商品与图片关联
            GoodsImageModel::increased((int)$model['goods_id'], $data['imagesIds'], $storeId);
            // 新增商品与规格关联
            GoodsSpecRelModel::increased((int)$model['goods_id'], $data['newSpecList'], $storeId);
            // 新增商品sku信息
            GoodsSkuModel::add((int)$model['goods_id'], $data['spec_type'], $data['newSkuList'], $storeId);
        });
           
        return true;
    }
    /**
     * 后台单个采集
     * [single description]
     * @param  string $url     [description]
     * @param  array  $form    [description]
     * @param  int    $storeId [description]
     * @return [type]          [description]
     */
    public function single(string $url, array $form, int $storeId): bool
    {
        if (!$url) {
            return true;
        }
        try {
            //var_dump($url);
            // 采集第三方商品数据
            $original = $this->collector($url, $storeId);
            if ($original['spec_type'] == 20) {
                $original['spec_type'] = 10;
                if (isset($original['specData'])) {
                    unset($original['specData']);
                }
                
            }
            $original['goods_price'] = $form['goods_price'] ?? 0.00;
            $original['line_price'] = $form['goods_price'] ?? 0.00;
            $original['cost_price'] = $form['cost_price'] ?? 0.00;
            $original['stock_num'] = $form['stock_num'] ?? 0;
            $original['remark'] = $form['remark'] ?? "";
            $original['cmmdty_model'] = $form['cmmdty_model'] ?? "";
            $original['goods_no'] = $form['goods_no'] ?? "";
            $original['region'] = $form['region'] ?? "";
            $original['region_text'] = $form['region_text'] ?? "";
            $original['delivery_time'] = $form['delivery_time'] ?? 2;
            $original['is_check'] = $form['is_check'] ?? 0;
            $original['is_use_jd_stock'] = $form['is_use_jd_stock'] ?? 0;
            $original['goods_source'] = $form['goods_source'] ?? "GC";
            $original['data_type'] = 1;
            $original['link'] = $url;
            // echo "
";
            // print_r($original);
            // exit();
            // 下载远程商品图片
            $original = $this->thirdPartyImages($original, $form['imageStorage'], $storeId);
        } catch (\Throwable $e) {
            // var_dump($e->getMessage());
            // exit;
            tre($e->getTraceAsString());
            $this->errorLog[] = ['url' => trim($url), 'message' => $e->getMessage()];
            return false;
        }
        // 生成商品数据(用于写入数据库)
        $data = $this->singleCreateData($original, $form, $storeId);
        // echo "
";
        // print_r($data);
        // exit();
        // 事务处理:添加商品
        $model = new GoodsModel();
        $model->transaction(function () use ($model, $data, $storeId) {
            // 添加商品
            $model->save($data);
            $model->where('goods_id', (int)$model['goods_id'])->update(['spu_id' => (int)$model['goods_id']]);
            // 新增商品与分类关联
            GoodsCategoryRelModel::increased((int)$model['goods_id'], $data['categoryIds'], $storeId);
            // 新增商品与图片关联
            GoodsImageModel::increased((int)$model['goods_id'], $data['imagesIds'], $storeId);
            // 新增商品与规格关联
            GoodsSpecRelModel::increased((int)$model['goods_id'], $data['newSpecList'], $storeId);
            // 新增商品sku信息
            GoodsSkuModel::add((int)$model['goods_id'], $data['spec_type'], $data['newSkuList'], $storeId);
        });
           
        return true;
    }
    /**
     * 后台单个采集
     * [single description]
     * @param  string $url     [description]
     * @param  array  $form    [description]
     * @param  int    $storeId [description]
     * @return [type]          [description]
     */
    public function updateGoods(string $url, array $form, int $storeId): bool
    {
        $goods = GoodsModel::where('goods_id', $form['goods_id'])->find();

        //商品不存在
        if (!$goods || !$url) {
            return true;
        }
        //新阙通信的抓取过了,就不抓取了;京东价拖抓取过了就不抓取了
        if (isset($form['is_cover']) && $form['is_cover'] == 0) {
            if (($goods['channel'] == 'xqtx' && $goods['content']) || $goods->goods_no_other) {
                return true;
            }
        }
        
        try {

            // 采集第三方商品数据
            $original = $this->collector($url, $storeId);
            // echo "
";
            // print_r($original);
            // exit();

            if ($original['spec_type'] == 20) {
                $original['spec_type'] = 10;
                //兼容99api和lt数据源
                if (isset($original['specData'])) {
                    $skuList = array_column($original['specData']['skuList'], null, "goods_sku_no");
                    $goods_price = $skuList[$original['goods_sku_no']]['goods_price'] ?? 0;
                    unset($original['specData']);
                } else{
                    $goods_price = $original['goods_price'];
                }
                
                $original['goods_price'] = $goods_price;
                $original['line_price'] = $goods_price;
                $original['data_type'] = 1;//苏宁的数据变成的人工数据了,不再使用苏宁接口更新数据
                $original['link_other'] = $url;
                
                
            }
            $form['imageStorage'] = 20;

            // 下载远程商品图片
            $original = $this->thirdPartyImages($original, $form['imageStorage'], $storeId);
        } catch (\Throwable $e) {
            // var_dump($e->getMessage());
            // exit;
            tre($e->getTraceAsString());
            $this->errorLog[] = ['url' => trim($url), 'message' => $e->getMessage()];
            return false;
        }
        // if ($original['goods_price'] == 0) {
        //     return false;
        // }

        $original['cost_price'] = $form['cost_price_min'];
        $data['link_other'] = $url;
        
        
        $data['content'] = $original['content'];

        //重新计算利润和利润率
        $data['goods_source'] = $form['goods_source'];
        $data['cmmdty_model'] = $form['cmmdty_model'];
        $data['delivery_time'] = $form['delivery_time'];
        $data['is_check'] = $form['is_check'];
        $data['is_use_jd_stock'] = $form['is_use_jd_stock'];
        $data['goods_price_min'] = $original['goods_price'];
        $data['goods_price_max'] = $original['goods_price'];
        $data['line_price_min'] = $original['goods_price'];
        $data['line_price_max'] = $original['goods_price'];
        $data['profit'] = $original['goods_price'] - $original['cost_price'];
        $profit_rate = (float)$original['goods_price'] > 0 ? ($original['goods_price'] - $original['cost_price']) / $original['goods_price'] : 0.00;
        $profit_rate = $profit_rate > 0.0001 ? bcmul((string)$profit_rate, "100", 2) : 0.00;
        $data['profit_rate'] = $profit_rate;

        // echo "
";
        // print_r($data);
        // exit();
        // 事务处理:添加商品
        $model = new GoodsModel();
        
        $goodsSku = [
            'goods_price' => $original['goods_price'], 
            'goods_sku_no' => $original['goods_sku_no'],
        ];
        //新阙通信的数据
        if ($goods->channel == "xqtx") {
            $data['goods_no'] = $original['goods_sku_no'];
            //goods
            $data['stock_total'] = $form['stock_total'];
            $data['goods_name'] = $original['goods_name'];

            //设置当前商品价格
            $data['profit'] = $original['goods_price'] - $original['cost_price'];
            $profit_rate = (float)$original['goods_price'] > 0 ? ($original['goods_price'] - $original['cost_price']) / $original['goods_price'] : 0.00;
            $profit_rate = $profit_rate > 0.0001 ? bcmul((string)$profit_rate, "100", 2) : 0.00;
            $data['profit_rate'] = $profit_rate;
            $data['link'] = $data['link_other'];
            unset($data['link_other']);

            //sku
            $goodsSku['stock_num'] = $form['stock_total'];
            //unset($goodsSku['goods_price']);
        } else {
            //京东价拖
            $data['goods_no_other'] = $original['goods_sku_no'];
        }
        // var_dump($data);
        // var_dump($goodsSku);
        // exit();
        $model->transaction(function () use ($form, $data, $original, $goodsSku) {
            $data['update_time'] = time();
            // 添加商品
            GoodsModel::where('goods_id', $form['goods_id'])->update($data);
            // 新增商品与图片关联
            GoodsImageModel1::updates((int)$form['goods_id'], $original['imagesIds']);
            //更新sku信息
            GoodsSkuModel::where('goods_id', $form['goods_id'])->update($goodsSku);
        });
           
        return true;
    }
    /**
     * 检查采集记录状态是否异常
     * @param int $recordId
     * @return bool
     */
    private function checkStatusFail(int $recordId): bool
    {
        $model = $this->getRecord($recordId);
        return $model['status'] == GoodsCollectorStatusEnum::FAIL || $model['is_delete'];
    }
    /**
     * 抓取第三方商品内容-lt数据源
     * @param string $url
     * @param int $storeId
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function collector1(string $url, int $storeId): array
    {
        // 获取商品来源
        $store = $this->getStore($url);
        // 获取url中的商品ID
        $itemId = $this->getItemId($url, $store);
        $res = getJdGoodsBySku([$itemId]);
        $item = $res[$itemId] ?? [];
        $item['spec_type'] = 20;//设置默认走多规格的逻辑
        $item['goodsImages'] = $item['mainImages'];
        $item['goods_price'] = $item['proxyPrice'];
        $item['goods_name'] = $item['name'];
        $item['imageStorage'] = 10;

        // echo "
";
        // print_r($item);
        // exit();
        $item['goods_sku_no'] = $itemId;
        return $item;
    }
    /**
     * 抓取第三方商品内容-99api数据源
     * @param string $url
     * @param int $storeId
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function collector(string $url, int $storeId): array
    {
        // 获取商品来源
        $store = $this->getStore($url);
        // 获取url中的商品ID
        $itemId = $this->getItemId($url, $store);
        // 商城采集设置
        $config = SettingModel::getItem(SettingEnum::COLLECTOR, $storeId);
        // 请求API查询商品详情
        $item = CollectorFacade::store($store)
            ->setOptions($config['config'][$config['provider']])
            ->detail($itemId);

        $item['goods_sku_no'] = $itemId;
        return $item;
    }

    /**
     * 根据url获取商品来源
     * @param string $url
     * @return string
     * @throws BaseException
     */
    private function getStore(string $url): string
    {
        $UrlStore = new UrlStore($url);
        if (!$store = $UrlStore->getStore()) {
            throwError('不支持该网址的采集,请检查url是否正确');
        }
        return $store;
    }

    /**
     * 获取url中的商品ID
     * @param string $url
     * @param string $store
     * @return string
     * @throws BaseException
     */
    private function getItemId(string $url, string $store): string
    {
        $UrlItemId = new UrlItemId($url, $store);
        if (!$itemId = $UrlItemId->getItemId()) {
            throwError('未能获取到商品ID,请检查url是否正确');
        }
        return $itemId;
    }

    /**
     * 更新采集记录
     * @param int $recordId 商品采集记录ID
     * @param int $currentCount 当前任务采集的商品总量
     * @return void
     */
    private function updateRecord(int $recordId, int $currentCount)
    {
        // 获取采集记录
        $model = $this->getRecord($recordId);
        // 计算采集失败的数量
        $failCount = $currentCount - $this->successCount;
        // 更新采集记录
        $model->save([
            'success_count' => $model['success_count'] + $this->successCount,
            'fail_count' => $model['fail_count'] + $failCount,
            'fail_log' => array_merge($model['fail_log'], $this->errorLog),
        ]);
        // 判断是否为最后一次队列
        if ($model['total_count'] <= ($model['success_count'] + $model['fail_count'])) {
            $model->save(['end_time' => \time(), 'status' => GoodsCollectorStatusEnum::COMPLETED]);
        }
    }

    /**
     * 获取采集记录
     * @param int $recordId 商品采集记录ID
     * @return GoodsCollectorModel|array|null
     */
    private function getRecord(int $recordId)
    {
        if (!$this->record) {
            $this->record = GoodsCollectorModel::detail($recordId);
        }
        return $this->record;
    }
    /**
     * 生成商品数据(用于写入数据库)
     * @param array $original 商品原始数据
     * @param array $form 用户提交的表单
     * @param int $storeId 当前商城id
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function singleCreateData(array $original, array $form, int $storeId): array
    {
        // 整理商品数据
        $data = [
            'goods_type' => $form['goods_type'],
            'delivery_id' => $form['delivery_id'] ?? 0,
            'goods_name' => $original['goods_name'],
            'goods_no' => $original['goods_sku_no'] ?? "",
            'is_check' => $original['is_check'] ?? 0,
            'is_use_jd_stock' => $original['is_use_jd_stock'] ?? 0,
            'delivery_time' => $original['delivery_time'] ?? 0,
            'goods_source' => $original['goods_source'] ?? "",
            'data_type' => $original['data_type'],//数据类型
            'link' => $original['link'],//采集地址
            'spec_type' => $original['spec_type'],
            'delivery_id' => $form['delivery_id'] ?? 0,
            'content' => $original['content'] ?? '',
            'sort' => 100,
            'deduct_stock_type' => DeductStockTypeEnum::CREATE,
            'status' => $form['goods_status'],
            'imagesIds' => $original['imagesIds'],
            'categoryIds' => $form['categoryIds'],
            // 下面是默认数据, 没有会报错
            'alone_grade_equity' => [],
            'newSpecList' => [],
            'newSkuList' => [],
            'store_id' => $storeId,
            'merchant_id' => $form['merchant_id'] ?? 0,
        ];
        if (isset($form['channel'])) {
            $data['channel'] = $form['channel'];
        }
        $data['unicode'] = $data['channel']."-0-".$original['goods_sku_no'];
        // 整理商品的价格和库存总量
        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
            $data['stock_total'] = GoodsSkuModel::getStockTotal($original['specData']['skuList']);
            [$data['goods_price_min'], $data['goods_price_max']] = GoodsSkuModel::getGoodsPrices($original['specData']['skuList']);
            [$data['line_price_min'], $data['line_price_max']] = GoodsSkuModel::getLinePrices($original['specData']['skuList']);
        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
            $data['goods_price_min'] = $data['goods_price_max'] = $original['goods_price'];
            $data['line_price_min'] = $data['line_price_max'] = $original['goods_price'];
            $data['cost_price_min'] = $original['cost_price'] ?? 0.00;
            $data['profit'] = (float)$original['goods_price'] - (float)$original['cost_price'];
            $profit_rate = (float)$original['goods_price'] > 0 ? ((float)$original['goods_price'] - (float)$original['cost_price']) / (float)$original['goods_price'] : 0.00;
            $profit_rate = $profit_rate > 0.0001 ? bcmul((string)$profit_rate, "100", 2) : 0.00;
            $data['profit_rate'] = $profit_rate;
            
            $data['stock_total'] = $original['stock_num'];
            $data['remark'] = $original['remark'] ?? "";
            $data['cmmdty_model'] = $original['cmmdty_model'] ?? "";
            $data['goods_no'] = $original['goods_no'] ?? "";
            $data['region'] = $original['region'] ?? "";
            $data['region_text'] = $original['region_text'] ?? "";
        }
        // 规格和sku数据处理
        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
            // 验证规格值是否合法
            SpecModel::checkSpecData($original['specData']['specList']);
            // 生成多规格数据 (携带id)
            $data['newSpecList'] = SpecModel::getNewSpecList($original['specData']['specList'], $storeId);
            // 生成skuList (携带goods_sku_id)
            $data['newSkuList'] = GoodsSkuModel::getNewSkuList($data['newSpecList'], $original['specData']['skuList']);
        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
            // 生成skuItem
            $data['newSkuList'] = helper::pick($original, ['goods_sku_no','goods_price', 'line_price', 'cost_price','stock_num', 'goods_weight']);
        }
        return $data;
    }
    /**
     * 生成商品数据(用于写入数据库)
     * @param array $original 商品原始数据
     * @param array $form 用户提交的表单
     * @param int $storeId 当前商城id
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function createData(array $original, array $form, int $storeId): array
    {
        // 整理商品数据
        $data = [
            'goods_type' => $form['goods_type'],
            'goods_name' => $original['goods_name'],
            'goods_no' => $original['goods_sku_no'] ?? "",
            'data_type' => $original['data_type'],//数据类型
            'link' => $original['link'],//采集地址
            'spec_type' => $original['spec_type'],
            'delivery_id' => $form['delivery_id'] ?? 0,
            'content' => $original['content'] ?? '',
            'sort' => 100,
            'deduct_stock_type' => DeductStockTypeEnum::CREATE,
            'status' => $form['goods_status'],
            'imagesIds' => $original['imagesIds'],
            'categoryIds' => $form['categoryIds'],
            // 下面是默认数据, 没有会报错
            'alone_grade_equity' => [],
            'newSpecList' => [],
            'newSkuList' => [],
            'store_id' => $storeId,
            'merchant_id' => $form['merchant_id'] ?? 0,
        ];
        if (isset($form['channel'])) {
            $data['channel'] = $form['channel'];
        }
        // 整理商品的价格和库存总量
        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
            $data['stock_total'] = GoodsSkuModel::getStockTotal($original['specData']['skuList']);
            [$data['goods_price_min'], $data['goods_price_max']] = GoodsSkuModel::getGoodsPrices($original['specData']['skuList']);
            [$data['line_price_min'], $data['line_price_max']] = GoodsSkuModel::getLinePrices($original['specData']['skuList']);
        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
            $data['goods_price_min'] = $data['goods_price_max'] = $original['goods_price'];
            $data['line_price_min'] = $data['line_price_max'] = $original['line_price'];
            $data['line_price_min'] = $data['line_price_max'] = $original['line_price'];
            $data['stock_total'] = $original['stock_num'] ?? 100;
        }
        // 规格和sku数据处理
        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
            // 验证规格值是否合法
            SpecModel::checkSpecData($original['specData']['specList']);
            // 生成多规格数据 (携带id)
            $data['newSpecList'] = SpecModel::getNewSpecList($original['specData']['specList'], $storeId);
            // 生成skuList (携带goods_sku_id)
            $data['newSkuList'] = GoodsSkuModel::getNewSkuList($data['newSpecList'], $original['specData']['skuList']);
        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
            // 生成skuItem
            $data['newSkuList'] = helper::pick($original, ['goods_sku_no','goods_price', 'line_price', 'stock_num', 'goods_weight']);
        }
        return $data;
    }

    /**
     * 下载远程商品图片
     * @param array $original 商品信息
     * @param int $imageStorage 商品主图 (10下载到本地、20使用源图片url)
     * @param int $storeId
     * @return array
     * @throws BaseException
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function thirdPartyImages(array $original, int $imageStorage, int $storeId): array
    {
        // 保存商品主图
        $original['imagesIds'] = [];
        foreach ($original['goodsImages'] as $imageUrl) {
            $original['imagesIds'][] = $imageStorage === 10 ? $this->downImage($imageUrl, $storeId)
                : $this->externalImage($imageUrl, $storeId);
        }
        // 保存商品SKU封面图
        if ($original['spec_type'] === GoodsSpecTypeEnum::MULTI) {
            foreach ($original['specData']['skuList'] as &$skuItem) {
                if (!empty($skuItem['imageUrl'])) {
                    $skuItem['image_id'] = $imageStorage === 10 ? $this->downImage($skuItem['imageUrl'], $storeId)
                        : $this->externalImage($skuItem['imageUrl'], $storeId);
                }
            }
        }
        return $original;
    }

    /**
     * 将远程图片外链保存到文件库中
     * @param string $imageUrl 远程图片url
     * @param int $storeId
     * @return mixed
     * @throws BaseException
     */
    private function externalImage(string $imageUrl, int $storeId)
    {
        // 如果已存在该文件则直接返回文件ID
        if (isset($this->dictImageUrls[$imageUrl])) {
            return $this->dictImageUrls[$imageUrl];
        }
        // 文件外链记录到文件库
        $UploadService = (new UploadService)->setStoreId($storeId);
        if (!$UploadService->uploadByExternal(FileTypeEnum::IMAGE, $imageUrl)) {
            throwError('图片记录失败:' . $UploadService->getError());
        }
        // 记录文件ID
        $fileId = $UploadService->getFileInfo()['file_id'];
        $this->dictImageUrls[$imageUrl] = $fileId;
        return $fileId;
    }

    /**
     * 将远程图片下载并保存到文件库中
     * @param string $imageUrl 远程图片url
     * @param int $storeId
     * @return mixed
     * @throws BaseException
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function downImage(string $imageUrl, int $storeId)
    {
        // 如果已存在该文件则直接返回文件ID
        if (isset($this->dictImageUrls[$imageUrl])) {
            return $this->dictImageUrls[$imageUrl];
        }
        // 下载远程图片
        $filePath = (new Download)->saveTempImage($storeId, $imageUrl);
        // 文件上传到文件库
        $UploadService = (new UploadService)->setStoreId($storeId);
        if (!$UploadService->uploadByLocal(FileTypeEnum::IMAGE, $filePath)) {
            throwError('图片上传失败:' . $UploadService->getError());
        }
        // 记录文件ID
        $fileId = $UploadService->getFileInfo()['file_id'];
        $this->dictImageUrls[$imageUrl] = $fileId;
        return $fileId;
    }
}