Files
lgp-admin-plus-api/app/Service/business/PriceSheetService.php
LQ bcf54c2727 初始化
缺陷:主题配色需要优化整体的同风格
2026-08-14 23:21:21 +08:00

215 lines
6.4 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\Service\business;
use App\BaseApp\BaseService;
use App\Models\business\CatalogueModel;
use App\Models\business\PriceSheetModel;
use Exception;
use Illuminate\Support\Facades\DB;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
/**
* 报价单(商品规格 + 常规价)
*
* 老接口靠 specification-1a / dimension-1b / routine-1b 这种动态键接收多行表单,
* 数量还得靠 count($params) 猜,多一个无关字段就会多循环一轮。
* 新接口收 rows 数组,并提供 saveRows 一次性覆盖某商品的全部规格行——抽屉里就是这个语义。
*/
class PriceSheetService extends BaseService
{
public function __construct()
{
parent::__construct();
$this->model = PriceSheetModel::class;
$this->selectField = array_merge(
['id', 'catalogue_id', 'specification', 'dimension'],
PriceSheetModel::MATERIAL_FIELDS,
['status', 'created_at', 'updated_at']
);
$this->queryField = ['catalogue_id' => '=', 'specification' => 'like', 'status' => '='];
$this->orderBy = ['name' => 'id', 'sort' => 'asc'];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function list(): array
{
return $this->getPageList();
}
public function option(): mixed
{
$this->optionField = ['id', 'specification as name'];
return $this->getOption();
}
/**
* @throws Exception
*/
public function detail($id): mixed
{
return $this->getDetail($id);
}
/**
* 新增单行或多行rows
* @throws Exception
*/
public function create($params): mixed
{
$catalogueId = (int) ($params['catalogue_id'] ?? 0);
$this->assertCatalogue($catalogueId);
$rows = $this->normalizeRows($catalogueId, $params);
if (empty($rows)) {
$this->utils->errorThrow('请至少填写一行规格');
}
if (count($rows) === 1) {
return $this->insert($rows[0]);
}
return PriceSheetModel::insert($rows);
}
/**
* @throws Exception
*/
public function update($id, $params): mixed
{
unset($params['rows']);
return $this->save($id, $params);
}
/**
* @throws Exception
*/
public function delete($id): mixed
{
return $this->del(is_array($id) ? $id : [$id]);
}
/**
* @throws Exception
*/
public function status($id, $status): mixed
{
return $this->save($id, ['status' => (int) $status]);
}
/**
* 覆盖式保存某商品的全部规格行:带 id 的更新,不带的新增,界面上被删掉的软删。
* 一次事务完成,避免中途失败留下半套规格。
* @throws Exception
*/
public function saveRows(int $catalogueId, array $rows): bool
{
$this->assertCatalogue($catalogueId);
$now = time();
$keepIds = [];
DB::connection('business')->beginTransaction();
try {
foreach ($rows as $row) {
$payload = $this->pickRowFields($row);
if (trim((string) ($payload['specification'] ?? '')) === '') {
continue;
}
$payload['catalogue_id'] = $catalogueId;
$id = (int) ($row['id'] ?? 0);
if ($id > 0) {
$payload['updated_at'] = $now;
PriceSheetModel::where('id', $id)->where('catalogue_id', $catalogueId)->update($payload);
$keepIds[] = $id;
} else {
$payload['created_at'] = $now;
$keepIds[] = (int) PriceSheetModel::insertGetId($payload);
}
}
PriceSheetModel::where('catalogue_id', $catalogueId)
->where('deleted_at', 0)
->when(!empty($keepIds), fn ($q) => $q->whereNotIn('id', $keepIds))
->update(['deleted_at' => $now, 'updated_at' => $now]);
DB::connection('business')->commit();
} catch (Exception $e) {
DB::connection('business')->rollBack();
$this->utils->errorThrow($e->getMessage());
}
return true;
}
/**
* 某商品的全部规格行,供报价单抽屉回填
*/
public function rowsOf(int $catalogueId): array
{
return PriceSheetModel::where('catalogue_id', $catalogueId)
->where('deleted_at', 0)
->orderBy('id')
->get($this->selectField)
->toArray();
}
/**
* 兼容单行字段与 rows 数组两种入参
*/
private function normalizeRows(int $catalogueId, array $params): array
{
$now = time();
$source = [];
if (!empty($params['rows']) && is_array($params['rows'])) {
$source = $params['rows'];
} elseif (trim((string) ($params['specification'] ?? '')) !== '') {
$source = [$params];
}
$rows = [];
foreach ($source as $row) {
if (!is_array($row)) {
continue;
}
$payload = $this->pickRowFields($row);
if (trim((string) ($payload['specification'] ?? '')) === '') {
continue;
}
$payload['catalogue_id'] = $catalogueId;
$payload['created_at'] = $now;
$rows[] = $payload;
}
return $rows;
}
/**
* 只取表里真实存在的列,把前端多传的字段挡在外面
*/
private function pickRowFields(array $row): array
{
$allowed = array_merge(['specification', 'dimension'], PriceSheetModel::MATERIAL_FIELDS);
$payload = [];
foreach ($allowed as $field) {
if (array_key_exists($field, $row)) {
$payload[$field] = is_scalar($row[$field]) ? (string) $row[$field] : '';
}
}
return $payload;
}
/**
* @throws Exception
*/
private function assertCatalogue(int $catalogueId): void
{
if ($catalogueId <= 0) {
$this->utils->errorThrow('请选择商品');
}
$exists = CatalogueModel::where('id', $catalogueId)->where('deleted_at', 0)->exists();
if (!$exists) {
$this->utils->errorThrow('商品不存在');
}
}
}