From 2638e94d1afe157fd4e3a539038c46ae4e3c9354 Mon Sep 17 00:00:00 2001 From: lqmac Date: Tue, 5 Mar 2024 09:30:48 +0800 Subject: [PATCH 1/3] 1 --- app/admin/controller/Category.php | 88 ++++++ app/admin/controller/goods/Import.php | 71 +++++ app/api/service/Goods.php | 46 ++- app/common/model/Category.php | 1 + app/job/controller/goods/AdminImport.php | 49 ++++ app/job/service/goods/AdminImport.php | 358 +++++++++++++++++++++++ app/store/model/Category.php | 2 +- app/store/model/goods/Import.php | 83 +++++- 8 files changed, 693 insertions(+), 5 deletions(-) create mode 100644 app/admin/controller/Category.php create mode 100644 app/admin/controller/goods/Import.php create mode 100644 app/job/controller/goods/AdminImport.php create mode 100644 app/job/service/goods/AdminImport.php diff --git a/app/admin/controller/Category.php b/app/admin/controller/Category.php new file mode 100644 index 00000000..f652e730 --- /dev/null +++ b/app/admin/controller/Category.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\admin\controller; + +use think\response\Json; +use app\store\model\Category as CategoryModel; + +/** + * 商品分类 + * Class Category + * @package app\store\controller\goods + */ +class Category extends Controller +{ + /** + * 商品分类列表 + * @return Json + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function list(): Json + { + $model = new CategoryModel; + $list = $model->getList(['store_id' =>0]); + return $this->renderSuccess(compact('list')); + } + + /** + * 删除商品分类 + * @param int $categoryId + * @return Json + */ + public function delete(int $categoryId): Json + { + // 分类详情 + $model = CategoryModel::detail($categoryId); + if (!$model->remove()) { + return $this->renderError($model->getError() ?: '删除失败'); + } + return $this->renderSuccess('删除成功'); + } + + /** + * 添加商品分类 + * @return Json + */ + public function add(): Json + { + // 新增记录 + $model = new CategoryModel; + $params = $this->postForm(); + $params['store_id'] = 0; + if ($model->add($params)) { + return $this->renderSuccess('添加成功'); + } + return $this->renderError($model->getError() ?: '添加失败'); + } + + /** + * 编辑商品分类 + * @param int $categoryId + * @return Json + * @throws \think\db\exception\DataNotFoundException + * @throws \think\db\exception\DbException + * @throws \think\db\exception\ModelNotFoundException + */ + public function edit(int $categoryId): Json + { + // 分类详情 + $model = CategoryModel::detail($categoryId, ['image']); + // 更新记录 + if ($model->edit($this->postForm())) { + return $this->renderSuccess('更新成功'); + } + return $this->renderError($model->getError() ?: '更新失败'); + } +} diff --git a/app/admin/controller/goods/Import.php b/app/admin/controller/goods/Import.php new file mode 100644 index 00000000..c338b42f --- /dev/null +++ b/app/admin/controller/goods/Import.php @@ -0,0 +1,71 @@ + +// +---------------------------------------------------------------------- +declare (strict_types=1); + +namespace app\admin\controller\goods; + +use think\response\Json; +use app\admin\controller\Controller; +use app\store\model\goods\Import as ImportModel; +use cores\exception\BaseException; + +/** + * 商品批量导入管理 + * Class Import + * @package app\store\controller\goods + */ +class Import extends Controller +{ + /** + * 获取列表记录 + * @return Json + * @throws \think\db\exception\DbException + */ + public function list(): Json + { + $params = $this->request->param(); + $params['store_id'] = 0; + $model = new ImportModel; + $list = $model->getList($params); + return $this->renderSuccess(compact('list')); + } + + /** + * 执行批量导入 + * @return Json + * @throws BaseException + * @throws \PhpOffice\PhpSpreadsheet\Exception + * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception + */ + public function batch(): Json + { + // 新增记录 + $model = new ImportModel; + if ($model->adminBatch($this->postData())) { + return $this->renderSuccess('已添加到导入任务中,请在历史导入记录中查看结果'); + } + return $this->renderError($model->getError() ?: '操作失败'); + } + + /** + * 删除记录 + * @param int $id + * @return Json + */ + public function delete(int $id): Json + { + $model = ImportModel::detail($id); + if (!$model->setDelete()) { + return $this->renderError($model->getError() ?: '删除失败'); + } + return $this->renderSuccess('删除成功'); + } +} diff --git a/app/api/service/Goods.php b/app/api/service/Goods.php index 00753a70..8746e856 100644 --- a/app/api/service/Goods.php +++ b/app/api/service/Goods.php @@ -137,8 +137,10 @@ class Goods extends GoodsService return []; } $list = $goodsList->toArray(); - - $list['data'] = $this->formatGoodsList($goodsList); + // echo "
";
+        // print_r($list);
+        // exit()
+        $list['data'] = $this->newFormatGoodsList($list['data']);
         return $list;
 
     }
@@ -317,6 +319,46 @@ class Goods extends GoodsService
         }
         return $price;
     }
+    /**
+     * 格式化商品列表
+     * @param $goodsList
+     * @return array
+     */
+    private function newFormatGoodsList($goodsList): array
+    {
+       
+        $data = [];
+        foreach ($goodsList as $goods) {
+            $temp = [
+                'goods_id' => $goods['goods_id'],
+                'goods_name' => $goods['goods_name'],
+                'selling_point' => $goods['selling_point'],
+                'goods_image' => $goods['goods_image'],
+                'goods_price_min' => $goods['goods_price_min'],//商品价格
+                'goods_price_max' => $goods['goods_price_max'],
+                'line_price_min' => $goods['goods_price_min'],//划线价格等于市场价
+                'line_price_max' => $goods['line_price_max'],
+                'goods_sales' => $goods['goods_sales'],
+                'remaizhishu' => $goods['remaizhishu'],
+            ];
+            
+            if (UserService::isLogin()) {
+                $catService = new \app\store\model\GoodsCategoryRel();
+                $catIds = $catService->where(['goods_id' => $goods['goods_id']])->column('category_id');
+                //价格判断
+                if (UserService::isstore()) {
+                    $temp['goods_price_min'] = $goods['cost_price_min'];
+                } elseif (UserService::isPlusMember()) {
+                   $temp['goods_price_min'] = \app\common\model\PriceSet::membershipPrice($goods['goods_price_min'], $goods['cost_price_min'], $catIds);
+                } elseif (UserService::isDealerMember()) {
+                    $priceArr = \app\common\model\PriceSet::distributionPrice($goods['goods_price_min'], $goods['cost_price_min'], $catIds);
+                    $temp['goods_price_min'] = $priceArr['goods_price_min_dealer'];
+                }
+            }
+            $data[] = $temp;
+        }
+        return $data;
+    }
     /**
      * 格式化商品列表
      * @param $goodsList
diff --git a/app/common/model/Category.php b/app/common/model/Category.php
index cefeeff2..bd49e997 100644
--- a/app/common/model/Category.php
+++ b/app/common/model/Category.php
@@ -94,6 +94,7 @@ class Category extends BaseModel
         if (isset($param['is_in_store']) && $param['is_in_store'] != "") {
             $filter[] = ['is_in_store', '=', $params['is_in_store'] ?? 0];
         }
+        isset($params['store_id']) && $params['store_id'] > -1 && $filter[] = ['store_id', '=', (int)$params['store_id']];
 
         // 查询列表数据
         return $this->with(['image'])
diff --git a/app/job/controller/goods/AdminImport.php b/app/job/controller/goods/AdminImport.php
new file mode 100644
index 00000000..8a77bd0f
--- /dev/null
+++ b/app/job/controller/goods/AdminImport.php
@@ -0,0 +1,49 @@
+
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\job\controller\goods;
+
+use app\job\service\goods\AdminImport as GoodsAdminImportService;
+use cores\BaseJob;
+use cores\traits\QueueTrait;
+use cores\exception\BaseException;
+use think\db\exception\DataNotFoundException;
+use think\db\exception\DbException;
+use think\db\exception\ModelNotFoundException;
+
+/**
+ * 队列任务:商品批量导入
+ * Class Import
+ * @package app\job\controller
+ */
+class AdminImport extends BaseJob
+{
+    use QueueTrait;
+
+    /**
+     * 消费队列任务:商品导入
+     * @param array $data 参数 [index队列顺序;totalCount商品总数量;list商品列表;storeId商城ID]
+     * @return bool 返回结果
+     * @throws BaseException
+     * @throws DataNotFoundException
+     * @throws DbException
+     * @throws ModelNotFoundException
+     */
+    public function handle(array $data): bool
+    {
+        $time = date('H:i:s');
+        echo "\n  ---- Import ----  {$time} ----   \n";
+
+        $service = new GoodsAdminImportService;
+        return $service->batch($data['list'], $data['recordId'], $data['storeId']);
+    }
+}
\ No newline at end of file
diff --git a/app/job/service/goods/AdminImport.php b/app/job/service/goods/AdminImport.php
new file mode 100644
index 00000000..67806a23
--- /dev/null
+++ b/app/job/service/goods/AdminImport.php
@@ -0,0 +1,358 @@
+
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\job\service\goods;
+
+use app\common\library\helper;
+use app\common\service\BaseService;
+use app\common\model\Spec as SpecModel;
+use app\common\model\Goods as GoodsModel;
+use app\common\model\Category as CategoryModel;
+use app\common\model\GoodsSku as GoodsSkuModel;
+use app\common\model\Delivery as DeliveryModel;
+use app\common\model\UploadFile as UploadFileModel;
+use app\common\model\GoodsImage as GoodsImageModel;
+use app\common\model\goods\Import as GoodsImportModel;
+use app\common\model\GoodsSpecRel as GoodsSpecRelModel;
+use app\common\model\goods\Service as GoodsServiceModel;
+use app\common\model\goods\ServiceRel as GoodsServiceRelModel;
+use app\common\model\GoodsCategoryRel as GoodsCategoryRelModel;
+use app\common\enum\goods\Status as GoodsStatusEnum;
+use app\common\enum\goods\GoodsType as GoodsTypeEnum;
+use app\common\enum\goods\SpecType as GoodsSpecTypeEnum;
+use app\common\enum\goods\ImportStatus as GoodsImportStatusEnum;
+use app\common\enum\goods\DeductStockType as DeductStockTypeEnum;
+use app\common\validate\goods\Import as GoodsImportValidate;
+use cores\exception\BaseException;
+
+/**
+ * 服务类:商品批量导入
+ * Class Import
+ * @package app\job\service\goods
+ */
+class AdminImport extends BaseService
+{
+    /**
+     * 错误日志记录
+     * @var array
+     */
+    private array $errorLog = [];
+
+    /**
+     * 导入成功的数量
+     * @var int
+     */
+    private int $successCount = 0;
+
+    /**
+     * 商品主信息字段映射
+     * @var string[]
+     */
+    private array $mapGoods = [
+        'goods_name' => 'B',
+        'goods_no' => 'C',
+        'categoryIds' => 'D',
+        'imagesIds' => 'E',
+        'delivery_id' => 'F',
+        'status' => 'G',
+        'sort' => 'N',
+        'deduct_stock_type' => 'O',
+        'sales_initial' => 'P',
+        'serviceIds' => 'Q',
+        'is_points_gift' => 'R',
+        'is_points_discount' => 'S',
+        'is_enable_grade' => 'T',
+    ];
+
+    /**
+     * 商品SKU字段映射
+     * @var string[]
+     */
+    private array $mapSku = [
+        'specText' => 'H',
+        'goods_price' => 'I',
+        'line_price' => 'J',
+        'stock_num' => 'K',
+        'goods_weight' => 'L',
+        'goods_sku_no' => 'M',
+    ];
+
+    /**
+     * 批量导入商品
+     * @param array $list
+     * @param int $recordId
+     * @param int $storeId
+     * @return bool
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function batch(array $list, int $recordId, int $storeId): bool
+    {
+        foreach ($list as $item) {
+            // 生成商品数据(用于写入数据库)
+            $data = $this->createData($item, $storeId);
+            // 数据验证
+            if (!$this->validateGoodsData($data, $storeId)) {
+                $this->errorLog[] = ['goodsSn' => $item['A'], 'message' => $this->getError()];
+                continue;
+            }
+            // 事务处理:添加商品
+            $model = new GoodsModel();
+            $model->transaction(function () use ($model, $data, $storeId) {
+                // 添加商品
+                $model->save($data);
+                // 新增商品与分类关联
+                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);
+                // 新增服务与承诺关联
+                GoodsServiceRelModel::increased((int)$model['goods_id'], $data['serviceIds'], $storeId);
+            });
+            // 记录导入成功
+            $this->successCount++;
+        }
+        // 更新导入记录
+        $this->updateRecord($recordId, \count($list));
+        return true;
+    }
+
+    /**
+     * 更新导入记录
+     * @param int $recordId 商品导入记录ID
+     * @param int $currentCount 当前任务导入的商品总量
+     * @return void
+     */
+    private function updateRecord(int $recordId, int $currentCount)
+    {
+        // 获取导入记录
+        $model = GoodsImportModel::detail($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' => GoodsImportStatusEnum::COMPLETED]);
+        }
+    }
+
+    /**
+     * 商品数据验证
+     * @param array $data
+     * @param int $storeId
+     * @return bool
+     */
+    private function validateGoodsData(array $data, int $storeId): bool
+    {
+        // 验证商品信息:商品名称、分类ID集、图片ID集、运费模板ID
+        $validate = new GoodsImportValidate;
+        if (!$validate->scene('goods')->check($data)) {
+            $this->setError($validate->getError());
+            return false;
+        }
+        // 验证SKU信息:商品价格、库存数量、商品重量
+        $skuList = $data['spec_type'] == GoodsSpecTypeEnum::MULTI ? $data['newSkuList'] : [$data['newSkuList']];
+        foreach ($skuList as $item) {
+            $validate = new GoodsImportValidate;
+            if (!$validate->scene('skuInfo')->check($item)) {
+                $this->setError($validate->getError());
+                return false;
+            }
+        }
+        // 验证运费模板ID是否存在
+        if (!DeliveryModel::checkDeliveryId((int)$data['delivery_id'], $storeId)) {
+            $this->setError('运费模板ID不存在');
+            return false;
+        }
+        if ($data['spec_type'] == GoodsSpecTypeEnum::MULTI) {
+            // 判断用户填写的SKU数量是否正确
+            $shouldSkuTotal = SpecModel::calcSkuListTotal($data['specData']['specList']);
+            $originalSkuTotal = \count($data['specData']['skuList']);
+            if ($shouldSkuTotal !== $originalSkuTotal) {
+                $this->setError('商品SKU数量不正确');
+                return false;
+            }
+            // 判断商品SKU是否存在重复规格
+            $goodsSkuIdArr = helper::getArrayColumn($data['newSkuList'], 'goods_sku_id');
+            if (count($data['newSkuList']) != count(array_unique($goodsSkuIdArr))) {
+                $this->setError('商品SKU存在重复的规格值');
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 生成商品数据(用于写入数据库)
+     * @param array $original
+     * @param int $storeId
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    private function createData(array $original, int $storeId): array
+    {
+        // 商品规格
+        $specType = isset($original['skuList']) ? GoodsSpecTypeEnum::MULTI : GoodsSpecTypeEnum::SINGLE;
+        // 整理商品数据
+        $data = [
+            'goods_type' => GoodsTypeEnum::PHYSICAL,
+            'goods_name' => $original[$this->mapGoods['goods_name']],
+            'goods_no' => $original[$this->mapGoods['goods_no']],
+            'spec_type' => $specType,
+            'delivery_id' => $original[$this->mapGoods['delivery_id']],
+            'sort' => $original[$this->mapGoods['sort']],
+            'sales_initial' => $original[$this->mapGoods['sales_initial']],
+            'deduct_stock_type' => $original[$this->mapGoods['deduct_stock_type']] === '付款减库存' ? DeductStockTypeEnum::PAYMENT
+                : DeductStockTypeEnum::CREATE,
+            'is_points_gift' => $original[$this->mapGoods['is_points_gift']] === '关闭' ? 0 : 1,
+            'is_points_discount' => $original[$this->mapGoods['is_points_discount']] === '关闭' ? 0 : 1,
+            'is_enable_grade' => $original[$this->mapGoods['is_enable_grade']] === '关闭' ? 0 : 1,
+            'status' => $original['G'] === '下架' ? GoodsStatusEnum::OFF_SALE : GoodsStatusEnum::ON_SALE,
+            'categoryIds' => $this->ids2array($original[$this->mapGoods['categoryIds']]),
+            'imagesIds' => $this->ids2array($original[$this->mapGoods['imagesIds']]),
+            'serviceIds' => $this->ids2array($original[$this->mapGoods['serviceIds']]),
+            // 下面是默认数据, 没有会报错
+            'content' => '',
+            'alone_grade_equity' => [],
+            'newSpecList' => [],
+            'newSkuList' => [],
+            'store_id' => $storeId,
+        ];
+        // 规格和sku数据处理
+        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
+            $specList = $this->createSpecList($original['skuList']);
+            $data['specData']['specList'] = $specList;
+            $data['specData']['skuList'] = $this->createSkuList($original['skuList'], $specList);
+            // 生成多规格数据 (携带id)
+            $data['newSpecList'] = SpecModel::getNewSpecList($data['specData']['specList'], $storeId);
+            // 生成skuList (携带goods_sku_id)
+            $data['newSkuList'] = GoodsSkuModel::getNewSkuList($data['newSpecList'], $data['specData']['skuList']);
+        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
+            // 生成skuItem
+            $data['newSkuList'] = [
+                'goods_price' => $original[$this->mapSku['goods_price']],
+                'line_price' => $original[$this->mapSku['line_price']],
+                'stock_num' => $original[$this->mapSku['stock_num']],
+                'goods_weight' => $original[$this->mapSku['goods_weight']],
+                // 'goods_sku_no' => $original[$this->mapSku['goods_sku_no']],
+            ];
+        }
+        // 整理商品的价格和库存总量
+        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
+            $data['stock_total'] = GoodsSkuModel::getStockTotal($data['specData']['skuList']);
+            [$data['goods_price_min'], $data['goods_price_max']] = GoodsSkuModel::getGoodsPrices($data['specData']['skuList']);
+            [$data['line_price_min'], $data['line_price_max']] = GoodsSkuModel::getLinePrices($data['specData']['skuList']);
+        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
+            $data['goods_price_min'] = $data['goods_price_max'] = $original[$this->mapSku['goods_price']];
+            $data['line_price_min'] = $data['line_price_max'] = $original[$this->mapSku['line_price']];
+            $data['stock_total'] = $original[$this->mapSku['stock_num']];
+        }
+        // 过滤不存在的ID集数据
+        $data['categoryIds'] = CategoryModel::filterCategoryIds($data['categoryIds'], $storeId);
+        $data['imagesIds'] = UploadFileModel::filteFileIds($data['imagesIds'], $storeId);
+        $data['serviceIds'] = GoodsServiceModel::filterServiceIds($data['serviceIds'], $storeId);
+        return $data;
+    }
+
+    /**
+     * ID集字符串转换成数组
+     * @param string $value
+     * @return array|false|string[]
+     */
+    private function ids2array(string $value)
+    {
+        return !empty($value) ? \explode(',', $value) : [];
+    }
+
+    /**
+     * 创建标准的商品SKU数据
+     * @param array $originalSkuList
+     * @param array $specList
+     * @return array
+     */
+    private function createSkuList(array $originalSkuList, array $specList): array
+    {
+        $data = [];
+        foreach ($originalSkuList as $item) {
+            // 设置skuKeys数据
+            foreach ($item['specNames'] as $spec) {
+                $specGroup = helper::arraySearch($specList, 'spec_name', $spec[0]);
+                $specValue = helper::arraySearch($specGroup['valueList'], 'spec_value', $spec[1]);
+                $item['skuKeys'][] = [
+                    'groupKey' => $specGroup['key'],
+                    'valueKey' => $specValue['key']
+                ];
+            }
+            // 整理SKU数据
+            $data[] = [
+                'image_id' => 0,
+                'goods_price' => $item[$this->mapSku['goods_price']],
+                'line_price' => $item[$this->mapSku['line_price']],
+                'stock_num' => $item[$this->mapSku['stock_num']],
+                'goods_weight' => $item[$this->mapSku['goods_weight']],
+                'goods_sku_no' => $item[$this->mapSku['goods_sku_no']],
+                'skuKeys' => $item['skuKeys'],
+            ];
+        }
+        return $data;
+    }
+
+    /**
+     * 创建标准的商品规格数据(树状)
+     * @param array $originalSkuList
+     * @return array
+     */
+    private function createSpecList(array &$originalSkuList): array
+    {
+        // 生成规格数据
+        $data = [];
+        foreach ($originalSkuList as &$item) {
+            $tempArr1 = \explode(',', $item['H']);  // ['颜色:白色', '尺码:小']
+            foreach ($tempArr1 as $val) {
+                $tempArr2 = \explode(':', $val);  // ['颜色','白色']
+                $data[$tempArr2[0]][$tempArr2[1]] = 1;
+                $item['specNames'][] = $tempArr2;
+            }
+        }
+        // 整理为specList格式
+        $specList = [];
+        foreach ($data as $specName => $specValues) {
+            $groupKey = \count($specList);
+            $valueList = [];
+            foreach ($specValues as $specValue => $key) {
+                $valueList[] = [
+                    'key' => \count($valueList),
+                    'groupKey' => $groupKey,
+                    'spec_value' => $specValue,
+                ];
+            }
+            $specList[] = [
+                'key' => $groupKey,
+                'spec_name' => $specName,
+                'valueList' => $valueList,
+            ];
+        }
+        return $specList;
+    }
+}
\ No newline at end of file
diff --git a/app/store/model/Category.php b/app/store/model/Category.php
index 99ab22a2..908a4997 100644
--- a/app/store/model/Category.php
+++ b/app/store/model/Category.php
@@ -28,7 +28,7 @@ class Category extends CategoryModel
      */
     public function add($data): bool
     {
-        $data['store_id'] = self::$storeId;
+        $data['store_id'] = $data['store_id'] ?? self::$storeId;
         return $this->save($data);
     }
 
diff --git a/app/store/model/goods/Import.php b/app/store/model/goods/Import.php
index e855c62d..259de050 100644
--- a/app/store/model/goods/Import.php
+++ b/app/store/model/goods/Import.php
@@ -15,7 +15,7 @@ namespace app\store\model\goods;
 use think\Paginator;
 use think\db\exception\DbException;
 use PhpOffice\PhpSpreadsheet\Exception;
-use app\job\controller\goods\Import as GoodsImportJob;
+use app\job\controller\goods\AdminImport as GoodsAdminImportJob;
 use app\common\enum\goods\ImportStatus as GoodsImportStatusEnum;
 use app\common\library\FileLocal;
 use app\common\library\helper;
@@ -56,8 +56,87 @@ class Import extends ImportModel
         // 检索查询条件
         $filter = [];
         $params['status'] > -1 && $filter[] = ['status', '=', (int)$params['status']];
+        isset($params['store_id']) && $params['store_id'] > -1 && $filter[] = ['store_id', '=', (int)$params['store_id']];
         return $filter;
     }
+    /**
+     * 执行批量导入
+     * @param array $form
+     * @return bool
+     * @throws BaseException
+     * @throws Exception
+     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
+     */
+    public function adminBatch(array $form): bool
+    {
+        // 读取excel文件内容
+        $execlData = $this->readExecl();
+        // 验证导入的商品数量是否合法
+        $this->checkLimit($execlData);
+        // 格式化导入的商品列表数据
+        $goodsList = $this->adminFormatGoodsList($execlData);
+        // echo "
";
+        // print_r($goodsList);
+        // exit();
+        //总后台的店铺id设置为0
+        self::$storeId = 0;
+        // 新增商品导入记录
+        $recordId = $this->addRecord(\count($goodsList));
+        // 调度计划任务
+        $this->adminDispatchJob($goodsList, $recordId);
+        return true;
+    }
+    /**
+     * 调度队列服务执行商品导入
+     * @param array $goodsList 商品列表
+     * @param int $recordId 商品导入记录ID
+     * @return void
+     */
+    private function adminDispatchJob(array $goodsList, int $recordId)
+    {
+        // 分批每次导入20条
+        $limit = 20;
+        // 根据商品总数量计算需要的队列任务数量
+        $jobCount = \count($goodsList) / $limit;
+        // 逐次发布队列任务
+        for ($i = 0; $i < $jobCount; $i++) {
+            $data = array_slice($goodsList, $i * $limit, $limit);
+            GoodsAdminImportJob::dispatch([
+                'list' => $data,
+                'recordId' => $recordId,
+                'storeId' => self::$storeId,
+            ]);
+        }
+    }
+    /**
+     * 格式化导入的商品列表数据
+     * @param array $execlData
+     * @return array
+     */
+    private function adminFormatGoodsList(array $execlData): array
+    {
+        $goodsList = [];
+        foreach ($execlData as $row) {
+            // 不存在商品序号的记录视为空行跳过
+            if (!is_numeric($row['A'])) {
+                continue;
+            }
+            // SKU信息
+            $skuInfo = helper::pick($row, ['G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']);
+            // 商品数据里不存在相同序号, 代表是第一次记录
+            if (!isset($goodsList[$row['A']])) {
+                $goodsList[$row['A']] = $row;
+                // 存在规格值组合则商品是多规格
+                if (!empty($row['H'])) {
+                    $goodsList[$row['A']]['skuList'] = [$skuInfo];
+                }
+            } elseif (isset($goodsList[$row['A']]['skuList'])) {
+                // 否则代表是多规格商品的SKU
+                $goodsList[$row['A']]['skuList'][] = $skuInfo;
+            }
+        }
+        return array_values($goodsList);
+    }
 
     /**
      * 执行批量导入
@@ -121,7 +200,7 @@ class Import extends ImportModel
         ]);
         return (int)$this['id'];
     }
-
+    
     /**
      * 格式化导入的商品列表数据
      * @param array $execlData

From 98a2fb0f066ea8bb50e3f6063669280cd61a42d6 Mon Sep 17 00:00:00 2001
From: lqmac 
Date: Tue, 5 Mar 2024 23:46:22 +0800
Subject: [PATCH 2/3] 1

---
 app/admin/controller/Files.php       | 149 ++++++++++++++++++++++++
 app/admin/controller/Goods.php       | 164 +++++++++++++++++++--------
 app/admin/controller/Goods1.php      |  80 +++++++++++++
 app/admin/controller/files/Group.php |  86 ++++++++++++++
 app/api/service/Goods.php            |   4 +-
 5 files changed, 435 insertions(+), 48 deletions(-)
 create mode 100644 app/admin/controller/Files.php
 create mode 100644 app/admin/controller/Goods1.php
 create mode 100644 app/admin/controller/files/Group.php

diff --git a/app/admin/controller/Files.php b/app/admin/controller/Files.php
new file mode 100644
index 00000000..03653749
--- /dev/null
+++ b/app/admin/controller/Files.php
@@ -0,0 +1,149 @@
+
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\admin\controller;
+
+use think\response\Json;
+use cores\library\Version;
+use app\store\model\UploadFile as UploadFileModel;
+
+/**
+ * 文件库管理
+ * Class Files
+ * @package app\store\controller
+ */
+class Files extends Controller
+{
+    /**
+     * 文件列表
+     * @return Json
+     * @throws \cores\exception\BaseException
+     * @throws \think\db\exception\DbException
+     */
+    public function list(): Json
+    {
+        $this->env();
+        $model = new UploadFileModel;
+        $list = $model->getList($this->request->param());
+        return $this->renderSuccess(compact('list'));
+    }
+
+    /**
+     * 编辑文件
+     * @param int $fileId
+     * @return Json
+     */
+    public function edit(int $fileId): Json
+    {
+        // 文件详情
+        $model = UploadFileModel::detail($fileId);
+        // 更新记录
+        if ($model->edit($this->postForm())) {
+            return $this->renderSuccess('更新成功');
+        }
+        return $this->renderError($model->getError() ?: '更新失败');
+    }
+
+    /**
+     * 删除文件(批量)
+     * @param array $fileIds 文件id集
+     * @return Json
+     * @throws \think\Exception
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function delete(array $fileIds): Json
+    {
+        $model = new UploadFileModel;
+        if (!$model->setDelete($fileIds)) {
+            return $this->renderError($model->getError() ?: '操作失败');
+        }
+        return $this->renderSuccess('操作成功');
+    }
+
+    /**
+     * 移动文件到指定分组(批量)
+     * @param int $groupId
+     * @param array $fileIds
+     * @return Json
+     */
+    public function moveGroup(int $groupId, array $fileIds): Json
+    {
+        $model = new UploadFileModel;
+        if (!$model->moveGroup($groupId, $fileIds)) {
+            return $this->renderError($model->getError() ?: '操作失败');
+        }
+        return $this->renderSuccess('操作成功');
+    }
+
+    /**
+     * 临时方法:环境检测并删除废弃的库文件
+     * 文件:vendor/topthink/framework/src/think/Filesystem.php
+     * 文件:vendor/topthink/framework/src/think/facade/Filesystem.php
+     * 文件:vendor/topthink/framework/tests/FilesystemTest.php
+     * 目录:vendor/topthink/framework/src/think/filesystem
+     * @return void
+     * @throws \cores\exception\BaseException
+     */
+    private function env()
+    {
+        // 判断当前版本小于2.2.7则不执行
+        if (Version::compare(Version::getVersion(), '2.2.7') === -1) {
+            return;
+        }
+        // 要删除的文件列表
+        $files = [
+            'vendor/topthink/framework/src/think/Filesystem.php',
+            'vendor/topthink/framework/src/think/facade/Filesystem.php',
+            'vendor/topthink/framework/tests/FilesystemTest.php'
+        ];
+        foreach ($files as $file) {
+            $filePath = root_path() . $file;
+            file_exists($filePath) && unlink($filePath);
+        }
+        // 要删除的目录列表
+        $folders = ['vendor/topthink/framework/src/think/filesystem/'];
+        foreach ($folders as $folder) {
+            $folderPath = root_path() . $folder;
+            is_dir($folderPath) && $this->deleteFolder($folderPath);
+        }
+    }
+
+    /**
+     * 临时方法:递归删除指定目录下所有文件
+     * @param $path
+     * @return void
+     */
+    private function deleteFolder($path): void
+    {
+        if (!is_dir($path)) {
+            return;
+        }
+        // 扫描一个文件夹内的所有文件夹和文件
+        foreach (scandir($path) as $val) {
+            // 排除目录中的.和..
+            if (!in_array($val, ['.', '..', '.gitignore'])) {
+                // 如果是目录则递归子目录,继续操作
+                if (is_dir($path . $val)) {
+                    // 子目录中操作删除文件夹和文件
+                    $this->deleteFolder($path . $val . '/');
+                    // 目录清空后删除空文件夹
+                    rmdir($path . $val . '/');
+                } else {
+                    // 如果是文件直接删除
+                    unlink($path . $val);
+                }
+            }
+        }
+    }
+}
diff --git a/app/admin/controller/Goods.php b/app/admin/controller/Goods.php
index 47bd25e3..2b05a80c 100644
--- a/app/admin/controller/Goods.php
+++ b/app/admin/controller/Goods.php
@@ -12,69 +12,141 @@ declare (strict_types=1);
 
 namespace app\admin\controller;
 
-use think\facade\Db;
+use think\db\exception\DbException;
 use think\response\Json;
+use cores\exception\BaseException;
+use app\store\model\Goods as GoodsModel;
 
 /**
- * 商城管理
- * Class Store
- * @package app\admin\controller
+ * 商品管理控制器
+ * Class Goods
+ * @package app\store\controller
  */
 class Goods extends Controller
 {
     /**
-     * 强制验证当前访问的控制器方法method
-     * @var array
+     * 商品列表
+     * @return Json
+     * @throws DbException
      */
-    protected array $methodRules = [
-        'index' => 'GET',
-        'recycle' => 'GET',
-        'add' => 'POST',
-        'move' => 'POST',
-        'delete' => 'POST',
-    ];
+    public function list(): Json
+    {
+        // 获取列表记录
+        $model = new GoodsModel;
+        $list= $model->getList($this->request->param());
+        return $this->renderSuccess(compact('list'));
+    }
 
     /**
-     * 商城列表
+     * 根据商品ID集获取列表记录
+     * @param array $goodsIds
      * @return Json
-     * @throws \think\db\exception\DbException
      */
-    public function index(): Json
+    public function listByIds(array $goodsIds): Json
     {
+        // 获取列表记录
+        $model = new GoodsModel;
+        $list = $model->getListByIds($goodsIds);
+        return $this->renderSuccess(compact('list'));
+    }
 
-        $params = $this->request->param();
-        $sort = $this->request->param('sort', 'id');
-        $order = $this->request->param('order', 'desc');
-        $where = [];
-        if (isset($params['channel']) && $params['channel']) {
-            $where[] = ['channel', '=', $params['channel']];
-        }
-        if (isset($params['min_profit_rate']) && $params['min_profit_rate']) {
-            $where[] = ['profit_rate', '>=', $params['min_profit_rate']];
-        }
-        if (isset($params['max_profit_rate']) && $params['max_profit_rate']) {
-            $where[] = ['profit_rate', '<=', $params['max_profit_rate']];
-        }
-        if (isset($params['min_price']) && $params['min_price']) {
-            $where[] = ['net_price', '>=', $params['min_price']];
-        }
-        if (isset($params['max_price']) && $params['max_price']) {
-            $where[] = ['net_price', '<=', $params['max_price']];
+    /**
+     * 商品详情(详细信息)
+     * @param int $goodsId
+     * @return Json
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function detail(int $goodsId): Json
+    {
+        // 获取商品详情
+        $model = new GoodsModel;
+        $goodsInfo = $model->getDetail($goodsId);
+        return $this->renderSuccess(compact('goodsInfo'));
+    }
+
+    /**
+     * 商品详情(基础信息)
+     * @param int $goodsId
+     * @return Json
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function basic(int $goodsId): Json
+    {
+        // 获取商品详情
+        $model = new GoodsModel;
+        $detail = $model->getBasic($goodsId);
+        return $this->renderSuccess(compact('detail'));
+    }
+
+    /**
+     * 添加商品
+     * @return Json
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function add(): Json
+    {
+        $model = new GoodsModel;
+        if ($model->add($this->postForm())) {
+            return $this->renderSuccess('添加成功');
         }
-        if (!empty($params['catalog_name'])) {
-            $where[] = ['catalog_name', 'like', "%{$params["catalog_name"]}%"];
+        return $this->renderError($model->getError() ?: '添加失败');
+    }
+
+    /**
+     * 商品编辑
+     * @param int $goodsId
+     * @return Json
+     * @throws BaseException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function edit(int $goodsId): Json
+    {
+        // 商品详情
+        $model = GoodsModel::detail($goodsId);
+        // 更新记录
+        if ($model->edit($this->postForm())) {
+            return $this->renderSuccess('更新成功');
         }
-        $list = Db::connect("dataCenterMysql")->table('goods_sku')
-            ->where($where)
-            ->order($sort, $order)
-            ->paginate($this->request->param('per_page', 15))->each(function ($item, $key) {
-                $item['create_time'] = date("Y-m-d H:i:s", $item['create_time']);
-                $item['update_time'] = date("Y-m-d H:i:s", $item['update_time']);
-                $item['channel'] = config('app.platformList')[$item['channel']] ?? "";
-                return $item;
-            });
-        return $this->renderSuccess(compact('list'));
+        return $this->renderError($model->getError() ?: '更新失败');
     }
 
+    /**
+     * 修改商品状态(上下架)
+     * @param array $goodsIds 商品id集
+     * @param bool $state 为true表示上架
+     * @return Json
+     */
+    public function state(array $goodsIds, bool $state): Json
+    {
+        $model = new GoodsModel;
+        if (!$model->setStatus($goodsIds, $state)) {
+            return $this->renderError($model->getError() ?: '操作失败');
+        }
+        return $this->renderSuccess('操作成功');
+    }
 
+    /**
+     * 删除商品
+     * @param array $goodsIds
+     * @return Json
+     */
+    public function delete(array $goodsIds): Json
+    {
+        $model = new GoodsModel;
+        if (!$model->setDelete($goodsIds)) {
+            return $this->renderError($model->getError() ?: '删除失败');
+        }
+        return $this->renderSuccess('删除成功');
+    }
 }
diff --git a/app/admin/controller/Goods1.php b/app/admin/controller/Goods1.php
new file mode 100644
index 00000000..47bd25e3
--- /dev/null
+++ b/app/admin/controller/Goods1.php
@@ -0,0 +1,80 @@
+
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\admin\controller;
+
+use think\facade\Db;
+use think\response\Json;
+
+/**
+ * 商城管理
+ * Class Store
+ * @package app\admin\controller
+ */
+class Goods extends Controller
+{
+    /**
+     * 强制验证当前访问的控制器方法method
+     * @var array
+     */
+    protected array $methodRules = [
+        'index' => 'GET',
+        'recycle' => 'GET',
+        'add' => 'POST',
+        'move' => 'POST',
+        'delete' => 'POST',
+    ];
+
+    /**
+     * 商城列表
+     * @return Json
+     * @throws \think\db\exception\DbException
+     */
+    public function index(): Json
+    {
+
+        $params = $this->request->param();
+        $sort = $this->request->param('sort', 'id');
+        $order = $this->request->param('order', 'desc');
+        $where = [];
+        if (isset($params['channel']) && $params['channel']) {
+            $where[] = ['channel', '=', $params['channel']];
+        }
+        if (isset($params['min_profit_rate']) && $params['min_profit_rate']) {
+            $where[] = ['profit_rate', '>=', $params['min_profit_rate']];
+        }
+        if (isset($params['max_profit_rate']) && $params['max_profit_rate']) {
+            $where[] = ['profit_rate', '<=', $params['max_profit_rate']];
+        }
+        if (isset($params['min_price']) && $params['min_price']) {
+            $where[] = ['net_price', '>=', $params['min_price']];
+        }
+        if (isset($params['max_price']) && $params['max_price']) {
+            $where[] = ['net_price', '<=', $params['max_price']];
+        }
+        if (!empty($params['catalog_name'])) {
+            $where[] = ['catalog_name', 'like', "%{$params["catalog_name"]}%"];
+        }
+        $list = Db::connect("dataCenterMysql")->table('goods_sku')
+            ->where($where)
+            ->order($sort, $order)
+            ->paginate($this->request->param('per_page', 15))->each(function ($item, $key) {
+                $item['create_time'] = date("Y-m-d H:i:s", $item['create_time']);
+                $item['update_time'] = date("Y-m-d H:i:s", $item['update_time']);
+                $item['channel'] = config('app.platformList')[$item['channel']] ?? "";
+                return $item;
+            });
+        return $this->renderSuccess(compact('list'));
+    }
+
+
+}
diff --git a/app/admin/controller/files/Group.php b/app/admin/controller/files/Group.php
new file mode 100644
index 00000000..5384529e
--- /dev/null
+++ b/app/admin/controller/files/Group.php
@@ -0,0 +1,86 @@
+
+// +----------------------------------------------------------------------
+declare (strict_types=1);
+
+namespace app\admin\controller\files;
+
+use think\response\Json;
+use app\admin\controller\Controller;
+use app\store\model\UploadGroup as GroupModel;
+
+/**
+ * 文件分组
+ * Class Group
+ * @package app\store\controller\content
+ */
+class Group extends Controller
+{
+    /**
+     * 文件分组列表
+     * @return Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function list(): Json
+    {
+        $model = new GroupModel;
+        $list = $model->getList();
+        return $this->renderSuccess(compact('list'));
+    }
+
+    /**
+     * 添加文件分组
+     * @return Json
+     */
+    public function add(): Json
+    {
+        // 新增记录
+        $model = new GroupModel;
+        if ($model->add($this->postForm())) {
+            return $this->renderSuccess('添加成功');
+        }
+        return $this->renderError($model->getError() ?: '添加失败');
+    }
+
+    /**
+     * 编辑文件分组
+     * @param int $groupId
+     * @return Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function edit(int $groupId): Json
+    {
+        // 分组详情
+        $model = GroupModel::detail($groupId);
+        // 更新记录
+        if ($model->edit($this->postForm())) {
+            return $this->renderSuccess('更新成功');
+        }
+        return $this->renderError($model->getError() ?: '更新失败');
+    }
+
+    /**
+     * 删除文件分组
+     * @param int $groupId
+     * @return Json
+     */
+    public function delete(int $groupId): Json
+    {
+        $model = GroupModel::detail($groupId);
+        if (!$model->remove()) {
+            return $this->renderError($model->getError() ?: '删除失败');
+        }
+        return $this->renderSuccess('删除成功');
+    }
+}
diff --git a/app/api/service/Goods.php b/app/api/service/Goods.php
index 8746e856..8b5958cb 100644
--- a/app/api/service/Goods.php
+++ b/app/api/service/Goods.php
@@ -179,7 +179,7 @@ class Goods extends GoodsService
         }
         $list = $goodsList->toArray();
 
-        $list['data'] = $this->formatGoodsList($goodsList);
+        $list['data'] = $this->newFormatGoodsList($list['data']);
         return $list;
 
     }
@@ -205,7 +205,7 @@ class Goods extends GoodsService
             ], 3);
             $list2 = $goodsList->toArray()['data'];
 
-            $v['goods_list'] = $this->formatGoodsList($list2);
+            $v['goods_list'] = $this->newFormatGoodsList($list2);
         }
 
         return $list;

From d7e3c6819b180130984fe80a6c8d8829e2972358 Mon Sep 17 00:00:00 2001
From: lqmac 
Date: Wed, 6 Mar 2024 09:22:00 +0800
Subject: [PATCH 3/3] 1

---
 app/common/validate/goods/AdminImport.php |  58 +++++++++++
 app/job/controller/goods/AdminImport.php  |   2 +-
 app/job/service/goods/AdminImport.php     | 120 ++++++++--------------
 app/job/service/goods/Collector.php       |  38 ++++++-
 app/store/model/goods/Import.php          |  56 ++++------
 5 files changed, 154 insertions(+), 120 deletions(-)
 create mode 100644 app/common/validate/goods/AdminImport.php

diff --git a/app/common/validate/goods/AdminImport.php b/app/common/validate/goods/AdminImport.php
new file mode 100644
index 00000000..2413d4b3
--- /dev/null
+++ b/app/common/validate/goods/AdminImport.php
@@ -0,0 +1,58 @@
+ ['goods_name', 'delivery_id', 'imagesIds', 'categoryIds', 'serviceIds'],
+        'skuInfo' => ['goods_price', 'stock_num', 'goods_weight'],
+    ];
+
+    /**
+     * 验证规则
+     * @var array
+     */
+    protected $rule = [
+        'goods_name|商品名称' => ['require'],
+        'delivery_id|运费模板ID' => ['require', 'number'],
+        'imagesIds|商品图片ID集' => ['require', 'array', 'validateIds'],
+        'categoryIds|商品分类ID集' => ['require', 'array', 'validateIds'],
+        'serviceIds|服务与承诺' => ['array', 'validateIds'],
+
+        'goods_price|商品价格' => ['require', 'float', '>=:0.01'],
+        'stock_num|库存数量' => ['require', 'integer', '>=:0'],
+        'goods_weight|商品重量' => ['require', 'float', '>=:0'],
+    ];
+
+    /**
+     * 错误信息
+     * @var string[]
+     */
+    protected $message = [
+        // 'delivery_id.number' => '运费模板ID必须是数字',
+    ];
+
+    /**
+     * 验证ID集格式是否正确
+     * @param $value
+     * @return bool
+     */
+    protected function validateIds($value): bool
+    {
+        foreach ($value as $val) {
+            if (!is_numeric($val)) {
+                return false;
+            }
+        }
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/app/job/controller/goods/AdminImport.php b/app/job/controller/goods/AdminImport.php
index 8a77bd0f..044d0e67 100644
--- a/app/job/controller/goods/AdminImport.php
+++ b/app/job/controller/goods/AdminImport.php
@@ -41,7 +41,7 @@ class AdminImport extends BaseJob
     public function handle(array $data): bool
     {
         $time = date('H:i:s');
-        echo "\n  ---- Import ----  {$time} ----   \n";
+        echo "\n  ---- adminImport ----  {$time} ----   \n";
 
         $service = new GoodsAdminImportService;
         return $service->batch($data['list'], $data['recordId'], $data['storeId']);
diff --git a/app/job/service/goods/AdminImport.php b/app/job/service/goods/AdminImport.php
index 67806a23..5069bb34 100644
--- a/app/job/service/goods/AdminImport.php
+++ b/app/job/service/goods/AdminImport.php
@@ -31,8 +31,9 @@ use app\common\enum\goods\GoodsType as GoodsTypeEnum;
 use app\common\enum\goods\SpecType as GoodsSpecTypeEnum;
 use app\common\enum\goods\ImportStatus as GoodsImportStatusEnum;
 use app\common\enum\goods\DeductStockType as DeductStockTypeEnum;
-use app\common\validate\goods\Import as GoodsImportValidate;
+use app\common\validate\goods\AdminImport as GoodsAdminImportValidate;
 use cores\exception\BaseException;
+use think\facade\Log;
 
 /**
  * 服务类:商品批量导入
@@ -99,30 +100,35 @@ class AdminImport extends BaseService
      */
     public function batch(array $list, int $recordId, int $storeId): bool
     {
+    	$service = new \app\job\service\goods\Collector();
         foreach ($list as $item) {
+        	$data = $this->createData($item, $storeId);
+        	$service->single($item['D'], $data, $storeId);
+
             // 生成商品数据(用于写入数据库)
-            $data = $this->createData($item, $storeId);
-            // 数据验证
-            if (!$this->validateGoodsData($data, $storeId)) {
-                $this->errorLog[] = ['goodsSn' => $item['A'], 'message' => $this->getError()];
-                continue;
-            }
-            // 事务处理:添加商品
-            $model = new GoodsModel();
-            $model->transaction(function () use ($model, $data, $storeId) {
-                // 添加商品
-                $model->save($data);
-                // 新增商品与分类关联
-                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);
-                // 新增服务与承诺关联
-                GoodsServiceRelModel::increased((int)$model['goods_id'], $data['serviceIds'], $storeId);
-            });
+            // $data = $this->createData($item, $storeId);
+            // Log::record("data".json_encode($data));
+            // // 数据验证
+            // if (!$this->validateGoodsData($data, $storeId)) {
+            //     $this->errorLog[] = ['goodsSn' => $item['A'], 'message' => $this->getError()];
+            //     continue;
+            // }
+            // // 事务处理:添加商品
+            // $model = new GoodsModel();
+            // $model->transaction(function () use ($model, $data, $storeId) {
+            //     // 添加商品
+            //     $model->save($data);
+            //     // 新增商品与分类关联
+            //     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);
+            //     // 新增服务与承诺关联
+            //     GoodsServiceRelModel::increased((int)$model['goods_id'], $data['serviceIds'], $storeId);
+            // });
             // 记录导入成功
             $this->successCount++;
         }
@@ -164,7 +170,8 @@ class AdminImport extends BaseService
     private function validateGoodsData(array $data, int $storeId): bool
     {
         // 验证商品信息:商品名称、分类ID集、图片ID集、运费模板ID
-        $validate = new GoodsImportValidate;
+        $validate = new GoodsAdminImportValidate;
+        Log::record($data);
         if (!$validate->scene('goods')->check($data)) {
             $this->setError($validate->getError());
             return false;
@@ -172,7 +179,7 @@ class AdminImport extends BaseService
         // 验证SKU信息:商品价格、库存数量、商品重量
         $skuList = $data['spec_type'] == GoodsSpecTypeEnum::MULTI ? $data['newSkuList'] : [$data['newSkuList']];
         foreach ($skuList as $item) {
-            $validate = new GoodsImportValidate;
+            $validate = new GoodsAdminImportValidate;
             if (!$validate->scene('skuInfo')->check($item)) {
                 $this->setError($validate->getError());
                 return false;
@@ -212,66 +219,19 @@ class AdminImport extends BaseService
      */
     private function createData(array $original, int $storeId): array
     {
-        // 商品规格
-        $specType = isset($original['skuList']) ? GoodsSpecTypeEnum::MULTI : GoodsSpecTypeEnum::SINGLE;
         // 整理商品数据
         $data = [
-            'goods_type' => GoodsTypeEnum::PHYSICAL,
-            'goods_name' => $original[$this->mapGoods['goods_name']],
-            'goods_no' => $original[$this->mapGoods['goods_no']],
-            'spec_type' => $specType,
-            'delivery_id' => $original[$this->mapGoods['delivery_id']],
-            'sort' => $original[$this->mapGoods['sort']],
-            'sales_initial' => $original[$this->mapGoods['sales_initial']],
-            'deduct_stock_type' => $original[$this->mapGoods['deduct_stock_type']] === '付款减库存' ? DeductStockTypeEnum::PAYMENT
-                : DeductStockTypeEnum::CREATE,
-            'is_points_gift' => $original[$this->mapGoods['is_points_gift']] === '关闭' ? 0 : 1,
-            'is_points_discount' => $original[$this->mapGoods['is_points_discount']] === '关闭' ? 0 : 1,
-            'is_enable_grade' => $original[$this->mapGoods['is_enable_grade']] === '关闭' ? 0 : 1,
-            'status' => $original['G'] === '下架' ? GoodsStatusEnum::OFF_SALE : GoodsStatusEnum::ON_SALE,
-            'categoryIds' => $this->ids2array($original[$this->mapGoods['categoryIds']]),
-            'imagesIds' => $this->ids2array($original[$this->mapGoods['imagesIds']]),
-            'serviceIds' => $this->ids2array($original[$this->mapGoods['serviceIds']]),
-            // 下面是默认数据, 没有会报错
-            'content' => '',
-            'alone_grade_equity' => [],
-            'newSpecList' => [],
-            'newSkuList' => [],
+            'cmmdty_model' => $original["A"],
+            'channel' => "jd",
+            'goods_no' => $original["C"],
+            'categoryIds' => $this->ids2array($original["E"]),
+            'imageStorage' => 10,//下载图片到本地
+            'goods_type' => 10,//实物
+            'goods_status' => 10,//上架
             'store_id' => $storeId,
         ];
-        // 规格和sku数据处理
-        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
-            $specList = $this->createSpecList($original['skuList']);
-            $data['specData']['specList'] = $specList;
-            $data['specData']['skuList'] = $this->createSkuList($original['skuList'], $specList);
-            // 生成多规格数据 (携带id)
-            $data['newSpecList'] = SpecModel::getNewSpecList($data['specData']['specList'], $storeId);
-            // 生成skuList (携带goods_sku_id)
-            $data['newSkuList'] = GoodsSkuModel::getNewSkuList($data['newSpecList'], $data['specData']['skuList']);
-        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
-            // 生成skuItem
-            $data['newSkuList'] = [
-                'goods_price' => $original[$this->mapSku['goods_price']],
-                'line_price' => $original[$this->mapSku['line_price']],
-                'stock_num' => $original[$this->mapSku['stock_num']],
-                'goods_weight' => $original[$this->mapSku['goods_weight']],
-                // 'goods_sku_no' => $original[$this->mapSku['goods_sku_no']],
-            ];
-        }
-        // 整理商品的价格和库存总量
-        if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
-            $data['stock_total'] = GoodsSkuModel::getStockTotal($data['specData']['skuList']);
-            [$data['goods_price_min'], $data['goods_price_max']] = GoodsSkuModel::getGoodsPrices($data['specData']['skuList']);
-            [$data['line_price_min'], $data['line_price_max']] = GoodsSkuModel::getLinePrices($data['specData']['skuList']);
-        } elseif ($data['spec_type'] === GoodsSpecTypeEnum::SINGLE) {
-            $data['goods_price_min'] = $data['goods_price_max'] = $original[$this->mapSku['goods_price']];
-            $data['line_price_min'] = $data['line_price_max'] = $original[$this->mapSku['line_price']];
-            $data['stock_total'] = $original[$this->mapSku['stock_num']];
-        }
         // 过滤不存在的ID集数据
-        $data['categoryIds'] = CategoryModel::filterCategoryIds($data['categoryIds'], $storeId);
-        $data['imagesIds'] = UploadFileModel::filteFileIds($data['imagesIds'], $storeId);
-        $data['serviceIds'] = GoodsServiceModel::filterServiceIds($data['serviceIds'], $storeId);
+        //$data['categoryIds'] = CategoryModel::filterCategoryIds($data['categoryIds'], $storeId);
         return $data;
     }
 
diff --git a/app/job/service/goods/Collector.php b/app/job/service/goods/Collector.php
index 757d84b1..2ccfe71b 100644
--- a/app/job/service/goods/Collector.php
+++ b/app/job/service/goods/Collector.php
@@ -116,7 +116,40 @@ class Collector extends BaseService
         $this->updateRecord($recordId, \count($urls));
         return true;
     }
-
+    public function single(string $url, array $form, int $storeId): bool
+    {
+       
+        try {
+            // 采集第三方商品数据
+            $original = $this->collector($url, $storeId);
+            // 下载远程商品图片
+            $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->createData($original, $form, $storeId);
+        // 事务处理:添加商品
+        $model = new GoodsModel();
+        $model->transaction(function () use ($model, $data, $storeId) {
+            // 添加商品
+            $model->save($data);
+            // 新增商品与分类关联
+            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;
+    }
     /**
      * 检查采集记录状态是否异常
      * @param int $recordId
@@ -251,6 +284,9 @@ class Collector extends BaseService
             'newSkuList' => [],
             'store_id' => $storeId,
         ];
+        if (isset($form['channel']) {
+            $data['channel'] = $form['channel'];
+        }
         // 整理商品的价格和库存总量
         if ($data['spec_type'] === GoodsSpecTypeEnum::MULTI) {
             $data['stock_total'] = GoodsSkuModel::getStockTotal($original['specData']['skuList']);
diff --git a/app/store/model/goods/Import.php b/app/store/model/goods/Import.php
index 259de050..ef553737 100644
--- a/app/store/model/goods/Import.php
+++ b/app/store/model/goods/Import.php
@@ -73,17 +73,26 @@ class Import extends ImportModel
         $execlData = $this->readExecl();
         // 验证导入的商品数量是否合法
         $this->checkLimit($execlData);
-        // 格式化导入的商品列表数据
-        $goodsList = $this->adminFormatGoodsList($execlData);
-        // echo "
";
-        // print_r($goodsList);
-        // exit();
-        //总后台的店铺id设置为0
+        
         self::$storeId = 0;
+        // $service = new \app\job\service\goods\Collector();
+        // foreach ($execlData as $item) {
+        //     $data = [
+        //         'cmmdty_model' => $item["A"],
+        //         'channel' => "jd",
+        //         'goods_no' => $item["C"],
+        //         'categoryIds' => explode(",", $item["E"]),
+        //         'imageStorage' => 10,//下载图片到本地
+        //         'goods_type' => 10,//实物
+        //         'goods_status' => 10,//上架
+        //         'store_id' => self::$storeId,
+        //     ];
+        //     $service->single($item['D'], $data, self::$storeId);
+        // }
         // 新增商品导入记录
-        $recordId = $this->addRecord(\count($goodsList));
+        $recordId = $this->addRecord(\count($execlData));
         // 调度计划任务
-        $this->adminDispatchJob($goodsList, $recordId);
+        $this->adminDispatchJob($execlData, $recordId);
         return true;
     }
     /**
@@ -108,36 +117,7 @@ class Import extends ImportModel
             ]);
         }
     }
-    /**
-     * 格式化导入的商品列表数据
-     * @param array $execlData
-     * @return array
-     */
-    private function adminFormatGoodsList(array $execlData): array
-    {
-        $goodsList = [];
-        foreach ($execlData as $row) {
-            // 不存在商品序号的记录视为空行跳过
-            if (!is_numeric($row['A'])) {
-                continue;
-            }
-            // SKU信息
-            $skuInfo = helper::pick($row, ['G', 'H', 'I', 'J', 'K', 'L', 'M', 'N']);
-            // 商品数据里不存在相同序号, 代表是第一次记录
-            if (!isset($goodsList[$row['A']])) {
-                $goodsList[$row['A']] = $row;
-                // 存在规格值组合则商品是多规格
-                if (!empty($row['H'])) {
-                    $goodsList[$row['A']]['skuList'] = [$skuInfo];
-                }
-            } elseif (isset($goodsList[$row['A']]['skuList'])) {
-                // 否则代表是多规格商品的SKU
-                $goodsList[$row['A']]['skuList'][] = $skuInfo;
-            }
-        }
-        return array_values($goodsList);
-    }
-
+    
     /**
      * 执行批量导入
      * @param array $form