Files
fdesk/app/common/service/VehVehicleSkuService.php
T
2025-09-01 10:08:51 +08:00

349 lines
13 KiB
PHP
Raw 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\common\service;
use app\common\logic\Fingerprint;
use app\common\logic\ModelNaming;
use app\common\logic\SkuCodeBuilder;
use app\common\validate\VehVehicleSkuValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\VehVehicleSku;
use support\Request;
class VehVehicleSkuService
{
use CrudServiceTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehVehicleSku::class;
/**
* 验证器
*/
protected $validator = VehVehicleSkuValidate::class;
/**
* 获取验证器
*/
public function getValidator()
{
return new $this->validator;
}
// 枚举
private const MAPS = [
'BODY' => [
'SEDAN' => '三厢轿车', 'SUV'=>'SUV', 'HB'=>'两厢/掀背', 'MPV'=>'MPV', 'PICKUP'=>'皮卡'
],
'DRIVE' => [
'FWD'=>'前驱', 'RWD'=>'后驱', 'AWD'=>'四驱(AWD)', '4WD'=>'四驱(4WD)'
],
'MOTOR_LAYOUT' => [
'FWD'=>'前置单电机', 'RWD'=>'后置单电机', 'AWD'=>'双电机四驱', 'DM-I'=>'DM-i', 'DM-P'=>'DM-p'
],
'FUEL' => [
'GAS'=>'汽油', 'HEV'=>'油电混动', 'PHEV'=>'插电混动', 'EV'=>'纯电', 'EREV'=>'增程'
],
'TRANS' => [
'MT'=>'手动', 'AT'=>'自动', 'CVT'=>'无级', 'DCT'=>'双离合', '1SPEED'=>'单速'
],
'RANGE_STD' => [
'CLTC'=>'CLTC', 'WLTP'=>'WLTP', 'EPA'=>'EPA', 'NEDC'=>'NEDC'
],
'EMISSION' => [
'CHN6'=>'国六', 'EURO6'=>'欧6', 'EPA'=>'美国EPA'
],
];
// *_code取中文
public function label(string $dict, ?string $code): ?string
{
if ($code === null || $code === '') return null;
$dict = strtoupper($dict);
$code = strtoupper($code);
return self::MAPS[$dict][$code] ?? $code;
}
// 静态映射把 *_code → 中文
private function backfill(array $d): array
{
$d['body_type'] = $this->label('BODY', $d['body_type_code']);
$d['drive_type'] = $this->label('DRIVE', $d['drive_type_code']);
$d['motor_layout'] = $this->label('MOTOR_LAYOUT', $d['motor_layout_code']);
$d['fuel_type'] = $this->label('FUEL', $d['fuel_type_code']);
$d['transmission'] = $this->label('TRANS', $d['transmission_code']);
$d['range_std'] = $this->label('RANGE_STD', $d['range_std_code']);
$d['emission_std'] = $this->label('EMISSION', $d['emission_std_code']);
return $d;
}
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
{
$p = $request->all();
$config = [];
$config['model'] = $this->modelClass;
switch ($scene) {
case 'default':
$config['where']['is_active'] = 1;
$config['order']['sort'] = 'desc';
$config['order']['id'] = 'desc';
break;
case 'index':
$config['where']['is_active'] = 1;
$config['order']['sort'] = 'desc';
$config['order']['id'] = 'desc';
break;
case 'show':
$config['where']['id'] = $p['id'];
$config['where']['is_active'] = 1;
break;
case 'store':
break;
case 'update':
$config['where']['id'] = $p['id'];
break;
case 'destroy':
$config['where']['id'] = $p['id'];
break;
}
return $config;
}
public function beforeServiceStore($data, Request $request)
{
$data = $this->backfill($data);
// 未提供时自动生成;若你想“强制覆盖人工输入”,可去掉 isset 判断
if (empty($data['model_code'])) {
$data['model_code'] = ModelNaming::buildModelCode($data);
}
if (empty($data['model_name'])) {
$data['model_name'] = ModelNaming::buildModelName($data);
}
// 填充系统字段
$data['sku_code'] = SkuCodeBuilder::build($data);
$data['corp_id'] = 0;
$data['created_by'] = $request->user->uid;
$data['updated_by'] = $request->user->uid;
// 指纹
$data['fingerprint'] = Fingerprint::makeFromArray($data);
return $data;
}
protected function afterServiceStore($res)
{
return $res;
}
public function beforeServiceUpdate($data, Request $request)
{
$data = $this->backfill($data);
// 未提供时自动生成;若你想“强制覆盖人工输入”,可去掉 isset 判断
if (empty($data['model_code'])) {
$data['model_code'] = ModelNaming::buildModelCode($data);
}
if (empty($data['model_name'])) {
$data['model_name'] = ModelNaming::buildModelName($data);
}
// 填充系统字段
$data['updated_by'] = $request->user->uid;
// 指纹
$data['fingerprint'] = Fingerprint::makeFromArray($data);
return $data;
}
protected function afterServiceUpdate($res)
{
return $res;
}
/** SKU 字段名 → dict 名(用于 i18n 取词 & 必填校验) */
protected static array $SKU_FIELD_TO_DICT = [
'brand_code' => 'BRAND',
'series_code' => 'SERIES',
'model_code' => 'MODEL',
'trim_code' => 'TRIM',
'trim_level_code' => 'TRIM_LEVEL',
'edition_code' => 'EDITION',
'fuel_type_code' => 'FUEL',
'drive_type_code' => 'DRIVE',
'transmission_code' => 'TRANS',
'motor_layout_code' => 'MOTOR_LAYOUT',
'body_type_code' => 'BODY',
'range_std_code' => 'RANGE_STD',
'emission_std_code' => 'EMISSION',
'color_exterior_code'=> 'COLOR',
'color_interior_code'=> 'COLOR',
];
/** 创建 SKU(含指纹与字典校验) */
public static function create(array $p, int $userId=0, int $corpId=0): VehicleSku
{
// SkuValidator::validateForCreate($p);
// 必填字典:由映射表控制(一般 BRAND/SERIES/FUEL)
$requiredDicts = MappingService::requiredDicts();
foreach (self::$SKU_FIELD_TO_DICT as $field => $dict) {
if (!MappingService::enabled($dict)) continue;
$isRequired = in_array($dict, $requiredDicts, true);
if ($isRequired) {
DictService::ensureExists($dict, $p[$field] ?? null, $field);
}
}
// 填充系统字段
$now = time();
$p['sku_code'] = $p['sku_code'] ?? ('SKU'.date('Ymd').'-'.substr(bin2hex(random_bytes(3)),0,6));
$p['corp_id'] = $p['corp_id'] ?? $corpId;
$p['created_by'] = $p['created_by'] ?? $userId;
$p['updated_by'] = $p['updated_by'] ?? $userId;
$p['created_at'] = $p['created_at'] ?? $now;
$p['updated_at'] = $p['updated_at'] ?? $now;
// 指纹
$p['fingerprint'] = Fingerprint::make($p /*, $scopeCorp=true/false*/);
return DB::connection()->transaction(function () use ($p) {
$sku = new VehicleSku($p);
$sku->save();
return $sku;
});
}
/** 更新 SKU(部分字段;指纹随事实变动而刷新) */
public static function update(int $id, array $p, int $userId=0): VehicleSku
{
SkuValidator::validateForUpdate($p);
$sku = VehicleSku::findOrFail($id);
// 若传入了必填 dict 的 code,需要确认字典存在
$requiredDicts = MappingService::requiredDicts();
foreach (self::$SKU_FIELD_TO_DICT as $field => $dict) {
if (!array_key_exists($field, $p)) continue;
if (!MappingService::enabled($dict)) continue;
$isRequired = in_array($dict, $requiredDicts, true);
if ($isRequired) {
DictService::ensureExists($dict, $p[$field], $field);
} else {
// 可选的:若传了 code 则也校验存在
if (($p[$field] ?? null) !== null && $p[$field] !== '') {
$exists = \app\model\DictTerm::where('dict',$dict)->where('code',$p[$field])->exists();
if (!$exists) throw new \InvalidArgumentException("字典不存在:{$dict}.{$p[$field]}");
}
}
}
// 刷新系统字段
$p['updated_by'] = $userId;
$p['updated_at'] = time();
// 赋值保存
$sku->fill($p);
// 只要影响到指纹的事实字段变动,就重算指纹
$fingerFields = [
'brand_code','series_code','model_year','fuel_type_code',
'drive_type_code','transmission_code','body_type_code',
'engine_disp_l','engine_turbo','battery_kwh','range_km',
'range_std_code','emission_std_code',
'corp_id'
];
foreach ($fingerFields as $f) {
if (array_key_exists($f, $p)) {
$sku->fingerprint = Fingerprint::make($sku->toArray());
break;
}
}
$sku->save();
return $sku;
}
/** 详情(带 i18n label 与标准标题) */
public static function detail(int $id, string $locale='zh-CN'): array
{
$sku = VehicleSku::findOrFail($id);
$data = $sku->toArray();
$labelOf = function(string $field) use ($data, $locale) {
$dict = self::$SKU_FIELD_TO_DICT[$field] ?? null;
if (!$dict) return null;
$code = $data[$field] ?? null;
// 若是品牌/车系,允许以中文兜底
$fallback = null;
if ($field === 'brand_code') $fallback = $data['brand_name'] ?? null;
if ($field === 'series_code') $fallback = $data['series_name'] ?? null;
// 版型/等级/特别版允许中文兜底
if ($field === 'trim_code') $fallback = $data['trim'] ?? null;
if ($field === 'trim_level_code') $fallback = $data['trim_level'] ?? null;
if ($field === 'edition_code') $fallback = $data['edition_name'] ?? null;
// 颜色兜底中文
if ($field === 'color_exterior_code') $fallback = $data['color_exterior_text'] ?? null;
if ($field === 'color_interior_code') $fallback = $data['color_interior_text'] ?? null;
return \app\service\DictService::label($dict, $code, $locale, $fallback);
};
$i18n = [
'brand_label' => $labelOf('brand_code'),
'series_label' => $labelOf('series_code'),
'model_label' => \app\service\DictService::label('MODEL', $data['model_code'] ?? null, $locale, $data['model_name'] ?? null),
'trim_label' => $labelOf('trim_code'),
'trim_level_label' => $labelOf('trim_level_code'),
'edition_label' => $labelOf('edition_code'),
'fuel_label' => $labelOf('fuel_type_code'),
'drive_label' => $labelOf('drive_type_code'),
'trans_label' => $labelOf('transmission_code'),
'motor_layout_label' => $labelOf('motor_layout_code'),
'body_label' => $labelOf('body_type_code'),
'range_std_label' => $labelOf('range_std_code'),
'emission_label' => $labelOf('emission_std_code'),
'color_exterior_label' => $labelOf('color_exterior_code'),
'color_interior_label' => $labelOf('color_interior_code'),
'listing_title' => TitleBuilder::build($data, $locale),
];
return ['sku'=>$data, 'i18n'=>$i18n];
}
/** 列表查询(支持基础筛选 & i18n 列) */
public static function list(array $q, string $locale='zh-CN', int $page=1, int $pageSize=20): array
{
$builder = VehicleSku::query();
// 常用筛选
if (!empty($q['brand_code'])) $builder->where('brand_code', $q['brand_code']);
if (!empty($q['series_code'])) $builder->where('series_code', $q['series_code']);
if (!empty($q['fuel_type_code'])) $builder->where('fuel_type_code', $q['fuel_type_code']);
if (!empty($q['model_year'])) $builder->where('model_year', (int)$q['model_year']);
if (isset($q['is_active'])) $builder->where('is_active', (int)$q['is_active']);
$builder->orderByDesc('created_at');
$total = (clone $builder)->count();
$rows = $builder->forPage($page, $pageSize)->get()->toArray();
// 附加 i18n 字段(轻量)
foreach ($rows as &$row) {
$row['brand_label'] = DictService::label('BRAND', $row['brand_code'] ?? null, $locale, $row['brand_name'] ?? null);
$row['series_label'] = DictService::label('SERIES', $row['series_code'] ?? null, $locale, $row['series_name'] ?? null);
$row['fuel_label'] = DictService::label('FUEL', $row['fuel_type_code'] ?? null, $locale, null);
$row['listing_title']= TitleBuilder::build($row, $locale);
}
return ['total'=>$total, 'list'=>$rows, 'page'=>$page, 'page_size'=>$pageSize];
}
}