diff --git a/app/admin/controller/BrandController.php b/app/admin/controller/BrandController.php
new file mode 100644
index 0000000..f416d9d
--- /dev/null
+++ b/app/admin/controller/BrandController.php
@@ -0,0 +1,53 @@
+service = new BrandService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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']);
+ if (!empty($data['logo']))
+ $data['logo_full'] = (new OssService)->generatePrivateUrl($data['logo']);
+ return $data;
+ }
+
+ /**
+ * 数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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']);
+ if (empty($data['logo']))
+ $data['logo_full'] = (new OssService)->generatePrivateUrl($data['logo']);
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/BrandSeriesController.php b/app/admin/controller/BrandSeriesController.php
new file mode 100644
index 0000000..c2d95f7
--- /dev/null
+++ b/app/admin/controller/BrandSeriesController.php
@@ -0,0 +1,48 @@
+service = new BrandSeriesService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ }
+
+ /**
+ * 数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/SysAccountController.php b/app/admin/controller/SysAccountController.php
new file mode 100644
index 0000000..64398bb
--- /dev/null
+++ b/app/admin/controller/SysAccountController.php
@@ -0,0 +1,52 @@
+service = new SysAccountService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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']);
+ $data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name');
+ return $data;
+ }
+
+ /**
+ * 数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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']);
+ $data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name');
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/SysCurrencyController.php b/app/admin/controller/SysCurrencyController.php
new file mode 100644
index 0000000..0e96169
--- /dev/null
+++ b/app/admin/controller/SysCurrencyController.php
@@ -0,0 +1,52 @@
+service = new SysCurrencyService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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']);
+ if (isset($data['last_updated']))
+ $data['last_updated'] = date('Y-m-d H:i:s', $data['last_updated']);
+ return $data;
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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']);
+ if (isset($data['last_updated']))
+ $data['last_updated'] = date('Y-m-d H:i:s', $data['last_updated']);
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/SysDictController.php b/app/admin/controller/SysDictController.php
new file mode 100644
index 0000000..34be3e1
--- /dev/null
+++ b/app/admin/controller/SysDictController.php
@@ -0,0 +1,78 @@
+service = new SysDictService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function indexFormat($data)
+ {
+ if (isset($data['sysDictItem']))
+ $data['sysDictItem'] = SysDictItem::where('dict_id',$data['id'])->get();
+ 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;
+ }
+
+ /**
+ * 数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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']);
+ $data['sysDictItem'] = SysDictItem::where('dict_id',$data['id'])->get();
+ return $data;
+ }
+
+
+
+ public function listScopeFormat($data)
+ {
+ $rdata = [];
+ foreach ($data as $item) {
+ $rdata[$item['dict_code']] = $item['sysDictItem'];
+ }
+ return $rdata;
+ }
+
+ public function listScope(Request $request)
+ {
+ try {
+ $raw = $this->service->serviceListAllScope($request);
+ $data = $this->transformData($raw, method_exists($this, 'listScopeFormat')
+ ? [$this, 'listScopeFormat']
+ : null);
+ return $this->success($data);
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/SysDictItemController.php b/app/admin/controller/SysDictItemController.php
new file mode 100644
index 0000000..9262933
--- /dev/null
+++ b/app/admin/controller/SysDictItemController.php
@@ -0,0 +1,48 @@
+service = new SysDictItemService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ }
+
+ /**
+ * 数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/SysPortController.php b/app/admin/controller/SysPortController.php
new file mode 100644
index 0000000..d98577e
--- /dev/null
+++ b/app/admin/controller/SysPortController.php
@@ -0,0 +1,53 @@
+service = new SysPortService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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']);
+ if (isset($data['country_id']))
+ if (isset($data['country_id']))
+ $data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr');
+ return $data;
+ }
+
+ /**
+ * 数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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']);
+ $data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr');
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/controller/VehColorController.php b/app/admin/controller/VehColorController.php
new file mode 100644
index 0000000..0d208ae
--- /dev/null
+++ b/app/admin/controller/VehColorController.php
@@ -0,0 +1,33 @@
+service = new VehColorService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ // }
+}
\ No newline at end of file
diff --git a/app/admin/controller/VehModificationController.php b/app/admin/controller/VehModificationController.php
new file mode 100644
index 0000000..fc057e1
--- /dev/null
+++ b/app/admin/controller/VehModificationController.php
@@ -0,0 +1,48 @@
+service = new VehModificationService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ }
+
+ /**
+ * 数据格式化
+ *
+ * @param array $data
+ * @return array
+ */
+ protected function showFormat($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;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/logic/BrandLogic.php b/app/admin/logic/BrandLogic.php
new file mode 100644
index 0000000..6b12364
--- /dev/null
+++ b/app/admin/logic/BrandLogic.php
@@ -0,0 +1,17 @@
+validator;
+ }
+
+ /**
+ * 构建查询条件
+ */
+
+ protected function buildQueryConfig(Request $request, string $scene = 'default'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'index':
+ // ====== ====== 排序 ====== ======
+ $config['order']['sort'] = 'desc';
+ $config['order']['id'] = 'desc';
+
+ // ====== ====== 筛选 ====== ======
+ $config['where']['brand_id'] = $p['brand_id'];
+ // 状态
+ if (isset($p['status']) && in_array($p['status'], [0,1])) {
+ $config['where']['status'] = $p['status'];
+ }
+ // 关键字
+ if (isset($p['keyword']) && $p['keyword']) {
+ $k = '%' . $p['keyword'] . '%';
+ foreach (['series_code','series_name'] as $col) {
+ $config['orWhere'][] = [$col, 'like', $k];
+ }
+ }
+ //$config['where']['status'] = 1;
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ //$config['where']['status'] = 1;
+ break;
+ case 'store':
+ break;
+ case 'update':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'destroy':
+ $config['where']['id'] = $p['id'];
+ break;
+ }
+
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/BrandService.php b/app/admin/service/BrandService.php
new file mode 100644
index 0000000..c35df96
--- /dev/null
+++ b/app/admin/service/BrandService.php
@@ -0,0 +1,79 @@
+validator;
+ }
+
+ /**
+ * 构建查询条件
+ */
+
+ protected function buildQueryConfig(Request $request, string $scene = 'default'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'index':
+ // ====== ====== 排序 ====== ======
+ $config['order']['sort'] = 'desc';
+ $config['order']['id'] = 'desc';
+
+ // ====== ====== 筛选 ====== ======
+ // 状态
+ if (isset($p['status']) && in_array($p['status'], [0,1])) {
+ $config['where']['status'] = $p['status'];
+ }
+ // 关键字
+ if (isset($p['keyword']) && $p['keyword']) {
+ $k = '%' . $p['keyword'] . '%';
+ foreach (['brand_code','brand_name'] as $col) {
+ $config['orWhere'][] = [$col, 'like', $k];
+ }
+ }
+ //$config['where']['status'] = 1;
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ //$config['where']['status'] = 1;
+ break;
+ case 'store':
+ break;
+ case 'update':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'destroy':
+ $config['where']['id'] = $p['id'];
+ break;
+ }
+
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/SysAccountService.php b/app/admin/service/SysAccountService.php
new file mode 100644
index 0000000..d413778
--- /dev/null
+++ b/app/admin/service/SysAccountService.php
@@ -0,0 +1,82 @@
+validator;
+ }
+
+ /**
+ * 构建查询条件
+ */
+ protected function buildQueryConfig(Request $request, string $scene = 'default'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'index':
+ // ====== ====== 排序 ====== ======
+ $config['order']['sort'] = 'desc';
+ $config['order']['id'] = 'desc';
+
+ // ====== ====== 筛选 ====== ======
+ // 状态
+ if (isset($p['status']) && in_array($p['status'], [0,1])) {
+ $config['where']['status'] = $p['status'];
+ }
+ // 状态
+ if (isset($p['type']) && $p['type']) {
+ $config['where']['type'] = $p['type'];
+ }
+ // 关键字
+ if (isset($p['keyword']) && $p['keyword']) {
+ $k = '%' . $p['keyword'] . '%';
+ foreach (['account_name','account_number','bank_name','bank_branch','description'] as $col) {
+ $config['orWhere'][] = [$col, 'like', $k];
+ }
+ }
+ //$config['where']['status'] = 1;
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ //$config['where']['status'] = 1;
+ break;
+ case 'store':
+ break;
+ case 'update':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'destroy':
+ $config['where']['id'] = $p['id'];
+ break;
+ }
+
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/SysCurrencyService.php b/app/admin/service/SysCurrencyService.php
new file mode 100644
index 0000000..19f0529
--- /dev/null
+++ b/app/admin/service/SysCurrencyService.php
@@ -0,0 +1,61 @@
+validator;
+ }
+
+
+ /**
+ * 构造 CrudUtil 查询配置
+ */
+ protected function buildQueryConfig(Request $request, string $scene = 'default'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'default':
+ $config['order']['id'] = 'desc';
+ case 'index':
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'store':
+ break;
+ case 'update':
+ case 'destroy':
+ $config['where']['id'] = $p['id'];
+ break;
+ }
+
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/SysDictItemService.php b/app/admin/service/SysDictItemService.php
new file mode 100644
index 0000000..577b9f0
--- /dev/null
+++ b/app/admin/service/SysDictItemService.php
@@ -0,0 +1,75 @@
+validator;
+ }
+
+ /**
+ * 构建查询条件
+ */
+ protected function buildQueryConfig(Request $request, string $scene = 'index'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'index':
+ // ====== ====== 排序 ====== ======
+ $config['order']['sort'] = 'desc';
+
+ // ====== ====== 筛选 ====== ======
+
+ $config['where']['dict_id'] = $p['id'];
+ // 状态
+ if (isset($p['status']) && in_array($p['status'], [0,1])) {
+ $config['where']['status'] = $p['status'];
+ }
+ // 关键字
+ if (isset($p['keyword']) && $p['keyword']) {
+ $k = '%' . $p['keyword'] . '%';
+ foreach (['item_label','item_value','remark'] as $col) {
+ $config['orWhere'][] = [$col, 'like', $k];
+ }
+ }
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'update':
+ case 'destroy':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'store':
+ break;
+ }
+
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/SysDictService.php b/app/admin/service/SysDictService.php
new file mode 100644
index 0000000..1261c30
--- /dev/null
+++ b/app/admin/service/SysDictService.php
@@ -0,0 +1,109 @@
+validator;
+ }
+
+
+ /**
+ * 构建查询条件
+ */
+ protected function buildQueryConfig(Request $request, string $scene = 'index'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'index':
+ // ====== ====== 排序 ====== ======
+ $config['order']['id'] = 'desc';
+
+ // ====== ====== 筛选 ====== ======
+ // 状态
+ if (isset($p['status']) && in_array($p['status'], [0,1])) {
+ $config['where']['status'] = $p['status'];
+ }
+ // 关键字
+ if (isset($p['keyword']) && $p['keyword']) {
+ $k = '%' . $p['keyword'] . '%';
+ foreach (['dict_name','dict_code','description'] as $col) {
+ $config['orWhere'][] = [$col, 'like', $k];
+ }
+ }
+
+ // ====== ====== 关联 ====== ======
+ $config['with']['sysDictItem'][] = 'item_label';
+ $config['with']['sysDictItem'][] = 'item_value';
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ // ====== ====== 关联 ====== ======
+ $config['with']['sysDictItem'][] = 'item_label';
+ $config['with']['sysDictItem'][] = 'item_value';
+ break;
+ case 'update':
+ case 'destroy':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'store':
+ break;
+ case 'scope':
+ $config['order']['id'] = 'desc';
+ if (isset($p['scope']) && !empty($p['scope'])) {
+ $config['where']['id'] = ['in', explode(',', $p['scope'])];
+ }
+ $config['with']['sysDictItem'][] = 'dict_id';
+ $config['with']['sysDictItem'][] = 'item_label';
+ $config['with']['sysDictItem'][] = 'item_value';
+ break;
+ }
+
+ return $config;
+ }
+
+
+ public function serviceListAllScope(Request $request)
+ {
+ $config = $this->buildQueryConfig($request, 'scope');
+ $result = $this->logicListAll($config);
+ return $this->postProcess('ListAllScope', $result);
+ }
+
+
+ public function afterServiceListAllScope($data)
+ {
+
+ // $data->each(function (&$item) {
+
+ // });
+
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/SysPortService.php b/app/admin/service/SysPortService.php
new file mode 100644
index 0000000..7a2dfd0
--- /dev/null
+++ b/app/admin/service/SysPortService.php
@@ -0,0 +1,103 @@
+validator;
+ }
+
+ /**
+ * 构建查询条件
+ */
+
+ protected function buildQueryConfig(Request $request, string $scene = 'default'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'index':
+ // ====== ====== 排序 ====== ======
+ $config['order']['sort'] = 'desc';
+ $config['order']['id'] = 'desc';
+
+ // ====== ====== 筛选 ====== ======
+ // 状态
+ if (isset($p['status']) && in_array($p['status'], [0,1])) {
+ $config['where']['status'] = $p['status'];
+ }
+ // 关键字
+ if (isset($p['keyword']) && $p['keyword']) {
+ $k = '%' . $p['keyword'] . '%';
+ foreach (['port_code','port_name'] as $col) {
+ $config['orWhere'][] = [$col, 'like', $k];
+ }
+ }
+ //$config['where']['status'] = 1;
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ //$config['where']['status'] = 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)
+ {
+ if(empty($data['lat']))
+ unset($data['lat']);
+ if(empty($data['lng']))
+ unset($data['lng']);
+ return $data;
+ }
+
+ /**
+ * 添加前置处理
+ */
+ public function beforeServiceUpdate($data, Request $request)
+ {
+ if(empty($data['lat']))
+ unset($data['lat']);
+ if(empty($data['lng']))
+ unset($data['lng']);
+ return $data;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/VehColorService.php b/app/admin/service/VehColorService.php
new file mode 100644
index 0000000..a701ef4
--- /dev/null
+++ b/app/admin/service/VehColorService.php
@@ -0,0 +1,31 @@
+validator;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/service/VehModificationService.php b/app/admin/service/VehModificationService.php
new file mode 100644
index 0000000..6c56d9b
--- /dev/null
+++ b/app/admin/service/VehModificationService.php
@@ -0,0 +1,83 @@
+validator;
+ }
+
+ /**
+ * 构建查询条件
+ */
+
+ protected function buildQueryConfig(Request $request, string $scene = 'default'): array
+ {
+ $p = $request->all();
+
+ $config = [];
+ $config['model'] = $this->modelClass;
+ switch ($scene) {
+ case 'index':
+ // ====== ====== 排序 ====== ======
+ $config['order']['sort'] = 'desc';
+ $config['order']['id'] = 'desc';
+
+ // ====== ====== 筛选 ====== ======
+ // 状态
+ if (isset($p['status']) && in_array($p['status'], [0,1])) {
+ $config['where']['status'] = $p['status'];
+ }
+ // 状态
+ if (isset($p['type']) && $p['type']) {
+ $config['where']['type'] = $p['type'];
+ }
+ // 关键字
+ if (isset($p['keyword']) && $p['keyword']) {
+ $k = '%' . $p['keyword'] . '%';
+ foreach (['code','name'] as $col) {
+ $config['orWhere'][] = [$col, 'like', $k];
+ }
+ }
+ //$config['where']['status'] = 1;
+ break;
+ case 'show':
+ $config['where']['id'] = $p['id'];
+ //$config['where']['status'] = 1;
+ break;
+ case 'store':
+ break;
+ case 'update':
+ $config['where']['id'] = $p['id'];
+ break;
+ case 'destroy':
+ $config['where']['id'] = $p['id'];
+ break;
+ }
+
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/app/admin/validate/BrandSeriesValidate.php b/app/admin/validate/BrandSeriesValidate.php
new file mode 100644
index 0000000..31e30e2
--- /dev/null
+++ b/app/admin/validate/BrandSeriesValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/BrandValidate.php b/app/admin/validate/BrandValidate.php
new file mode 100644
index 0000000..370728d
--- /dev/null
+++ b/app/admin/validate/BrandValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/SysAccountValidate.php b/app/admin/validate/SysAccountValidate.php
new file mode 100644
index 0000000..65cc1d7
--- /dev/null
+++ b/app/admin/validate/SysAccountValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/SysCurrencyValidate.php b/app/admin/validate/SysCurrencyValidate.php
new file mode 100644
index 0000000..4aebb21
--- /dev/null
+++ b/app/admin/validate/SysCurrencyValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/SysDictItemValidate.php b/app/admin/validate/SysDictItemValidate.php
new file mode 100644
index 0000000..2d4ad58
--- /dev/null
+++ b/app/admin/validate/SysDictItemValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/SysDictValidate.php b/app/admin/validate/SysDictValidate.php
new file mode 100644
index 0000000..bdb6d1e
--- /dev/null
+++ b/app/admin/validate/SysDictValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/SysPortValidate.php b/app/admin/validate/SysPortValidate.php
new file mode 100644
index 0000000..26cb9cd
--- /dev/null
+++ b/app/admin/validate/SysPortValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/VehColorValidate.php b/app/admin/validate/VehColorValidate.php
new file mode 100644
index 0000000..1c619ec
--- /dev/null
+++ b/app/admin/validate/VehColorValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/admin/validate/VehModificationValidate.php b/app/admin/validate/VehModificationValidate.php
new file mode 100644
index 0000000..805b049
--- /dev/null
+++ b/app/admin/validate/VehModificationValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/common/controller/PresetController.php b/app/common/controller/PresetController.php
index 37073c4..0d3ebf1 100644
--- a/app/common/controller/PresetController.php
+++ b/app/common/controller/PresetController.php
@@ -3,6 +3,15 @@
namespace app\common\controller;
use app\admin\service\RoleService;
+use app\common\service\BrandSeriesService;
+use app\common\service\BrandService;
+use app\common\service\SysAccountService;
+use app\common\service\SysCurrencyService;
+use app\common\service\SysDictItemService;
+use app\common\service\SysDictService;
+use app\common\service\SysPortService;
+use app\common\service\VehColorService;
+use app\common\service\VehModificationService;
use support\Request;
use app\common\service\CorpService;
use app\common\service\CorpFeishuAppService;
@@ -76,6 +85,99 @@ class PresetController extends BaseController
}
}
+ public function currency()
+ {
+ try {
+ $result = (new SysCurrencyService)->getList();
+ return $this->success($result, '获取货币列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function brand()
+ {
+ try {
+ $result = (new BrandService)->getList();
+ return $this->success($result, '获取品牌列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function series(Request $request)
+ {
+ try {
+ $params = $request->all();
+ $result = (new BrandSeriesService)->getList($params);
+ return $this->success($result, '获取车系列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function account()
+ {
+ try {
+ $result = (new SysAccountService)->getList();
+ return $this->success($result, '获取账号列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function dict()
+ {
+ try {
+ $result = (new SysDictService)->getList();
+ return $this->success($result, '获取字典列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function dictItem(Request $request)
+ {
+ try {
+ $params = $request->all();
+ $result = (new SysDictItemService)->getList($params);
+ return $this->success($result, '获取字典项列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function port()
+ {
+ try {
+ $result = (new SysPortService)->getList();
+ return $this->success($result, '获取港口列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function color(Request $request)
+ {
+ try {
+ $params = $request->all();
+ $result = (new VehColorService)->getList($params);
+ return $this->success($result, '获取颜色列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function modification()
+ {
+ try {
+ $result = (new VehModificationService)->getList();
+ return $this->success($result, '获取货币列表');
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
public function cacheClear()
{
diff --git a/app/common/controller/StockOrdersController.php b/app/common/controller/StockOrdersController.php
new file mode 100644
index 0000000..4bb5a50
--- /dev/null
+++ b/app/common/controller/StockOrdersController.php
@@ -0,0 +1,33 @@
+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;
+ // }
+}
\ No newline at end of file
diff --git a/app/common/controller/VehDictI18nController.php b/app/common/controller/VehDictI18nController.php
new file mode 100644
index 0000000..6a87c9f
--- /dev/null
+++ b/app/common/controller/VehDictI18nController.php
@@ -0,0 +1,33 @@
+service = new VehDictI18nService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ // }
+}
\ No newline at end of file
diff --git a/app/common/controller/VehDictMappingController.php b/app/common/controller/VehDictMappingController.php
new file mode 100644
index 0000000..d1a1dfe
--- /dev/null
+++ b/app/common/controller/VehDictMappingController.php
@@ -0,0 +1,33 @@
+service = new VehDictMappingService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ // }
+}
\ No newline at end of file
diff --git a/app/common/controller/VehVehicleListingController.php b/app/common/controller/VehVehicleListingController.php
new file mode 100644
index 0000000..59d49aa
--- /dev/null
+++ b/app/common/controller/VehVehicleListingController.php
@@ -0,0 +1,33 @@
+service = new VehVehicleListingService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ // }
+}
\ No newline at end of file
diff --git a/app/common/controller/VehVehicleSkuController.php b/app/common/controller/VehVehicleSkuController.php
new file mode 100644
index 0000000..3272f28
--- /dev/null
+++ b/app/common/controller/VehVehicleSkuController.php
@@ -0,0 +1,204 @@
+service = new VehVehicleSkuService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ }
+
+ protected function showFormat($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;
+ }
+
+
+ public function store(Request $request)
+ {
+ try {
+ $data = $this->validate($this->service->getValidator(), $request->post(), 'store');
+ $res = $this->service->serviceStore($request, $data);
+ return $this->success($res, '创建成功');
+ } catch (\PDOException $e) {
+ $errorCode = $e->getCode();
+ $errorMessage = $e->getMessage();
+ if ($errorCode == '23000') {
+ if (strpos($errorMessage, "Duplicate entry") !== false && strpos($errorMessage, "uk_fingerprint") !== false) {
+ return $this->error("该车辆指纹已存在,请勿重复提交");
+ }
+ // 其他类型的完整性约束错误
+ throw new BusinessException("数据完整性错误", 0, $e);
+ }
+ // 重新抛出其他类型的异常
+ throw $e;
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+ public function update(Request $request)
+ {
+ try {
+ $data = $this->validate($this->service->getValidator(), $request->post(), 'update');
+ $res = $this->service->serviceUpdate($request, $data);
+ return $this->success([], '更新成功');
+ } catch (\PDOException $e) {
+ $errorCode = $e->getCode();
+ $errorMessage = $e->getMessage();
+ if ($errorCode == '23000') {
+ if (strpos($errorMessage, "Duplicate entry") !== false && strpos($errorMessage, "uk_fingerprint") !== false) {
+ return $this->error("该车辆指纹已存在,请勿重复提交");
+ }
+ // 其他类型的完整性约束错误
+ throw new BusinessException("数据完整性错误", 0, $e);
+ }
+ // 重新抛出其他类型的异常
+ throw $e;
+ } catch (\Throwable $e) {
+ return $this->error($e->getMessage());
+ }
+ }
+
+
+ public function fields_desc(Request $request)
+ {
+ $data = [
+ 'sku_code' , // 'SKU编码,系统生成',
+ 'fingerprint' , // '规格指纹(sha256)去重',
+ 'brand_code' , // '品牌代码,如 BYD、HYUNDAI、KIA',
+ 'brand_name' , // '品牌名称展示,如 比亚迪、现代、起亚',
+ 'series_code' , // '车系代码,如 ELANTRA、SONGPLUS',
+ 'series_name' , // '车系名称展示',
+ 'model_code' , // '车型/配置代码(工厂/内部编码)',
+ 'model_name' , // '车型/配置名称(可读,如 伊兰特 1.5L、海狮07)',
+ 'model_year' , // '年款(YYYY)',
+ 'trim_code' , // '版型代码(TRIM)',
+ 'trim_level_code' , // '配置等级代码(TRIM_LEVEL)',
+ 'edition_code' , // '特别版代码(EDITION)',
+ 'trim' , // '版型/细分配置(如 TOP旗舰版、荣耀版)',
+ 'trim_level' , // '配置等级(豪华型/旗舰型等,便于筛选)',
+ 'edition_name' , // '特别版/纪念版(如 荣耀版、致敬版等)',
+ 'body_type_code' , // '车身类型:SEDAN/SUV/HB/MPV/Pickup',
+ 'drive_type_code' , // '驱动:FWD/RWD/AWD/4WD',
+ 'motor_layout_code' , // '电驱/电机布置(MOTOR_LAYOUT):FWD/RWD/AWD/DM-i/DM-p 等',
+ 'fuel_type_code' , // '能源:GAS/HEV/PHEV/EV/EREV',
+ 'engine_disp_l' , // '排量(L),如 1.5;纯电为空',
+ 'engine_turbo' , // '0' COMMENT '是否涡轮(0/1)',
+ 'engine_power_kw' , // '最大功率(kW)',
+ 'battery_kwh' , // '电池容量(kWh)',
+ 'transmission_code' , // '变速箱:MT/AT/CVT/DCT/1SPEED',
+ 'gears' , // '挡位数(EV多为1)',
+ 'range_km' , // '续航里程(km)',
+ 'range_std_code' , // '续航标准:CLTC/WLTP/EPA/NEDC',
+ 'doors' , // '门数',
+ 'seats' , // '座位数',
+ 'weight_kg' , // '整备质量(kg)',
+ 'dimensions_mm' , // '尺寸(mm):{length,width,height,wheelbase}',
+ 'color_exterior_code' , // '外观色代码',
+ 'color_exterior_text' , // '外观色名称',
+ 'color_interior_code' , // '内饰色代码',
+ 'color_interior_text' , // '内饰色名称',
+ 'options_official' , // '官方选装(结构化 JSON)',
+ 'features' , // '功能/安全/智能配置(结构化 JSON)',
+ 'emission_std_code' , // '排放标准:CHN6/EURO6/EPA',
+ 'origin_country' , // '原产国 ISO-3166-1 alpha-2',
+ 'currency' , // 'CNY' COMMENT '币种 ISO-4217',
+ 'msrp' , // '建议零售价/参考价',
+ 'is_active' , // '1' COMMENT '启用(1)/禁用(0)',
+ 'corp_id' , // '0' COMMENT '租户/公司(全局库可写0)',
+ 'remark' , // '备注',
+ 'created_by' , // '0',
+ 'updated_by' , // '0',
+ ];
+
+
+ $data = [
+ 'fingerprint' , // '规格指纹(sha256)去重',
+ 'brand_name' , // '品牌名称展示,如 比亚迪、现代、起亚',
+ 'series_name' , // '车系名称展示',
+ 'model_name' , // '车型/配置名称(可读,如 伊兰特 1.5L、海狮07)',
+ 'model_year' , // '年款(YYYY)',
+ 'trim' , // '版型/细分配置(如 TOP旗舰版、荣耀版)',
+ 'trim_level' , // '配置等级(豪华型/旗舰型等,便于筛选)',
+ 'edition_name' , // '特别版/纪念版(如 荣耀版、致敬版等)',
+ 'engine_disp_l' , // '排量(L),如 1.5;纯电为空',
+ 'engine_turbo' , // '0' COMMENT '是否涡轮(0/1)',
+ 'engine_power_kw' , // '最大功率(kW)',
+ 'battery_kwh' , // '电池容量(kWh)',
+ 'gears' , // '挡位数(EV多为1)',
+ 'range_km' , // '续航里程(km)',
+ 'doors' , // '门数',
+ 'seats' , // '座位数',
+ 'weight_kg' , // '整备质量(kg)',
+ 'dimensions_mm' , // '尺寸(mm):{length,width,height,wheelbase}',
+ 'color_exterior_text' , // '外观色名称',
+ 'color_interior_text' , // '内饰色名称',
+ 'options_official' , // '官方选装(结构化 JSON)',
+ 'features' , // '功能/安全/智能配置(结构化 JSON)',
+ 'origin_country' , // '原产国 ISO-3166-1 alpha-2',
+ 'currency' , // 'CNY' COMMENT '币种 ISO-4217',
+ 'msrp' , // '建议零售价/参考价',
+ 'is_active' , // '1' COMMENT '启用(1)/禁用(0)',
+ 'corp_id' , // '0' COMMENT '租户/公司(全局库可写0)',
+ 'remark' , // '备注',
+ 'created_by' , // '0',
+ 'updated_by' , // '0',
+
+ 'body_type', // '车身类型'
+ 'drive_type', // '驱动:FWD/RWD/AWD/4WD',
+ 'motor_layout', // '电机布置(MOTOR_LAYOUT):FWD/RWD/AWD/DM-i/DM-p 等'
+ 'fuel_type', // '能源:GAS/HEV/PHEV/EV/EREV'
+ 'transmission', // '变速箱:MT/AT/CVT/DCT/1SPEED'
+ 'range_std', // '续航标准:CLTC/WLTP/EPA/NEDC'
+ 'emission_std', // '排放标准:CHN6/EURO6/EPA'
+
+ 'sku_code' , // 'SKU编码,系统生成',
+ 'brand_code' , // '品牌代码,如 BYD、HYUNDAI、KIA',
+ 'series_code' , // '车系代码,如 ELANTRA、SONGPLUS',
+ 'model_code' , // '车型/配置代码(工厂/内部编码)',
+ 'trim_code' , // '版型代码(TRIM)',
+ 'trim_level_code' , // '配置等级代码(TRIM_LEVEL)',
+ 'edition_code' , // '特别版代码(EDITION)',
+ 'color_exterior_code' , // '外观色代码',
+ 'color_interior_code' , // '内饰色代码',
+
+ 'body_type_code' , // '车身类型:SEDAN/SUV/HB/MPV/Pickup',
+ 'drive_type_code' , // '驱动:FWD/RWD/AWD/4WD',
+ 'motor_layout_code' , // '电驱/电机布置(MOTOR_LAYOUT):FWD/RWD/AWD/DM-i/DM-p 等',
+ 'fuel_type_code' , // '能源:GAS/HEV/PHEV/EV/EREV',
+ 'transmission_code' , // '变速箱:MT/AT/CVT/DCT/1SPEED',
+ 'range_std_code' , // '续航标准:CLTC/WLTP/EPA/NEDC',
+ 'emission_std_code' , // '排放标准:CHN6/EURO6/EPA',
+ ];
+ }
+}
\ No newline at end of file
diff --git a/app/common/controller/VehVehicleUnitController.php b/app/common/controller/VehVehicleUnitController.php
new file mode 100644
index 0000000..3d2e7e2
--- /dev/null
+++ b/app/common/controller/VehVehicleUnitController.php
@@ -0,0 +1,33 @@
+service = new VehVehicleUnitService();
+ }
+
+ /**
+ * 列表页数据格式化
+ *
+ * @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;
+ // }
+}
\ No newline at end of file
diff --git a/app/common/logic/BrandLogic.php b/app/common/logic/BrandLogic.php
new file mode 100644
index 0000000..3040572
--- /dev/null
+++ b/app/common/logic/BrandLogic.php
@@ -0,0 +1,22 @@
+orderBy('sort','desc')->get(['id', 'brand_code', 'brand_name', 'logo', 'description']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/BrandSeriesLogic.php b/app/common/logic/BrandSeriesLogic.php
new file mode 100644
index 0000000..956ca55
--- /dev/null
+++ b/app/common/logic/BrandSeriesLogic.php
@@ -0,0 +1,22 @@
+where($where)->orderBy('sort','desc')->get(['id', 'series_code', 'series_name', 'description']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/Fingerprint.php b/app/common/logic/Fingerprint.php
new file mode 100644
index 0000000..a066ada
--- /dev/null
+++ b/app/common/logic/Fingerprint.php
@@ -0,0 +1,262 @@
+['msrp']]); // 可选排除
+ */
+class Fingerprint
+{
+ /** 你的 veh_vehicle_sku 所有列(保持与表结构一致,顺序无关但建议完整) */
+ public const COLS = [
+ 'id','sku_code','fingerprint',
+ 'brand_code','brand_name','series_code','series_name',
+ 'model_code','model_name','model_year',
+ 'trim_code','trim_level_code','edition_code',
+ 'trim','trim_level','edition_name',
+ 'body_type_code','drive_type_code','motor_layout_code','fuel_type_code',
+ 'engine_disp_l','engine_turbo','engine_power_kw','battery_kwh',
+ 'transmission_code','gears','range_km','range_std_code',
+ 'doors','seats','weight_kg','dimensions_mm',
+ 'color_exterior_code','color_exterior_text',
+ 'color_interior_code','color_interior_text',
+ 'options_official','features','emission_std_code',
+ 'origin_country','currency','msrp',
+ 'is_active','corp_id','remark',
+ 'created_by','updated_by','created_at','updated_at',
+ ];
+
+ /** 默认剔除:技术/循环依赖字段 */
+ public const EXCLUDE_DEFAULT = [
+ 'id','sku_code','fingerprint', 'dimensions_mm', 'options_official', 'features',
+ 'origin_country','currency','msrp',
+ 'is_active','corp_id','remark',
+ 'created_by','updated_by','created_at','updated_at'
+ ];
+
+ /** 识别为“code类”的字段模式(统一大写) */
+ private const CODE_FIELD_REGEX = '/(_code|_country|^currency)$/i';
+
+ /** 识别为 JSON 字段 */
+ private const JSON_FIELDS = ['dimensions_mm','options_official','features'];
+
+ /**
+ * 从 Eloquent 模型生成
+ */
+ public static function makeFromModel($model, array $opts = []): string
+ {
+ return self::makeFromArray($model->toArray(), $opts);
+ }
+
+ /**
+ * 从数组生成指纹
+ * @param array $row 一般为 $_POST 合并后的业务数据或 $model->toArray()
+ * @param array $opts ['exclude'=>[], 'extra'=>[], 'salt'=>string]
+ * - exclude: 额外排除的字段(默认仅排除 id,fingerprint)
+ * - extra : 额外拼入的键值(例如上下文、租户策略),会参与计算
+ * - salt : 额外加盐字符串
+ */
+ public static function makeFromArray(array $row, array $opts = []): string
+ {
+ $exclude = array_values(array_unique(array_merge(self::EXCLUDE_DEFAULT, $opts['exclude'] ?? [])));
+ $extra = $opts['extra'] ?? [];
+ $salt = $opts['salt'] ?? '';
+
+ // 1) 统一抽取“表中定义的字段” + extra,缺失字段也要纳入(值按 NULL 处理)
+ $data = [];
+ foreach (self::COLS as $col) {
+ if (in_array($col, $exclude, true)) continue;
+ $data[$col] = array_key_exists($col, $row) ? $row[$col] : null;
+ }
+ // extra 也参与
+ foreach ($extra as $k => $v) {
+ if (!is_string($k) || $k === '') continue;
+ $data['__extra__'.$k] = $v;
+ }
+
+ // 2) 规范化(按字段特征)
+ $canon = [];
+ foreach ($data as $k => $v) {
+ $canon[$k] = self::normalize($k, $v);
+ }
+
+ // 3) 键名排序,确保顺序无关
+ ksort($canon, SORT_STRING);
+
+ // 4) 拼成稳定串: key=value | key=value...
+ $parts = [];
+ foreach ($canon as $k => $v) {
+ // 为空也必须占位,避免 key 消失影响其他键的意义
+ $parts[] = $k.'='.$v;
+ }
+ if ($salt !== '') {
+ $parts[] = '__salt__='.$salt;
+ }
+ $plain = implode('|', $parts);
+
+ // 5) sha256
+ return hash('sha256', $plain);
+ }
+
+ /**
+ * 规范化单个字段
+ * - NULL -> 特殊占位 "∅"(避免与空串混淆)
+ * - 布尔/整数/浮点 -> 统一数字字符串
+ * - code类字段 -> 去首尾空白 & 转大写
+ * - 普通字符串 -> trim & 压缩连续空白为单空格
+ * - JSON字段 -> 解析后做“键排序 + 值规范化 + 索引数组可排序”,再无空白编码
+ */
+ private static function normalize(string $field, $value): string
+ {
+ if ($value === null) return '∅';
+
+ // 数值类型
+ if (is_int($value)) return (string)$value;
+ if (is_bool($value)) return $value ? '1' : '0';
+
+ if (is_float($value) || (is_string($value) && is_numeric($value) && self::looksLikeNumberField($field))) {
+ // 统一浮点格式,最多 6 位小数并去尾零
+ $num = (float)$value;
+ $s = number_format($num, 6, '.', '');
+ $s = rtrim(rtrim($s, '0'), '.');
+ return $s === '' ? '0' : $s;
+ }
+
+ // JSON 字段
+ if (in_array($field, self::JSON_FIELDS, true)) {
+ return self::normalizeJson($value);
+ }
+
+ // 字符串
+ if (is_string($value)) {
+ $s = trim($value);
+ // code类:统一大写
+ if (preg_match(self::CODE_FIELD_REGEX, $field)) {
+ $s = mb_strtoupper($s, 'UTF-8');
+ } else {
+ // 普通文本:压缩连续空白
+ $s = preg_replace('/\s+/u', ' ', $s);
+ }
+ return $s === '' ? '' : $s;
+ }
+
+ // 数组(极少出现,按 JSON 处理)
+ if (is_array($value)) {
+ return self::normalizeJson($value);
+ }
+
+ // 其他类型(对象等):转 JSON 后处理
+ return self::normalizeJson($value);
+ }
+
+ /** 判断这个字段是否“看起来像数值字段” */
+ private static function looksLikeNumberField(string $field): bool
+ {
+ static $numKeys = [
+ 'engine_disp_l','engine_power_kw','battery_kwh','gears',
+ 'range_km','doors','seats','weight_kg','msrp','model_year',
+ 'created_at','updated_at','corp_id','is_active'
+ ];
+ return in_array($field, $numKeys, true);
+ }
+
+ /**
+ * JSON 规范化:
+ * - 字符串:若能 json_decode 则按 JSON;否则当普通字符串再规范化
+ * - 对象:键名排序;值递归规范化
+ * - 索引数组:元素递归规范化后,按字符串值排序(视为集合,避免顺序抖动)
+ * - 最终 json_encode(JSON_UNESCAPED_UNICODE|UNESCAPED_SLASHES)
+ */
+ private static function normalizeJson($val): string
+ {
+ // 已是数组/对象
+ if (is_array($val)) {
+ $normalized = self::canonArray($val);
+ return json_encode($normalized, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
+ }
+
+ // 字符串尝试解析
+ if (is_string($val)) {
+ $val = trim($val);
+ if ($val === '') return '""';
+ $decoded = json_decode($val, true);
+ if (json_last_error() === JSON_ERROR_NONE) {
+ $normalized = self::canonArray($decoded);
+ return json_encode($normalized, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
+ }
+ // 非 JSON 字符串,按普通字符串规范化
+ $s = preg_replace('/\s+/u', ' ', $val);
+ return json_encode($s, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
+ }
+
+ // 其他类型:直接编码
+ return json_encode($val, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
+ }
+
+ /** 递归规范化数组/对象 */
+ private static function canonArray($arr)
+ {
+ if (!is_array($arr)) return $arr;
+
+ // 关联数组(对象)
+ if (self::isAssoc($arr)) {
+ $out = [];
+ ksort($arr, SORT_STRING);
+ foreach ($arr as $k => $v) {
+ $out[(string)$k] = self::canonValue($v);
+ }
+ return $out;
+ }
+
+ // 索引数组(当集合处理:元素字符串化后排序)
+ $tmp = [];
+ foreach ($arr as $v) {
+ $tmp[] = self::canonValue($v);
+ }
+ // 将元素转为字符串再排序,确保稳定
+ usort($tmp, function($a, $b) {
+ $sa = is_scalar($a) ? (string)$a : json_encode($a, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
+ $sb = is_scalar($b) ? (string)$b : json_encode($b, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
+ return strcmp($sa, $sb);
+ });
+ return $tmp;
+ }
+
+ private static function canonValue($v)
+ {
+ if (is_array($v)) return self::canonArray($v);
+ if (is_bool($v)) return $v ? 1 : 0;
+ if (is_int($v)) return $v;
+ if (is_float($v)) {
+ $s = number_format($v, 6, '.', '');
+ $s = rtrim(rtrim($s, '0'), '.');
+ return $s === '' ? '0' : $s;
+ }
+ if (is_string($v)) {
+ $s = trim($v);
+ $s = preg_replace('/\s+/u', ' ', $s);
+ return $s;
+ }
+ return $v;
+ }
+
+ private static function isAssoc(array $arr): bool
+ {
+ // 有任意一个键不是 0..n 的递增整数,就视为关联数组
+ $i = 0;
+ foreach ($arr as $k => $_) {
+ if ($k !== $i++) return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/app/common/logic/ModelNaming.php b/app/common/logic/ModelNaming.php
new file mode 100644
index 0000000..b50a4cf
--- /dev/null
+++ b/app/common/logic/ModelNaming.php
@@ -0,0 +1,101 @@
+ 15L
+ if (!empty($s['engine_turbo']) && (int)$s['engine_turbo'] === 1) $key[] = 'T';
+ if (!empty($s['transmission_code'])) $key[] = self::tok($s['transmission_code']);
+ break;
+
+ case 'HEV':
+ case 'PHEV':
+ case 'EREV':
+ $key[] = $fuel;
+ if (!empty($s['engine_disp_l'])) $key[] = self::dispToken($s['engine_disp_l']);
+ if (!empty($s['motor_layout_code'])) $key[] = self::tok($s['motor_layout_code']); // 如 DM-I/DM-P/AWD
+ break;
+
+ default:
+ $key[] = $fuel;
+ }
+
+ if (!empty($s['drive_type_code'])) $key[] = self::tok($s['drive_type_code']);
+
+ $parts[] = implode('_', array_filter($key));
+ return strtoupper(implode('_', array_filter($parts)));
+ }
+
+ /** 生成中文可读的 model_name(走快照中文,不依赖 i18n) */
+ public static function buildModelName(array $s): string
+ {
+ $seriesName = trim((string)($s['series_name'] ?? $s['series_code'] ?? ''));
+ $yearPart = !empty($s['model_year']) ? ($s['model_year'] . '款 ') : '';
+
+ $fuel = strtoupper($s['fuel_type_code'] ?? '');
+ $tail = '';
+
+ if ($fuel === 'EV') {
+ $range = !empty($s['range_km']) ? (int)$s['range_km'] . 'KM ' : '';
+ $drive = trim((string)($s['drive_type'] ?? $s['drive_type_code'] ?? ''));
+ $tail = "EV {$range}{$drive}";
+ } elseif ($fuel === 'GAS') {
+ $disp = (!empty($s['engine_disp_l']))
+ ? rtrim(rtrim(number_format((float)$s['engine_disp_l'], 1, '.', ''), '0'), '.') . 'L '
+ : '';
+ $trans = trim((string)($s['transmission'] ?? $s['transmission_code'] ?? ''));
+ $tail = "{$disp}{$trans}";
+ } else {
+ $tail = trim((string)($s['fuel_type'] ?? $fuel));
+ }
+
+ $extras = [];
+ foreach (['trim','trim_level','edition_name'] as $k) {
+ if (!empty($s[$k])) $extras[] = trim((string)$s[$k]);
+ }
+ $extraStr = $extras ? ' ' . implode(' ', $extras) : '';
+
+ return trim($seriesName . ' ' . $yearPart . $tail . $extraStr);
+ }
+
+ /* ===== Helpers ===== */
+
+ private static function tok($v): string
+ {
+ $v = strtoupper((string)$v);
+ return preg_replace('/[^A-Z0-9_]/', '', $v ?? '');
+ }
+
+ private static function numToken($v): string
+ {
+ return preg_replace('/[^0-9]/', '', (string)$v);
+ }
+
+ /** 1.5L -> 15L;2.0L -> 20L(便于 code 稳定检索) */
+ private static function dispToken($l): string
+ {
+ $x = (float)$l;
+ return (string)round($x * 10) . 'L';
+ }
+}
\ No newline at end of file
diff --git a/app/common/logic/SkuCodeBuilder.php b/app/common/logic/SkuCodeBuilder.php
new file mode 100644
index 0000000..823b8dc
--- /dev/null
+++ b/app/common/logic/SkuCodeBuilder.php
@@ -0,0 +1,233 @@
+ 'FLG',
+ 'PREMIUM' => 'PRM',
+ 'STANDARD' => 'STD',
+ 'DELUXE' => 'DLX',
+ // edition
+ 'HONOR' => 'HNR',
+ 'CHAMPION' => 'CHP',
+ 'ANNIV' => 'ANV',
+ // trans
+ '1SPEED' => '1SP',
+ // drive/fuel/body 等一般已短,不必压缩
+ ];
+
+ /** 入口:生成 sku_code */
+ public static function build(array $s, array $opts = []): string
+ {
+ $maxLen = $opts['max_len'] ?? 40;
+ $ensureUnique = $opts['ensure_unique'] ?? true;
+
+ $tokens = [
+ 'brand' => self::tok($s['brand_code'] ?? ''),
+ 'series' => self::tok($s['series_code'] ?? ''),
+ 'year' => isset($s['model_year']) ? (string)intval($s['model_year']) : '',
+ 'fuel' => self::tok($s['fuel_type_code'] ?? ''),
+ 'drive' => self::tok($s['drive_type_code'] ?? ''),
+ 'spec' => self::buildSpec($s, self::tok($s['fuel_type_code'] ?? '')),
+ 'level' => self::abbr(self::tok($s['trim_level_code'] ?? '')),
+ 'edition' => self::abbr(self::tok($s['edition_code'] ?? '')),
+ ];
+
+ // 过滤空段并按既定顺序拼接
+ $order = ['brand','series','year','fuel','drive','spec','level','edition'];
+ $parts = [];
+ foreach ($order as $k) {
+ if (!empty($tokens[$k])) $parts[$k] = $tokens[$k];
+ }
+
+ $sku = self::normalizeSku(implode('-', $parts));
+
+ if (strlen($sku) > $maxLen) {
+ $sku = self::shrink($parts, $maxLen); // 传入“带键名的 parts”
+ }
+
+ if ($ensureUnique) {
+ $sku = self::ensureUnique($sku, $maxLen);
+ }
+ return $sku;
+ }
+
+ /** 构造规格位(SPEC),按能源类型差异化 */
+ private static function buildSpec(array $s, string $fuel): string
+ {
+ $fuel = strtoupper($fuel);
+ if ($fuel === 'EV') {
+ if (!empty($s['range_km'])) {
+ $r = (int)$s['range_km'];
+ $r10 = (int)round($r / 10) * 10; // 到 10 位
+ return (string)$r10;
+ }
+ if (!empty($s['battery_kwh'])) {
+ return self::numToken($s['battery_kwh']) . 'KWH';
+ }
+ return '';
+ }
+
+ if ($fuel === 'GAS') {
+ $bits = [];
+ if (!empty($s['engine_disp_l'])) {
+ $bits[] = self::dispToken($s['engine_disp_l']); // 1.5L -> 15L
+ }
+ if (!empty($s['engine_turbo']) && intval($s['engine_turbo']) === 1) {
+ $bits[] = 'T';
+ }
+ if (!empty($s['transmission_code'])) {
+ $bits[] = self::abbr(self::tok($s['transmission_code']));
+ }
+ return implode('', $bits); // 如 15LTCVT
+ }
+
+ // HEV/PHEV/EREV 等
+ $bits = [];
+ if (!empty($s['engine_disp_l'])) {
+ $bits[] = self::dispToken($s['engine_disp_l']); // 可空
+ }
+ if (!empty($s['motor_layout_code'])) {
+ $bits[] = self::tok($s['motor_layout_code']); // 如 AWD / DM-I / DM-P
+ }
+ return implode('', $bits);
+ }
+
+ /** 冲突检测并追加短校验(全局唯一) */
+ private static function ensureUnique(string $sku, int $maxLen): string
+ {
+ if (!VehVehicleSku::where('sku_code', $sku)->exists()) {
+ return $sku;
+ }
+ // 用 crc32 生成 5~6 位 base36 校验(稳定且短)
+ $crc = self::base36Crc($sku);
+ $suffix = '-X' . $crc;
+
+ if (strlen($sku . $suffix) > $maxLen) {
+ $sku = substr($sku, 0, max(0, $maxLen - strlen($suffix)));
+ $sku = rtrim($sku, '-'); // 避免尾部 '-'
+ }
+ $sku .= $suffix;
+
+ // 若极端情况下仍冲突,追加递增计数
+ $i = 2;
+ $candidate = $sku;
+ while (VehVehicleSku::where('sku_code', $candidate)->exists()) {
+ $extra = '-'.$i;
+ $cut = max(0, $maxLen - strlen($extra));
+ $candidate = substr($sku, 0, $cut) . $extra;
+ $i++;
+ }
+ return $candidate;
+ }
+
+ /** 把 token 数组尽量压到 maxLen(逐步压缩策略) */
+ private static function shrink(array $partsByKey, int $maxLen): string
+ {
+ // 1) 先对 series/level/edition 做激进压缩
+ $p = $partsByKey;
+ foreach (['series','level','edition'] as $k) {
+ if (!empty($p[$k])) $p[$k] = self::heavyAbbr($p[$k]);
+ }
+ $sku = self::normalizeSku(implode('-', $p));
+ if (strlen($sku) <= $maxLen) return $sku;
+
+ // 2) 依次移除不太关键的信息:edition → level(若存在)
+ if (!empty($p['edition'])) { unset($p['edition']); }
+ $sku = self::normalizeSku(implode('-', $p));
+ if (strlen($sku) <= $maxLen) return $sku;
+
+ if (!empty($p['level'])) { unset($p['level']); }
+ $sku = self::normalizeSku(implode('-', $p));
+ if (strlen($sku) <= $maxLen) return $sku;
+
+ // 3) 压缩 spec(如去 KM/KWH,仅保留核心)
+ if (!empty($p['spec'])) { $p['spec'] = self::compactSpec($p['spec']); }
+ $sku = self::normalizeSku(implode('-', $p));
+ if (strlen($sku) <= $maxLen) return $sku;
+
+ // 4) 仍超长:从右向左截断次要段(spec/drive/year),保留前三段(brand/series/fuel)优先
+ $dropOrder = ['spec','drive','year'];
+ $q = $p;
+ foreach ($dropOrder as $k) {
+ if (!empty($q[$k])) { unset($q[$k]); }
+ $sku = self::normalizeSku(implode('-', $q));
+ if (strlen($sku) <= $maxLen) return $sku;
+ }
+
+ // 5) 最后兜底:硬截到 maxLen,后续 ensureUnique 会追加 -X 校验并避免冲突
+ return substr(self::normalizeSku(implode('-', $p)), 0, $maxLen);
+ }
+
+ /* ===== Helpers ===== */
+
+ private static function tok($v): string
+ {
+ $v = strtoupper((string)$v);
+ return preg_replace('/[^A-Z0-9_]/', '', $v ?? '');
+ }
+
+ private static function abbr(string $t): string
+ {
+ return self::ABBR[$t] ?? $t;
+ }
+
+ private static function heavyAbbr(string $t): string
+ {
+ // 更激进:去除元音,连字符化
+ $t = str_replace(['STANDARD','FLAGSHIP','PREMIUM','DELUXE'], ['STD','FLG','PRM','DLX'], $t);
+ $t = preg_replace('/[AEIOU]/', '', $t);
+ return $t;
+ }
+
+ private static function compactSpec(string $s): string
+ {
+ // 规则:去 KM/KWH 等单位,只保留数字与核心字母
+ $s = strtoupper($s);
+ $s = str_replace(['KM','KWH'], '', $s);
+ return $s;
+ }
+
+ private static function numToken($v): string
+ {
+ return preg_replace('/[^0-9]/', '', (string)$v);
+ }
+
+ /** 1.5L -> 15L;2.0L -> 20L */
+ private static function dispToken($l): string
+ {
+ $x = (float)$l;
+ return (string)round($x * 10) . 'L';
+ }
+
+ private static function base36Crc(string $s): string
+ {
+ $crc = sprintf('%u', crc32($s)); // 无符号
+ $n = (int)$crc;
+ $chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ $res = '';
+ do {
+ $res = $chars[$n % 36] . $res;
+ $n = intdiv($n, 36);
+ } while ($n > 0);
+ return substr($res, -6); // 取后6位足够
+ }
+
+ private static function normalizeSku(string $s): string
+ {
+ // 连续的 '-' 合并,首尾修剪
+ $s = preg_replace('/-+/', '-', $s);
+ $s = trim($s, '-');
+ return $s;
+ }
+}
\ No newline at end of file
diff --git a/app/common/logic/StockOrdersLogic.php b/app/common/logic/StockOrdersLogic.php
new file mode 100644
index 0000000..29d09ad
--- /dev/null
+++ b/app/common/logic/StockOrdersLogic.php
@@ -0,0 +1,17 @@
+orderBy('sort','desc')->get(['id', 'account_name', 'currency_id', 'account_number', 'bank_name', 'bank_branch', 'description']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/SysCurrencyLogic.php b/app/common/logic/SysCurrencyLogic.php
new file mode 100644
index 0000000..206efa2
--- /dev/null
+++ b/app/common/logic/SysCurrencyLogic.php
@@ -0,0 +1,21 @@
+get(['id', 'currency_code', 'currency_name', 'currency_symbol', 'exchange_rate', 'float_percent']);
+ }
+}
\ No newline at end of file
diff --git a/app/common/logic/SysDictItemLogic.php b/app/common/logic/SysDictItemLogic.php
new file mode 100644
index 0000000..d6efc72
--- /dev/null
+++ b/app/common/logic/SysDictItemLogic.php
@@ -0,0 +1,22 @@
+where($where)->orderBy('sort','desc')->get(['id', 'item_label', 'item_value', 'remark', 'dict_id']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/SysDictLogic.php b/app/common/logic/SysDictLogic.php
new file mode 100644
index 0000000..6447ed3
--- /dev/null
+++ b/app/common/logic/SysDictLogic.php
@@ -0,0 +1,27 @@
+where('code', $code)->orderBy('sort','desc')->first(['id']);
+ }
+
+ public function getList()
+ {
+ return SysDict::where('status', 1)->get(['id', 'dict_name', 'dict_code', 'description']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/SysPortLogic.php b/app/common/logic/SysPortLogic.php
new file mode 100644
index 0000000..a2e78a8
--- /dev/null
+++ b/app/common/logic/SysPortLogic.php
@@ -0,0 +1,22 @@
+orderBy('sort','desc')->get(['id', 'port_code', 'port_name', 'country_id', 'description']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/VehColorLogic.php b/app/common/logic/VehColorLogic.php
new file mode 100644
index 0000000..7a36811
--- /dev/null
+++ b/app/common/logic/VehColorLogic.php
@@ -0,0 +1,22 @@
+where($where)->orderBy('sort','desc')->get(['id', 'color_code', 'color_text']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/VehDictI18nLogic.php b/app/common/logic/VehDictI18nLogic.php
new file mode 100644
index 0000000..f25b50b
--- /dev/null
+++ b/app/common/logic/VehDictI18nLogic.php
@@ -0,0 +1,17 @@
+orderBy('sort','desc')->get(['id', 'code', 'name', 'type', 'price']);
+ }
+
+}
\ No newline at end of file
diff --git a/app/common/logic/VehVehicleListingLogic.php b/app/common/logic/VehVehicleListingLogic.php
new file mode 100644
index 0000000..6c0ad44
--- /dev/null
+++ b/app/common/logic/VehVehicleListingLogic.php
@@ -0,0 +1,17 @@
+hasMany(SysDictItem::class, 'dict_id', 'id');
+ }
+}
\ No newline at end of file
diff --git a/app/common/model/SysDictItem.php b/app/common/model/SysDictItem.php
new file mode 100644
index 0000000..f53a7a9
--- /dev/null
+++ b/app/common/model/SysDictItem.php
@@ -0,0 +1,59 @@
+belongsTo(SysDict::class, 'dict_id', 'id');
+ }
+}
\ No newline at end of file
diff --git a/app/common/model/SysPort.php b/app/common/model/SysPort.php
new file mode 100644
index 0000000..2249b98
--- /dev/null
+++ b/app/common/model/SysPort.php
@@ -0,0 +1,49 @@
+ 'integer',
+ 'enabled' => 'integer',
+ 'sort_order' => 'integer',
+ 'created_at' => 'integer',
+ 'updated_at' => 'integer',
+ ];
+
+ protected $fillable = [
+ 'field','dict','required','enabled','sort_order',
+ 'remark','created_at','updated_at'
+ ];
+}
\ No newline at end of file
diff --git a/app/common/model/VehModification.php b/app/common/model/VehModification.php
new file mode 100644
index 0000000..d3bd16e
--- /dev/null
+++ b/app/common/model/VehModification.php
@@ -0,0 +1,49 @@
+ 'array',
+ 'features' => 'array',
+ 'dimensions_mm' => 'array',
+ 'model_year' => 'integer',
+ 'engine_turbo' => 'integer',
+ 'gears' => 'integer',
+ 'range_km' => 'integer',
+ 'doors' => 'integer',
+ 'seats' => 'integer',
+ 'weight_kg' => 'integer',
+ 'msrp' => 'float',
+ 'battery_kwh' => 'float',
+ 'engine_disp_l' => 'float',
+ 'is_active' => 'integer',
+ 'corp_id' => 'integer',
+ 'created_at' => 'integer',
+ 'updated_at' => 'integer',
+ ];
+
+ protected $fillable = [
+ 'sku_code','fingerprint',
+ 'brand_code','brand_name',
+ 'series_code','series_name',
+ 'model_code','model_name','model_year',
+ 'trim_code','trim_level_code','edition_code',
+ 'trim','trim_level','edition_name',
+ 'body_type_code','drive_type_code','motor_layout_code',
+ 'fuel_type_code','engine_disp_l','engine_turbo','engine_power_kw',
+ 'battery_kwh','transmission_code','gears',
+ 'range_km','range_std_code',
+ 'doors','seats','weight_kg','dimensions_mm',
+ 'color_exterior_code','color_exterior_text',
+ 'color_interior_code','color_interior_text',
+ 'options_official','features','emission_std_code',
+ 'origin_country','currency','msrp',
+ 'is_active','corp_id','remark',
+ 'created_by','updated_by','created_at','updated_at',
+ 'body_type', 'drive_type', 'motor_layout', 'fuel_type', 'transmission',
+ 'range_std', 'emission_std'
+ ];
+}
\ No newline at end of file
diff --git a/app/common/model/VehVehicleUnit.php b/app/common/model/VehVehicleUnit.php
new file mode 100644
index 0000000..28e38f1
--- /dev/null
+++ b/app/common/model/VehVehicleUnit.php
@@ -0,0 +1,49 @@
+logic = (new BrandSeriesLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList($params)
+ {
+ if (empty($params['brand_id']))
+ throw new BusinessException('品牌id不能为空');
+ $where = [];
+ if(isset($params['brand_id']) && $params['brand_id'])
+ $where[] = ['brand_id', '=', $params['brand_id']];
+ return $this->logic->getList($where);
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/BrandService.php b/app/common/service/BrandService.php
new file mode 100644
index 0000000..c3430fe
--- /dev/null
+++ b/app/common/service/BrandService.php
@@ -0,0 +1,24 @@
+logic = (new BrandLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList()
+ {
+ return $this->logic->getList();
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/StockOrdersService.php b/app/common/service/StockOrdersService.php
new file mode 100644
index 0000000..a5c73ac
--- /dev/null
+++ b/app/common/service/StockOrdersService.php
@@ -0,0 +1,31 @@
+validator;
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/SysAccountService.php b/app/common/service/SysAccountService.php
new file mode 100644
index 0000000..b9c59ad
--- /dev/null
+++ b/app/common/service/SysAccountService.php
@@ -0,0 +1,28 @@
+logic = (new SysAccountLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList()
+ {
+ return $this->logic->getList();
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/SysCurrencyService.php b/app/common/service/SysCurrencyService.php
new file mode 100644
index 0000000..f0108d0
--- /dev/null
+++ b/app/common/service/SysCurrencyService.php
@@ -0,0 +1,25 @@
+logic = (new SysCurrencyLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList()
+ {
+ return $this->logic->getList();
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/SysDictItemService.php b/app/common/service/SysDictItemService.php
new file mode 100644
index 0000000..c1e51ed
--- /dev/null
+++ b/app/common/service/SysDictItemService.php
@@ -0,0 +1,42 @@
+logic = (new SysDictItemLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList($params)
+ {
+ if (empty($params['dict_id']) && empty($params['dict_code']))
+ throw new BusinessException('未明确要查询的字典组');
+ $where = [];
+ if(isset($params['dict_id']) && $params['dict_id'])
+ $where[] = ['dict_id', '=', $params['dict_id']];
+ if(isset($params['dict_code']) && $params['dict_code']){
+ $dict = (new SysDictLogic)->getDictByCode($params['dict_code']);
+ if (empty($dict['id']))
+ throw new BusinessException('字典组code错误');
+ $where[] = ['dict_id', '=', $dict['id']];
+ }
+
+ return $this->logic->getList($where);
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/SysDictService.php b/app/common/service/SysDictService.php
new file mode 100644
index 0000000..57ab33c
--- /dev/null
+++ b/app/common/service/SysDictService.php
@@ -0,0 +1,28 @@
+logic = (new SysDictLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList()
+ {
+ return $this->logic->getList();
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/SysPortService.php b/app/common/service/SysPortService.php
new file mode 100644
index 0000000..2918a96
--- /dev/null
+++ b/app/common/service/SysPortService.php
@@ -0,0 +1,28 @@
+logic = (new SysPortLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList()
+ {
+ return $this->logic->getList();
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/VehColorService.php b/app/common/service/VehColorService.php
new file mode 100644
index 0000000..2060efe
--- /dev/null
+++ b/app/common/service/VehColorService.php
@@ -0,0 +1,33 @@
+logic = (new VehColorLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList($params)
+ {
+ if (empty($params['type']))
+ throw new BusinessException('类型不能为空');
+ $where = [];
+ if(isset($params['type']) && $params['type'])
+ $where[] = ['type', '=', $params['type']];
+ return $this->logic->getList($where);
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/VehDictI18nService.php b/app/common/service/VehDictI18nService.php
new file mode 100644
index 0000000..1c738d2
--- /dev/null
+++ b/app/common/service/VehDictI18nService.php
@@ -0,0 +1,75 @@
+validator;
+ }
+
+
+ /** 本进程缓存:[dict][code] => labels array */
+ protected static array $labelsCache = [];
+
+ public static function label(string $dict=null, ?string $code=null, string $locale='zh-CN', ?string $fallbackZh=null): ?string
+ {
+ if (!$dict || !$code) return $fallbackZh;
+
+ $labels = self::labels($dict, $code);
+ if (!$labels) return $fallbackZh ?? $code;
+
+ return $labels[$locale] ?? $labels['zh-CN'] ?? $code;
+ }
+
+ /** 返回 labels 数组,命中缓存 */
+ public static function labels(string $dict, string $code): ?array
+ {
+ $dict = strtoupper($dict);
+ $code = (string)$code;
+
+ if (isset(self::$labelsCache[$dict][$code])) {
+ return self::$labelsCache[$dict][$code];
+ }
+
+ $term = DictTerm::where('dict',$dict)->where('code',$code)->first(['labels']);
+ if (!$term) return null;
+
+ $labels = $term->labels ?? null;
+ if (!is_array($labels)) return null;
+
+ self::$labelsCache[$dict][$code] = $labels;
+ return $labels;
+ }
+
+ /** 校验 code 是否存在于字典(用于必填维度) */
+ public static function ensureExists(string $dict, ?string $code, string $fieldNameForError): void
+ {
+ if ($code === null || $code === '') {
+ throw new \InvalidArgumentException("缺少必填字段:{$fieldNameForError}");
+ }
+ $ok = VehDictI18n::where('dict',$dict)->where('code',$code)->where('status', 1)->exists();
+ if (!$ok) throw new \InvalidArgumentException("字典不存在或未启用:{$dict}.{$code}");
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/VehDictMappingService.php b/app/common/service/VehDictMappingService.php
new file mode 100644
index 0000000..67c5288
--- /dev/null
+++ b/app/common/service/VehDictMappingService.php
@@ -0,0 +1,57 @@
+validator;
+ }
+
+
+ public static function all(): array
+ {
+ $rows = VehDictMapping::where('status', 1)->orderBy('sort')->orderBy('id')->get()->toArray();
+ $out = [];
+ foreach ($rows as $r) {
+ $out[$r['dict']] = [
+ 'field' => $r['field'],
+ 'dict' => $r['dict'],
+ 'required' => (int)$r['required'] === 1,
+ ];
+ }
+ return $out;
+ }
+
+ public static function requiredDicts(): array
+ {
+ return array_keys(array_filter(self::all(), fn($x)=>$x['required']===true));
+ }
+
+ public static function enabled(string $dict): bool
+ {
+ $all = self::all();
+ return isset($all[$dict]);
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/VehModificationService.php b/app/common/service/VehModificationService.php
new file mode 100644
index 0000000..31c7119
--- /dev/null
+++ b/app/common/service/VehModificationService.php
@@ -0,0 +1,28 @@
+logic = (new VehModificationLogic());
+ }
+
+ /**
+ * 获取系统list
+ */
+ public function getList()
+ {
+ return $this->logic->getList();
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/VehVehicleListingService.php b/app/common/service/VehVehicleListingService.php
new file mode 100644
index 0000000..3aee146
--- /dev/null
+++ b/app/common/service/VehVehicleListingService.php
@@ -0,0 +1,31 @@
+validator;
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/VehVehicleSkuService.php b/app/common/service/VehVehicleSkuService.php
new file mode 100644
index 0000000..ca25040
--- /dev/null
+++ b/app/common/service/VehVehicleSkuService.php
@@ -0,0 +1,162 @@
+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']['id'] = 'desc';
+ break;
+ case 'index':
+ $config['where']['is_active'] = 1;
+ $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);
+ 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);
+ 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;
+ }
+}
\ No newline at end of file
diff --git a/app/common/service/VehVehicleUnitService.php b/app/common/service/VehVehicleUnitService.php
new file mode 100644
index 0000000..4af3ea4
--- /dev/null
+++ b/app/common/service/VehVehicleUnitService.php
@@ -0,0 +1,31 @@
+validator;
+ }
+}
\ No newline at end of file
diff --git a/app/common/utils/scaffold/Generate.php b/app/common/utils/scaffold/Generate.php
index eb82025..2ed10a0 100644
--- a/app/common/utils/scaffold/Generate.php
+++ b/app/common/utils/scaffold/Generate.php
@@ -156,11 +156,11 @@ class Generate
protected function deleteFileIfExists($path)
{
if (file_exists($path)) {
- "文件: {$path} 已存在,核对后手动删除。\n";
- return;
+ // "文件: {$path} 已存在,核对后手动删除。\n";
+ // return;
- // unlink($path);
- // echo "删除已存在文件: {$path} \n";
+ unlink($path);
+ echo "删除已存在文件: {$path} \n";
}
}
diff --git a/app/common/validate/StockOrdersValidate.php b/app/common/validate/StockOrdersValidate.php
new file mode 100644
index 0000000..78fccf3
--- /dev/null
+++ b/app/common/validate/StockOrdersValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/common/validate/VehDictI18nValidate.php b/app/common/validate/VehDictI18nValidate.php
new file mode 100644
index 0000000..cb65500
--- /dev/null
+++ b/app/common/validate/VehDictI18nValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/common/validate/VehDictMappingValidate.php b/app/common/validate/VehDictMappingValidate.php
new file mode 100644
index 0000000..1b4bc7a
--- /dev/null
+++ b/app/common/validate/VehDictMappingValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/common/validate/VehVehicleListingValidate.php b/app/common/validate/VehVehicleListingValidate.php
new file mode 100644
index 0000000..ffa9c83
--- /dev/null
+++ b/app/common/validate/VehVehicleListingValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/common/validate/VehVehicleSkuValidate.php b/app/common/validate/VehVehicleSkuValidate.php
new file mode 100644
index 0000000..7305e71
--- /dev/null
+++ b/app/common/validate/VehVehicleSkuValidate.php
@@ -0,0 +1,128 @@
+ 'max:40|alphaNum',
+ 'fingerprint' => 'length:64|alphaNum',
+ 'brand_code' => 'require|max:32',
+ 'brand_name' => 'require|max:64',
+ 'series_code' => 'max:64',
+ 'series_name' => 'max:128',
+ 'model_code' => 'max:64',
+ 'model_name' => 'require|max:128',
+ 'model_year' => 'require|number|between:1900,2100',
+ 'trim_code' => 'max:64',
+ 'trim_level_code' => 'max:64',
+ 'edition_code' => 'max:64',
+ 'trim' => 'max:128',
+ 'trim_level' => 'max:64',
+ 'edition_name' => 'max:64',
+ 'body_type_code' => 'max:32',
+ 'drive_type_code' => 'max:16',
+ 'motor_layout_code' => 'max:32',
+ 'fuel_type_code' => 'max:16',
+ 'engine_disp_l' => 'float|between:0,99.9',
+ 'engine_turbo' => 'in:0,1',
+ 'engine_power_kw' => 'number|between:0,2000',
+ 'battery_kwh' => 'float|between:0,999.99',
+ 'transmission_code' => 'max:16',
+ 'gears' => 'number|between:1,20',
+ 'range_km' => 'number|between:0,2000',
+ 'range_std_code' => 'max:16',
+ 'doors' => 'number|between:2,10',
+ 'seats' => 'number|between:1,20',
+ 'weight_kg' => 'number|between:0,10000',
+ 'dimensions_mm' => 'array',
+ 'color_exterior_code'=> 'max:32',
+ 'color_exterior_text'=> 'max:64',
+ 'color_interior_code'=> 'max:32',
+ 'color_interior_text'=> 'max:64',
+ 'options_official' => 'array',
+ 'features' => 'array',
+ 'emission_std_code' => 'max:16',
+ 'origin_country' => 'alpha|length:2',
+ 'currency' => 'require|alpha|length:3',
+ 'msrp' => 'float|between:0,9999999999.99',
+ 'is_active' => 'in:0,1',
+ 'corp_id' => 'require|number',
+ 'remark' => 'max:255',
+ 'created_by' => 'number',
+ 'updated_by' => 'number',
+ 'created_at' => 'require|number',
+ 'updated_at' => 'require|number',
+ ];
+
+ /**
+ * 字段别名
+ */
+ protected $field = [
+ 'sku_code' => 'SKU编码',
+ 'fingerprint' => '规格指纹',
+ 'brand_code' => '品牌代码',
+ 'brand_name' => '品牌名称',
+ 'series_code' => '车系代码',
+ 'series_name' => '车系名称',
+ 'model_code' => '车型代码',
+ 'model_name' => '车型名称',
+ 'model_year' => '年款',
+ 'trim_code' => '版型代码',
+ 'trim_level_code' => '配置等级代码',
+ 'edition_code' => '特别版代码',
+ 'trim' => '版型/细分配置',
+ 'trim_level' => '配置等级',
+ 'edition_name' => '特别版名称',
+ 'body_type_code' => '车身类型',
+ 'drive_type_code' => '驱动方式',
+ 'motor_layout_code' => '电机布置',
+ 'fuel_type_code' => '能源类型',
+ 'engine_disp_l' => '排量(L)',
+ 'engine_turbo' => '是否涡轮',
+ 'engine_power_kw' => '最大功率(kW)',
+ 'battery_kwh' => '电池容量(kWh)',
+ 'transmission_code' => '变速箱代码',
+ 'gears' => '挡位数',
+ 'range_km' => '续航里程',
+ 'range_std_code' => '续航标准',
+ 'doors' => '门数',
+ 'seats' => '座位数',
+ 'weight_kg' => '整备质量',
+ 'dimensions_mm' => '车身尺寸',
+ 'color_exterior_code'=> '外观色代码',
+ 'color_exterior_text'=> '外观色名称',
+ 'color_interior_code'=> '内饰色代码',
+ 'color_interior_text'=> '内饰色名称',
+ 'options_official' => '官方选装',
+ 'features' => '功能配置',
+ 'emission_std_code' => '排放标准',
+ 'origin_country' => '原产国',
+ 'currency' => '币种',
+ 'msrp' => '建议零售价',
+ 'is_active' => '是否启用',
+ 'corp_id' => '公司ID',
+ 'remark' => '备注',
+ 'created_by' => '创建人',
+ 'updated_by' => '更新人',
+ 'created_at' => '创建时间',
+ 'updated_at' => '更新时间',
+ ];
+
+ /**
+ * 场景定义
+ */
+ protected $scene = [
+ 'store' => [
+ 'brand_code', 'brand_name', 'model_year','currency'
+ ],
+ 'update' => [
+ 'id', 'brand_code','brand_name', 'model_year','currency'
+ ],
+ ];
+}
\ No newline at end of file
diff --git a/app/common/validate/VehVehicleUnitValidate.php b/app/common/validate/VehVehicleUnitValidate.php
new file mode 100644
index 0000000..11f91a9
--- /dev/null
+++ b/app/common/validate/VehVehicleUnitValidate.php
@@ -0,0 +1,29 @@
+ [
+
+ ],
+
+ 'update' => [
+
+ ]
+ ];
+}
\ No newline at end of file
diff --git a/app/controller/IndexController.php b/app/controller/IndexController.php
index ba87d98..a0f6dba 100644
--- a/app/controller/IndexController.php
+++ b/app/controller/IndexController.php
@@ -78,25 +78,25 @@ class IndexController
$options = [
'controller' => [
'module' => 'common',
- 'name' => 'message_notifications'
+ 'name' => 'stock_orders'
],
'model' => [
'module' => 'common',
- 'name' => 'message_notifications'
+ 'name' => 'stock_orders'
],
'service' => [
'module' => 'common',
- 'name' => 'message_notifications'
+ 'name' => 'stock_orders'
],
'logic' => [
'module' => 'common',
- 'name' => 'message_notifications'
+ 'name' => 'stock_orders'
],
'validate' => [
'module' => 'common',
- 'name' => 'message_notifications'
+ 'name' => 'stock_orders'
],
- 'table' => 'message_notifications'
+ 'table' => 'stock_orders'
];
$result = (new Generate($options))->doGenerate();
@@ -106,43 +106,24 @@ class IndexController
public function test()
{
+ $params = [
+ 'email' => '',
+ 'phone' => '11',
+ 'whatsApp' => ''
+ ];
+ $corpId = 1;
+ $customer = \app\crm\model\Customer::where('corp_id', $corpId)
+ ->where((function (\Illuminate\Database\Eloquent\Builder $query) use ($params) {
+ if(!empty($params['email']))
+ $query->Orwhere('email', '=', $params['email']);
+ if(!empty($params['phone']))
+ $query->Orwhere('phone', '=', $params['phone']);
+ if(!empty($params['whatsApp']))
+ $query->Orwhere('whatsApp', '=', $params['whatsApp']);
+ return $query;
+ }))
+ ->first();
- // $data = [
- // 'sender_id' => 0,
- // 'sender_type' => 'system',
- // 'title' => '测试消息 - 标题',
- // 'content' => '测试消息 - 内容',
- // 'scene' => 1,
- // 'recipient' => [1],
- // ];
-
- // $data['recipient'] = [1, 74];
- // // // 同步推送
- // // (new MessageNotificationsService())->pushNotice($data);
-
-
-
- // // 异步推送
- // \Webman\RedisQueue\Redis::send('notice', $data);
-
-
- $info = InquiryLog::with(['channelInfo', 'countryInfo', 'enter'])->where('id', 1)->where('sync_crm', 0)->first();
-
- var_dump(empty($info->recipient));
-
- if ($info) {
- var_dump(11);
- } else {
- var_dump(22);
- }
-
-
- if ($info !== NULL) {
- var_dump(33);
- } else {
- var_dump(44);
- }
-
- return json(['code' => 0, 'msg' => 'success']);
+ return json($customer);
}
}
\ No newline at end of file
diff --git a/app/functions.php b/app/functions.php
index d9bb411..db8cfe7 100644
--- a/app/functions.php
+++ b/app/functions.php
@@ -304,6 +304,29 @@ if (!function_exists('generateMsgId')) {
// 随机部分(3位)
$rand = mt_rand(100, 999);
+ // 拼接:日期时间 + 微秒 + 随机数
+ return $date . $micro . $rand;
+ }
+}
+
+/**
+ * 生成sku_code
+ * 格式:年月日时分秒 + 微秒 + 随机数
+ * 例如:20250820175530987654321
+ *
+ * @return string
+ */
+if (!function_exists('skuCode')) {
+ function skuCode(): string
+ {
+ // 时间部分(精确到微秒)
+ $time = microtime(true);
+ $micro = sprintf("%06d", ($time - floor($time)) * 1e6);
+ $date = date('YmdHis', (int)$time);
+
+ // 随机部分(3位)
+ $rand = mt_rand(100, 999);
+
// 拼接:日期时间 + 微秒 + 随机数
return $date . $micro . $rand;
}
diff --git a/config/route.php b/config/route.php
index 86aa1a0..38c7907 100644
--- a/config/route.php
+++ b/config/route.php
@@ -61,8 +61,17 @@ Route::group('/common', function () {
Route::any('/feishu/app', [app\common\controller\PresetController::class, 'feishuApp']);
Route::any('/systems', [app\common\controller\PresetController::class, 'systems']);
Route::any('/roles', [app\common\controller\PresetController::class, 'roles']);
+ Route::any('/currency', [app\common\controller\PresetController::class, 'currency']);
Route::any('/cache/clear', [app\common\controller\PresetController::class, 'cacheClear']);
Route::any('/menus', [app\common\controller\PresetController::class, 'menus']);
+ Route::any('/brand', [app\common\controller\PresetController::class, 'brand']);
+ Route::any('/brand/series', [app\common\controller\PresetController::class, 'series']);
+ Route::any('/account', [app\common\controller\PresetController::class, 'account']);
+ Route::any('/dict', [app\common\controller\PresetController::class, 'dict']);
+ Route::any('/dictItem', [app\common\controller\PresetController::class, 'dictItem']);
+ Route::any('/port', [app\common\controller\PresetController::class, 'port']);
+ Route::any('/color', [app\common\controller\PresetController::class, 'color']);
+ Route::any('/modification', [app\common\controller\PresetController::class, 'modification']);
});
@@ -182,6 +191,99 @@ Route::group('/admin', function () {
Route::any('/allocation', [app\crmAdmin\controller\CustomerController::class, 'allocation']);
});
});
+
+ // 车辆
+ Route::group('/vehicle', function () {
+ // 基础信息
+ Route::group('/sku', function () {
+ Route::any('/list', [app\common\controller\VehVehicleSkuController::class, 'index']);
+ Route::any('/show', [app\common\controller\VehVehicleSkuController::class, 'show']);
+ Route::any('/store', [app\common\controller\VehVehicleSkuController::class, 'store']);
+ Route::any('/update', [app\common\controller\VehVehicleSkuController::class, 'update']);
+ Route::any('/destroy', [app\common\controller\VehVehicleSkuController::class, 'destroy']);
+ });
+ });
+
+ // 字典
+ Route::group('/dict', function () {
+ Route::any('/list', [app\admin\controller\SysDictController::class, 'index']);
+ Route::any('/show', [app\admin\controller\SysDictController::class, 'show']);
+ Route::any('/store', [app\admin\controller\SysDictController::class, 'store']);
+ Route::any('/update', [app\admin\controller\SysDictController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\SysDictController::class, 'destroy']);
+ Route::any('/scope', [app\admin\controller\SysDictController::class, 'listScope']);
+
+ Route::group('/item', function () {
+ Route::any('/list', [app\admin\controller\SysDictItemController::class, 'index']);
+ Route::any('/show', [app\admin\controller\SysDictItemController::class, 'show']);
+ Route::any('/store', [app\admin\controller\SysDictItemController::class, 'store']);
+ Route::any('/update', [app\admin\controller\SysDictItemController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\SysDictItemController::class, 'destroy']);
+ });
+ });
+
+ // 货币
+ Route::group('/currency', function () {
+ Route::any('/list', [app\admin\controller\SysCurrencyController::class, 'index']);
+ Route::any('/show', [app\admin\controller\SysCurrencyController::class, 'show']);
+ Route::any('/store', [app\admin\controller\SysCurrencyController::class, 'store']);
+ Route::any('/update', [app\admin\controller\SysCurrencyController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\SysCurrencyController::class, 'destroy']);
+ });
+
+ // 品牌
+ Route::group('/brand', function () {
+ Route::any('/list', [app\admin\controller\BrandController::class, 'index']);
+ Route::any('/show', [app\admin\controller\BrandController::class, 'show']);
+ Route::any('/store', [app\admin\controller\BrandController::class, 'store']);
+ Route::any('/update', [app\admin\controller\BrandController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\BrandController::class, 'destroy']);
+ // 车系
+ Route::group('/series', function () {
+ Route::any('/list', [app\admin\controller\BrandSeriesController::class, 'index']);
+ Route::any('/show', [app\admin\controller\BrandSeriesController::class, 'show']);
+ Route::any('/store', [app\admin\controller\BrandSeriesController::class, 'store']);
+ Route::any('/update', [app\admin\controller\BrandSeriesController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\BrandSeriesController::class, 'destroy']);
+ });
+ });
+
+ // 汽车颜色
+ Route::group('/color', function () {
+ Route::any('/list', [app\admin\controller\VehColorController::class, 'index']);
+ Route::any('/show', [app\admin\controller\VehColorController::class, 'show']);
+ Route::any('/store', [app\admin\controller\VehColorController::class, 'store']);
+ Route::any('/update', [app\admin\controller\VehColorController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\VehColorController::class, 'destroy']);
+ });
+
+ // 汽车改装项目
+ Route::group('/modification', function () {
+ Route::any('/list', [app\admin\controller\VehModificationController::class, 'index']);
+ Route::any('/show', [app\admin\controller\VehModificationController::class, 'show']);
+ Route::any('/store', [app\admin\controller\VehModificationController::class, 'store']);
+ Route::any('/update', [app\admin\controller\VehModificationController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\VehModificationController::class, 'destroy']);
+ });
+
+ // 账户
+ Route::group('/account', function () {
+ Route::any('/list', [app\admin\controller\SysAccountController::class, 'index']);
+ Route::any('/show', [app\admin\controller\SysAccountController::class, 'show']);
+ Route::any('/store', [app\admin\controller\SysAccountController::class, 'store']);
+ Route::any('/update', [app\admin\controller\SysAccountController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\SysAccountController::class, 'destroy']);
+ });
+
+ // 账户
+ Route::group('/port', function () {
+ Route::any('/list', [app\admin\controller\SysPortController::class, 'index']);
+ Route::any('/show', [app\admin\controller\SysPortController::class, 'show']);
+ Route::any('/store', [app\admin\controller\SysPortController::class, 'store']);
+ Route::any('/update', [app\admin\controller\SysPortController::class, 'update']);
+ Route::any('/destroy', [app\admin\controller\SysPortController::class, 'destroy']);
+ });
+
});