更新若干功能
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Models\business\ImageModel;
|
||||
use App\Models\business\PriceSheetModel;
|
||||
use App\Service\common\MediaUrlService;
|
||||
use Exception;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
@@ -23,7 +24,7 @@ class CatalogueService extends BaseService
|
||||
{
|
||||
parent::__construct();
|
||||
$this->model = CatalogueModel::class;
|
||||
$this->selectField = ['id', 'title', 'category_id', 'cover', 'pdf', 'price', 'alias', 'identifier', 'status', 'created_at', 'updated_at'];
|
||||
$this->selectField = ['id', 'title', 'category_id', 'cover', 'pdf', 'video', 'price', 'alias', 'identifier', 'status', 'created_at', 'updated_at'];
|
||||
$this->queryField = ['title' => 'like', 'alias' => 'like', 'identifier' => 'like', 'status' => '='];
|
||||
$this->media = MediaUrlService::getInstance();
|
||||
}
|
||||
@@ -55,6 +56,7 @@ class CatalogueService extends BaseService
|
||||
unset($item['category']);
|
||||
$item['cover'] = $this->media->toPublic($item['cover'] ?? '');
|
||||
$item['pdf'] = $this->media->toPublic($item['pdf'] ?? '');
|
||||
$item['video'] = $this->media->toPublic($item['video'] ?? '');
|
||||
$item['show_field'] = $this->pickUsedMaterialFields($item['price_sheet'] ?? []);
|
||||
}
|
||||
unset($item);
|
||||
@@ -76,6 +78,7 @@ class CatalogueService extends BaseService
|
||||
$info = $this->getDetail($id);
|
||||
$info->cover = $this->media->toPublic($info->cover);
|
||||
$info->pdf = $this->media->toPublic($info->pdf);
|
||||
$info->video = $this->media->toPublic($info->video);
|
||||
|
||||
$priceSheet = PriceSheetModel::where('catalogue_id', $id)
|
||||
->where('deleted_at', 0)
|
||||
@@ -134,6 +137,141 @@ class CatalogueService extends BaseService
|
||||
return $this->save($id, ['status' => (int) $status]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品 + 关联报价单:两个工作表,xlsx 由前端 ExcelJS 美化
|
||||
*/
|
||||
public function exportExcel(): array
|
||||
{
|
||||
$rows = CatalogueModel::where('deleted_at', 0)->orderByDesc('id')->get([
|
||||
'id', 'title', 'identifier', 'alias', 'category_id', 'price', 'status',
|
||||
])->toArray();
|
||||
$byId = [];
|
||||
foreach ($rows as &$row) {
|
||||
$row['status'] = (int) ($row['status'] ?? 0) === 0 ? '上架' : '下架';
|
||||
$byId[(int) $row['id']] = $row;
|
||||
}
|
||||
unset($row);
|
||||
|
||||
$ids = array_keys($byId);
|
||||
$priceRows = [];
|
||||
if (!empty($ids)) {
|
||||
$sheets = PriceSheetModel::where('deleted_at', 0)
|
||||
->whereIn('catalogue_id', $ids)
|
||||
->orderBy('catalogue_id')
|
||||
->orderBy('id')
|
||||
->get(['id', 'catalogue_id', 'specification', 'dimension', 'routine', 'stock', 'status'])
|
||||
->toArray();
|
||||
foreach ($sheets as $sheet) {
|
||||
$cat = $byId[(int) $sheet['catalogue_id']] ?? [];
|
||||
$priceRows[] = [
|
||||
'id' => $sheet['id'],
|
||||
'catalogue_id' => $sheet['catalogue_id'],
|
||||
'identifier' => $cat['identifier'] ?? '',
|
||||
'title' => $cat['title'] ?? '',
|
||||
'specification' => $sheet['specification'] ?? '',
|
||||
'dimension' => $sheet['dimension'] ?? '',
|
||||
'routine' => $sheet['routine'] ?? '',
|
||||
'stock' => (int) ($sheet['stock'] ?? -1),
|
||||
'status' => (int) ($sheet['status'] ?? 0) === 0 ? '启用' : '禁用',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'filename' => 'catalogue.xlsx',
|
||||
'title' => '商品图册',
|
||||
'sheets' => [
|
||||
[
|
||||
'title' => '商品图册',
|
||||
'sheet' => '商品',
|
||||
'columns' => [
|
||||
['key' => 'id', 'header' => 'ID', 'width' => 10, 'align' => 'center'],
|
||||
['key' => 'title', 'header' => '商品名称', 'width' => 28],
|
||||
['key' => 'identifier', 'header' => '商品编号', 'width' => 16],
|
||||
['key' => 'alias', 'header' => '别名', 'width' => 24],
|
||||
['key' => 'category_id', 'header' => '分类ID', 'width' => 12, 'align' => 'center'],
|
||||
['key' => 'price', 'header' => '参考价', 'width' => 14, 'align' => 'right'],
|
||||
['key' => 'status', 'header' => '状态', 'width' => 10, 'align' => 'center'],
|
||||
],
|
||||
'rows' => $rows,
|
||||
],
|
||||
[
|
||||
'title' => '关联报价单',
|
||||
'sheet' => '报价单',
|
||||
'subtitle' => '按商品编号回写;库存 -1 表示不限',
|
||||
'columns' => [
|
||||
['key' => 'id', 'header' => 'ID', 'width' => 10, 'align' => 'center'],
|
||||
['key' => 'catalogue_id', 'header' => '商品ID', 'width' => 12, 'align' => 'center'],
|
||||
['key' => 'identifier', 'header' => '商品编号', 'width' => 16],
|
||||
['key' => 'title', 'header' => '商品名称', 'width' => 24],
|
||||
['key' => 'specification', 'header' => '规格', 'width' => 20],
|
||||
['key' => 'dimension', 'header' => '尺寸', 'width' => 16],
|
||||
['key' => 'routine', 'header' => '常规价', 'width' => 14, 'align' => 'right'],
|
||||
['key' => 'stock', 'header' => '库存', 'width' => 10, 'align' => 'center'],
|
||||
['key' => 'status', 'header' => '状态', 'width' => 10, 'align' => 'center'],
|
||||
],
|
||||
'rows' => $priceRows,
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入商品 + 报价单:先落商品,再按编号挂规格
|
||||
*/
|
||||
public function importRows(array $rows, array $priceSheets = []): array
|
||||
{
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
$priceCreated = 0;
|
||||
$priceUpdated = 0;
|
||||
$now = time();
|
||||
DB::connection('business')->beginTransaction();
|
||||
try {
|
||||
foreach ($rows as $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$identifier = trim((string) ($row['identifier'] ?? $row['商品编号'] ?? ''));
|
||||
$title = trim((string) ($row['title'] ?? $row['商品名称'] ?? ''));
|
||||
if ($title === '') {
|
||||
continue;
|
||||
}
|
||||
$payload = [
|
||||
'title' => $title,
|
||||
'identifier' => $identifier,
|
||||
'alias' => (string) ($row['alias'] ?? $row['别名'] ?? ''),
|
||||
'category_id' => (int) ($row['category_id'] ?? $row['分类ID'] ?? 0),
|
||||
'price' => (string) ($row['price'] ?? $row['参考价'] ?? ''),
|
||||
'status' => $this->parseStatus($row['status'] ?? $row['状态'] ?? 0),
|
||||
'updated_at' => $now,
|
||||
];
|
||||
$exists = $identifier !== ''
|
||||
? CatalogueModel::where('identifier', $identifier)->where('deleted_at', 0)->first()
|
||||
: null;
|
||||
if (!empty($exists)) {
|
||||
CatalogueModel::where('id', $exists['id'])->update($payload);
|
||||
$updated++;
|
||||
} else {
|
||||
$payload['created_at'] = $now;
|
||||
CatalogueModel::insert($payload);
|
||||
$created++;
|
||||
}
|
||||
}
|
||||
[$priceCreated, $priceUpdated] = $this->importPriceSheets($priceSheets, $now);
|
||||
DB::connection('business')->commit();
|
||||
} catch (Exception $e) {
|
||||
DB::connection('business')->rollBack();
|
||||
$this->utils->errorThrow($e->getMessage());
|
||||
}
|
||||
return [
|
||||
'created' => $created,
|
||||
'updated' => $updated,
|
||||
'price_created' => $priceCreated,
|
||||
'price_updated' => $priceUpdated,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 报价单里真正有值的材质列
|
||||
*/
|
||||
@@ -164,7 +302,7 @@ class CatalogueService extends BaseService
|
||||
|
||||
private function normalize(array $params): array
|
||||
{
|
||||
foreach (['cover', 'pdf'] as $field) {
|
||||
foreach (['cover', 'pdf', 'video'] as $field) {
|
||||
if (array_key_exists($field, $params)) {
|
||||
$params[$field] = $this->media->firstOf($params[$field]);
|
||||
}
|
||||
@@ -190,4 +328,100 @@ class CatalogueService extends BaseService
|
||||
$this->utils->errorThrow('商品编号已存在:' . $identifier);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入报价单:优先商品编号,其次商品ID;同商品同规格同尺寸则更新
|
||||
*/
|
||||
private function importPriceSheets(array $rows, int $now): array
|
||||
{
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
foreach ($rows as $row) {
|
||||
if (!is_array($row)) {
|
||||
continue;
|
||||
}
|
||||
$catalogueId = $this->resolveCatalogueId($row);
|
||||
$specification = trim((string) ($row['specification'] ?? $row['规格'] ?? ''));
|
||||
if ($catalogueId <= 0 || $specification === '') {
|
||||
continue;
|
||||
}
|
||||
$dimension = (string) ($row['dimension'] ?? $row['尺寸'] ?? '');
|
||||
$payload = [
|
||||
'catalogue_id' => $catalogueId,
|
||||
'specification' => $specification,
|
||||
'dimension' => $dimension,
|
||||
'routine' => (string) ($row['routine'] ?? $row['常规价'] ?? ''),
|
||||
'stock' => $this->parseStock($row['stock'] ?? $row['库存'] ?? -1),
|
||||
'status' => $this->parseStatus($row['status'] ?? $row['状态'] ?? 0),
|
||||
'updated_at' => $now,
|
||||
];
|
||||
$id = (int) ($row['id'] ?? $row['ID'] ?? 0);
|
||||
$exists = $id > 0
|
||||
? PriceSheetModel::where('id', $id)->where('catalogue_id', $catalogueId)->where('deleted_at', 0)->first()
|
||||
: null;
|
||||
if (empty($exists)) {
|
||||
$exists = PriceSheetModel::where('catalogue_id', $catalogueId)
|
||||
->where('specification', $specification)
|
||||
->where('dimension', $dimension)
|
||||
->where('deleted_at', 0)
|
||||
->first();
|
||||
}
|
||||
if (!empty($exists)) {
|
||||
PriceSheetModel::where('id', $exists['id'])->update($payload);
|
||||
$updated++;
|
||||
} else {
|
||||
$payload['created_at'] = $now;
|
||||
PriceSheetModel::insert($payload);
|
||||
$created++;
|
||||
}
|
||||
}
|
||||
return [$created, $updated];
|
||||
}
|
||||
|
||||
/**
|
||||
* 报价单行挂到哪件商品:编号优先,兼容导出里的商品ID
|
||||
*/
|
||||
private function resolveCatalogueId(array $row): int
|
||||
{
|
||||
$identifier = trim((string) ($row['identifier'] ?? $row['商品编号'] ?? ''));
|
||||
if ($identifier !== '') {
|
||||
$cat = CatalogueModel::where('identifier', $identifier)->where('deleted_at', 0)->first();
|
||||
if (!empty($cat)) {
|
||||
return (int) $cat['id'];
|
||||
}
|
||||
}
|
||||
$id = (int) ($row['catalogue_id'] ?? $row['商品ID'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
return 0;
|
||||
}
|
||||
$exists = CatalogueModel::where('id', $id)->where('deleted_at', 0)->exists();
|
||||
return $exists ? $id : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Excel 状态列可能是「上架/下架」或 0/1,统一成库里的数字
|
||||
*/
|
||||
private function parseStatus(mixed $value): int
|
||||
{
|
||||
$raw = trim((string) $value);
|
||||
if (in_array($raw, ['上架', '启用', '正常', '0', ''], true)) {
|
||||
return 0;
|
||||
}
|
||||
if (in_array($raw, ['下架', '禁用', '1'], true)) {
|
||||
return 1;
|
||||
}
|
||||
return ((int) $raw) === 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 库存:空 / 不限 → -1
|
||||
*/
|
||||
private function parseStock(mixed $value): int
|
||||
{
|
||||
$raw = trim((string) $value);
|
||||
if ($raw === '' || in_array($raw, ['不限', '无限', '-1'], true)) {
|
||||
return -1;
|
||||
}
|
||||
return (int) $raw;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user