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.
yanzong/app/store/model/goods/Import.php

273 lines
9.1 KiB

11 months ago
<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\store\model\goods;
use think\Paginator;
use think\db\exception\DbException;
use PhpOffice\PhpSpreadsheet\Exception;
9 months ago
use app\job\controller\goods\AdminImport as GoodsAdminImportJob;
11 months ago
use app\common\enum\goods\ImportStatus as GoodsImportStatusEnum;
use app\common\library\FileLocal;
use app\common\library\helper;
use app\common\library\phpoffice\ReadExecl;
use app\common\model\goods\Import as ImportModel;
use cores\exception\BaseException;
/**
* 商品批量导入记录模型
* Class Import
* @package app\store\model\goods
*/
class Import extends ImportModel
{
/**
* 获取导出记录
* @param array $param
* @return Paginator
* @throws DbException
*/
public function getList(array $param = []): \think\Paginator
{
return $this->where($this->getFilter($param))
->where('is_delete', '=', 0)
->order(['create_time' => 'desc', $this->getPk()])
->paginate();
}
/**
* 获取查询条件
* @param array $param
* @return array
*/
private function getFilter(array $param = []): array
{
// 默认查询参数
$params = $this->setQueryDefaultValue($param, ['goods_type' => -1, 'status' => -1]);
// 检索查询条件
$filter = [];
$params['status'] > -1 && $filter[] = ['status', '=', (int)$params['status']];
9 months ago
isset($params['store_id']) && $params['store_id'] > -1 && $filter[] = ['store_id', '=', (int)$params['store_id']];
11 months ago
return $filter;
}
9 months ago
/**
* 执行批量导入
* @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);
9 months ago
9 months ago
self::$storeId = 0;
9 months ago
// $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);
// }
9 months ago
// 新增商品导入记录
9 months ago
$recordId = $this->addRecord(\count($execlData));
9 months ago
// 调度计划任务
9 months ago
$this->adminDispatchJob($execlData, $recordId);
9 months ago
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,
]);
}
}
9 months ago
11 months ago
/**
* 执行批量导入
* @param array $form
* @return bool
* @throws BaseException
* @throws Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function batch(array $form): bool
{
// 读取excel文件内容
$execlData = $this->readExecl();
// 验证导入的商品数量是否合法
$this->checkLimit($execlData);
// 格式化导入的商品列表数据
$goodsList = $this->formatGoodsList($execlData);
// 新增商品导入记录
$recordId = $this->addRecord(\count($goodsList));
// 调度计划任务
$this->dispatchJob($goodsList, $recordId);
return true;
}
/**
* 调度队列服务执行商品导入
* @param array $goodsList 商品列表
* @param int $recordId 商品导入记录ID
* @return void
*/
private function dispatchJob(array $goodsList, int $recordId)
{
// 分批每次导入20条
$limit = 20;
// 根据商品总数量计算需要的队列任务数量
$jobCount = \count($goodsList) / $limit;
// 逐次发布队列任务
for ($i = 0; $i < $jobCount; $i++) {
$data = array_slice($goodsList, $i * $limit, $limit);
GoodsImportJob::dispatch([
'list' => $data,
'recordId' => $recordId,
'storeId' => self::$storeId,
]);
}
}
/**
* 新增商品导入记录
* @param int $totalCount 商品总数量
* @return int
*/
private function addRecord(int $totalCount): int
{
$this->save([
'total_count' => $totalCount,
'start_time' => \time(),
'fail_log' => [],
'status' => GoodsImportStatusEnum::NORMAL,
'store_id' => self::$storeId
]);
return (int)$this['id'];
}
9 months ago
11 months ago
/**
* 格式化导入的商品列表数据
* @param array $execlData
* @return array
*/
private function formatGoodsList(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 $execlData
* @return void
* @throws BaseException
*/
private function checkLimit(array $execlData): void
{
// 判断商品数据是否为空
if (empty($execlData)) {
throwError('很抱歉,模板文件中商品数量为空');
}
// 过滤重复的商品序号
$originalUnique = helper::arrayUnique($execlData, 'A');
// 判断商品数量是否超出500条
if (\count($originalUnique) > 500) {
throwError('很抱歉,模板文件中最多不能超过500个商品');
}
}
/**
* 读取excel文件内容
* @return array
* @throws BaseException
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
private function readExecl(): array
{
// 接收用户上传的模板文件
$file = request()->file('file');
empty($file) && throwError('很抱歉,您没有上传模板文件');
// 写入到本地临时目录
$path = FileLocal::writeFile($file, 'batch-goods', self::$storeId);
// 读取excel数据
$original = ReadExecl::load($path, 0, 21);
// 去除标题数据
unset($original[1]);
// 过滤空行和无效的内容
foreach ($original as $key => $row) {
if (!is_numeric($row['A']) || empty($row['A'])) {
unset($original[$key]);
}
}
return $original;
}
/**
* 删除记录
* @return bool
*/
public function setDelete(): bool
{
if ($this['status'] == GoodsImportStatusEnum::NORMAL) {
$this->error = '很抱歉,当前任务没有结束不能删除';
return false;
}
return $this->save(['is_delete' => 1]);
}
}