备货单

This commit is contained in:
mzl
2025-09-02 09:36:37 +08:00
parent 7ded55ca0e
commit 476921e6b8
6 changed files with 161 additions and 184 deletions
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\StockOrdersService;
class StockOrdersController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new StockOrdersService();
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
// protected function indexFormat($data)
// {
// if (isset($data['created_at']))
// $data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
// if (isset($data['updated_at']))
// $data['updated_at'] = date('Y-m-d H:i:s', $data['updated_at']);
// return $data;
// }
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\StockOrders;
class StockOrdersLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = StockOrders::class;
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace app\common\model;
use support\Model;
class StockOrders extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'stock_orders';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = true;
protected $dateFormat = 'U';
/**
* 允许自动填充模型字段
*/
protected $fillable = ['id', 'order_no', 'pi_no', 'biz_date', 'salesperson_id', 'salesperson_name_snapshot', 'clearance_country_id', 'clearance_country_name_snapshot', 'ali_order_no', 'customer_source_id', 'customer_source_name_snapshot', 'customer_id', 'customer_name_snapshot', 'customer_country_id', 'customer_country_name_snapshot', 'declarant_name', 'eta_ship_date', 'shipping_method', 'cif_total_amount', 'domestic_port_id', 'domestic_port_name_snapshot', 'trade_term_id', 'trade_term_name_snapshot', 'clearance_port_id', 'clearance_port_name_snapshot', 'latest_arrival_date', 'contract_exchange_rate', 'status', 'remark', 'created_at', 'updated_at', 'deleted_at'];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace app\common\service;
use app\common\validate\StockOrdersValidate;
use app\common\traits\crud\CrudServiceTrait;
use app\common\model\StockOrders;
class StockOrdersService
{
use CrudServiceTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = StockOrders::class;
/**
* 验证器
*/
protected $validator = StockOrdersValidate::class;
/**
* 获取验证器
*/
public function getValidator()
{
return new $this->validator;
}
}
+2 -184
View File
@@ -115,7 +115,7 @@ class VehVehicleSkuService
public function beforeServiceStore($data, Request $request)
{
$data = $this->backfill($data);
// $data = $this->backfill($data);
if (empty($data['model_code'])) {
$data['model_code'] = ModelNaming::buildModelCode($data);
}
@@ -140,7 +140,7 @@ class VehVehicleSkuService
public function beforeServiceUpdate($data, Request $request)
{
$data = $this->backfill($data);
// $data = $this->backfill($data);
if (empty($data['model_code'])) {
$data['model_code'] = ModelNaming::buildModelCode($data);
}
@@ -159,186 +159,4 @@ class VehVehicleSkuService
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];
}
}
@@ -0,0 +1,29 @@
<?php
namespace app\common\validate;
use think\Validate;
class StockOrdersValidate extends Validate
{
// 规则
protected $rule = [
];
// 提示
protected $message = [
];
// 场景
protected $scene = [
'store' => [
],
'update' => [
]
];
}