This commit is contained in:
2026-01-05 14:33:21 +08:00
commit ee348b4925
451 changed files with 39954 additions and 0 deletions
+77
View File
@@ -0,0 +1,77 @@
<?php
namespace app\common\audit;
use Webman\Context;
class AuditBuffer
{
const CTX_KEY = '__audit_buffer__';
public array $changes = []; // 每项:['scene','object_id','field','old','new']
public ?string $action = null; // 业务动作(可覆盖)
public array $meta = []; // 业务自定义元信息(如需扩展入库,可在消费者处处理)
public array $maskFields = ['password','pwd','token','secret','access_token','refresh_token'];
public static function instance(): self
{
$buf = Context::get(self::CTX_KEY);
if (!$buf) {
$buf = new self();
Context::set(self::CTX_KEY, $buf);
}
return $buf;
}
public static function reset(): void
{
Context::set(self::CTX_KEY, new self());
}
public function setAction(?string $action): void
{
$this->action = $action;
}
public function setMeta(array $meta): void
{
$this->meta = $meta + $this->meta;
}
/** 模型字段级变更推送(由 Trait 调用) */
public function pushModelChange(string $scene, $objectId, array $old, array $new): void
{
$keys = array_unique(array_merge(array_keys($old), array_keys($new)));
foreach ($keys as $k) {
$ov = $old[$k] ?? null;
$nv = $new[$k] ?? null;
if ($ov === $nv) continue;
[$ovMasked, $nvMasked] = $this->maskIfNeeded($k, $ov, $nv);
$this->changes[] = [
'scene' => $scene,
'object_id' => $objectId,
'field' => $k,
'old' => $ovMasked,
'new' => $nvMasked,
];
}
}
private function maskIfNeeded(string $field, $old, $new): array
{
foreach ($this->maskFields as $m) {
if (stripos($field, $m) !== false) {
return [$old===null?null:'***', $new===null?null:'***'];
}
}
if (preg_match('/(mobile|phone|tel|idcard|id_card)/i', $field)) {
$mask = function ($v) {
if ($v === null) return null;
$s = (string)$v;
return mb_substr($s, 0, 3).'****'.mb_substr($s, -4);
};
return [$mask($old), $mask($new)];
}
return [$old, $new];
}
}
+121
View File
@@ -0,0 +1,121 @@
<?php
namespace app\common\controller;
use app\common\service\AuthService;
use app\common\validate\UserValidate;
use support\exception\BusinessException;
use support\Request;
class AuthController extends BaseController
{
/**
* 不需要头信息的方法
*/
protected $noNeedHeaderData = ['feishuAuth'];
protected $noNeedLogin = ['feishuScope', 'login', 'register', 'feishuAuth'];
// 调试
public function feishuAuth(Request $request)
{
try {
$code = $request->all();
return $this->success($code);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function feishuScope(Request $request)
{
try {
$result = (new AuthService())->feishuAuthorize($request->get('app_id'), $request->system_code, $request->is_mob);
return $this->success($result);
} catch (\Throwable $e) {
return $this->error($e->getMessage().$e->getLine().$e->getFile());
}
}
public function login(Request $request)
{
try {
$data = $request->all();
if(empty($data['feishu_code']) || empty($data['app_id'])){
throw new BusinessException('参数错误');
}
$result = (new AuthService())->login($data);
return $this->success($result, '登录成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage().$e->getLine().$e->getFile());
}
}
public function register(Request $request)
{
try {
$data = $this->validate(new UserValidate(), $this->requestData($request), $request->login_type.'_register');
$result = (new AuthService())->register($data);
return $this->success($result, '注册成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function refresh(Request $request)
{
try {
$data = $this->requestData($request);
if (!$data['refresh_token'] || !$data['system_code']) return $this->error('参数缺失', 422);
$result = (new AuthService())->refreshToken($data['refresh_token'], $data['system_code']);
return $this->success($result, '刷新成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage(), 401);
}
}
// public function perm(Request $request)
// {
// try {
// $data = $this->requestData($request);
// if (!$data['access_token'] || !$data['system_code']) return $this->error('参数缺失', 422);
// $result = (new AuthService())->logout($data['access_token'], $data['system_code']);
// return $this->success($result, '已登出');
// } catch (\Throwable $e) {}
// }
// public function verify(Request $request)
// {
// try {
// $token = $request->post('access_token') ?: $request->header('authorization');
// $systemCode = $request->post('system_code');
// if (!$token || !$systemCode) return $this->error('参数缺失', 422);
// $payload = (new AuthService())->verifyToken($token, $systemCode);
// return $this->success($payload, '验证成功');
// } catch (\Throwable $e) {
// return $this->error($e->getMessage() ?: '无效或过期的token', 401);
// }
// }
// public function logout(Request $request)
// {
// $token = $request->post('access_token') ?: $request->header('Authorization');
// $systemCode = $request->post('system_code') ?: $request->header('system_code');
// (new AuthService())->logout($token, $systemCode);
// return $this->success([], '已登出');
// }
// public function blockToken(Request $request)
// {
// $token = $request->post('token');
// $systemCode = $request->post('system_code');
// if (!$token || !$systemCode) return $this->error('参数缺失', 422);
// (new AuthService())->blockToken($token, $systemCode);
// return $this->success([], '已强制停用该token');
// }
}
+92
View File
@@ -0,0 +1,92 @@
<?php
namespace app\common\controller;
use support\exception\BusinessException;
use app\common\traits\ResponseTrait;
use app\common\traits\DataTransformer;
use think\Validate;
use support\Request;
class BaseController
{
/**
* 响应处理、数据格式化处理
*/
use ResponseTrait, DataTransformer;
/**
* 验证器
* @var Validate
*/
protected mixed $validator = null;
/**
* @var Model
*/
protected $model = null;
/**
* 不登录不鉴权
* @var array
*/
protected $noNeedLogin = [];
/**
* 登录不鉴权
* @var array
*/
protected $noNeedAuth = [];
/**
* 不用头部数据
* @var array
*/
protected $noNeedHeaderData = [];
/**
* 数据限制
* null 不做限制,任何管理员都可以查看该表的所有数据
* auth 管理员能看到自己以及自己的子管理员插入的数据
* personal 管理员只能看到自己插入的数据
* @var string
*/
protected $dataLimit = null;
/**
* 数据限制字段
*/
protected $dataLimitField = 'admin_id';
/**
* 验证数据
*
* @param Validate $validator 验证器实例
* @param array $data 待验证的数据
* @param string $scene 验证场景
* @return array 验证后的数据
* @throws BusinessException 验证失败时抛出业务异常
*/
public function validate(Validate $validator, array $data, string $scene = ''): array
{
// 如果指定了验证场景,并且验证器支持场景方法,则设置验证场景
if ($scene && method_exists($validator, 'scene')) {
$validator->scene($scene);
}
// 执行数据验证
if (!$validator->check($data)) {
// 验证失败,抛出业务异常,异常信息为验证器返回的错误信息
throw new BusinessException($validator->getError());
}
// 验证成功,返回原始数据
return $data;
}
/**
* 参数处理
*/
public function requestData(Request $request)
{
return $request->all() + $request->basic_data;
}
}
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\admin\service\BrandService;
use support\Request;
class BrandController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
}
/**
* 抓取品牌系列
* @param Request $request
* @return \support\Response
*/
public function crawlSeries(Request $request){
try {
$result = $this->service->crawlSeries($request);
if($result){
return $this->success($result,'成功');
}else{
return $this->error('抓取任务提交失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 创建被抓取且选中的品牌系列
* @param Request $request
* @return \support\Response
*/
public function crawlSeriesCreate(Request $request){
try {
$result = $this->service->crawlSeriesCreate($request);
if($result){
return $this->success([],$result);
}else{
return $this->error('创建失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,121 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\admin\service\BrandSeriesService;
use support\Request;
class BrandSeriesController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
}
/**
* 抓取系列车型
* @param Request $request
* @return \support\Response
*/
public function crawlModels(Request $request){
try {
$result = $this->service->crawlModel($request);
if($result){
return $this->success($result,'抓取成功');
}else{
return $this->error('抓取任务失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 保存抓取的系列车型
* @param Request $request
* @return \support\Response
*/
public function crawlModelCreate(Request $request){
try {
$result = $this->service->crawlModelCreate($request);
if($result){
return $this->success($result,'成功');
}else{
return $this->error('创建失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 关键词抓取品牌、车系、车型
* @param Request $request
* @return \support\Response
*/
public function crawlKeyword(Request $request){
try {
$result = $this->service->crawlKeyword($request);
if($result){
return $this->success($result,'抓取成功');
}else{
return $this->error('抓取任务失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* 保存抓取的系列车型
* @param Request $request
* @return \support\Response
*/
public function crawlKeywordCreate(Request $request){
try {
$result = $this->service->crawlKeywordCreate($request);
if($result){
return $this->success($result,'成功');
}else{
return $this->error('创建失败');
}
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,181 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\model\Country;
use app\common\model\FinPaymentStock;
use app\common\model\StockOrders;
use app\common\model\SysAccount;
use app\common\model\SysCurrency;
use app\common\model\SysDictItem;
use app\common\model\User;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\FinPaymentApplyService;
class FinPaymentApplyController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new FinPaymentApplyService();
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if (isset($data['doc_user_id'])) //内勤
$data['doc_user_name'] = User::where('id', $data['doc_user_id'])->value('name')??'';
if (isset($data['sales_user_id'])) //业务员
$data['sales_user_name'] = User::where('id', $data['doc_user_id'])->value('name')??'';
if (isset($data['corp_id'])) //公司(渠道)
$data['corp_name'] = SysDictItem::where('id', $data['corp_id'])->value('item_label')??'';
if (isset($data['account_id'])){ //收款账号
$data['account_name'] = SysAccount::where('id', $data['account_id'])->value('account_name')??'';
$data['account_short_desc'] = SysAccount::where('id', $data['account_id'])->value('short_desc')??'';
}
if (isset($data['country_id'])) //付款来源国家
$data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr')??'';
if (isset($data['currency_id'])) //付款币种
$data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name')??'';
$OssService = new OssService();
if (!empty($data['submit_files'])){
$data['submit_files'] = json_decode($data['submit_files'], true);
foreach ($data['submit_files'] as $key => $value) {
$data['submit_files'][$key] = [
'file_src' => $value['file_src'],
'file_full' => $OssService->generatePrivateUrl($value['file_src']),
'file_name' => $value['file_name'],
];
}
}else{
$data['submit_files'] = [];
}
if (!empty($data['voucher_file'])){
$data['voucher_file'] = json_decode($data['voucher_file'], true);
foreach ($data['voucher_file'] as $key => $value) {
$data['voucher_file'][$key] = [
'file_src' => $value['file_src'],
'file_full' => $OssService->generatePrivateUrl($value['file_src']),
'file_name' => $value['file_name'],
];
}
}else{
$data['voucher_file'] = [];
}
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['claimed_at'])){
$data['enter_file_last'] = date('Y-m-d H:i:s', ($data['claimed_at']+86400)); //入账资料最后提交时间
$data['claimed_at'] = date('Y-m-d H:i:s', $data['claimed_at']); //认领时间
}
if (isset($data['id'])){
$finPaymentStock = FinPaymentStock::where('payment_apply_id', $data['id'])->get();
$stock = [];
$stock_order_no = [];
foreach ($finPaymentStock as $v) {
$stock[$v['pi_no']]['pi_no'] = $v['pi_no'];
$stock[$v['pi_no']]['stock_id'][] = [$v['stock_id']];
$stockOrders = StockOrders::where('id', $v['stock_id'])->first();
$stock_order_no[] = $stockOrders['order_no'];
}
$data['stock'] = array_values($stock);
$data['stock_order_no'] = $stock_order_no;
}
return $data;
}
/**
* 数据格式化
*
* @param array $data
* @return array
*/
public function showFormat($data)
{
if (isset($data['doc_user_id'])) //内勤
$data['doc_user_name'] = User::where('id', $data['doc_user_id'])->value('name')??'';
if (isset($data['sales_user_id'])) //业务员
$data['sales_user_name'] = User::where('id', $data['doc_user_id'])->value('name')??'';
if (isset($data['corp_id'])) //公司(渠道)
$data['corp_name'] = SysDictItem::where('id', $data['corp_id'])->value('item_label')??'';
if (isset($data['account_id'])){ //收款账号
$data['account_name'] = SysAccount::where('id', $data['account_id'])->value('account_name')??'';
$data['account_short_desc'] = SysAccount::where('id', $data['account_id'])->value('short_desc')??'';
}
if (isset($data['country_id'])) //付款来源国家
$data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr')??'';
if (isset($data['currency_id'])) //付款币种
$data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name')??'';
$OssService = new OssService();
if (!empty($data['submit_files'])){
$data['submit_files'] = json_decode($data['submit_files'], true);
foreach ($data['submit_files'] as $key => $value) {
$data['submit_files'][$key] = [
'file_src' => $value['file_src'],
'file_full' => $OssService->generatePrivateUrl($value['file_src']),
'file_name' => $value['file_name'],
];
}
}else{
$data['submit_files'] = [];
}
if (!empty($data['voucher_file'])){
$data['voucher_file'] = json_decode($data['voucher_file'], true);
foreach ($data['voucher_file'] as $key => $value) {
$data['voucher_file'][$key] = [
'file_src' => $value['file_src'],
'file_full' => $OssService->generatePrivateUrl($value['file_src']),
'file_name' => $value['file_name'],
];
}
}else{
$data['voucher_file'] = [];
}
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']);
$finPaymentStock = FinPaymentStock::where('payment_apply_id', $data['id'])->get();
$stock = [];
foreach ($finPaymentStock as $v) {
$stock[$v['pi_no']]['pi_no'] = $v['pi_no'];
$stock[$v['pi_no']]['stock_id'][] = [$v['stock_id']];
}
$data['stock'] = array_values($stock);
return $data;
}
/**
* 作废
* @param Request $request
* @return \support\Response
*/
public function delete(Request $request)
{
try {
$id = $request->input('id');
$raw = $this->service->delete($id);
return $this->success($raw);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,195 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\model\Country;
use app\common\model\FinPaymentApply;
use app\common\model\FinPaymentStock;
use app\common\model\SysAccount;
use app\common\model\SysCurrency;
use app\common\model\SysDictItem;
use app\common\model\User;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\FinReceiptService;
use support\Redis;
use support\Request;
class FinReceiptController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new FinReceiptService();
}
/**
* 确认入账
* @param Request $request
* @return \support\Response
*/
public function credit(Request $request)
{
try {
$id = $request->input('id');
$exchange_rate = $request->input('exchange_rate');
if(empty($exchange_rate) || !is_numeric($exchange_rate)){
return $this->error('请输入汇率');
}
$raw = $this->service->credit($id,$exchange_rate);
return $this->success($raw);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function show(Request $request)
{
try {
$raw = $this->service->serviceShow($request);
$data = $this->transformData($raw, method_exists($this, 'showFormat')
? [$this, 'showFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 更新
*
* @param Request $request 请求对象
* @return mixed 返回更新成功的数据或信息
*/
public function payment(Request $request)
{
try {
$data = $this->validate($this->service->getValidator(), $request->post(), 'update');
$res = $this->service->serviceUpdatePayment($request, $data);
return $this->success([], '更新成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if (isset($data['created_at'])){
$data['claim_timeout'] = (($data['created_at'] < (time()-86400)) && empty($data['payment_apply_id'])) ?1:0;
$data['claim_timeout_time'] = date('Y-m-d H:i:s', $data['created_at']+86400);
$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['arrived_at']))
$data['arrived_at'] = date('Y-m-d H:i:s', $data['arrived_at']);
if (isset($data['received_at'])){
$data['received_at'] = date('Y-m-d H:i:s', $data['received_at']);
$voucher_no_timeout_hour = redis::get('voucher_no_timeout_hour');
if(!empty($voucher_no_timeout_hour)){
$data['voucher_no_timeout_time'] = date('Y-m-d H:i:s', time()+(60*60*$voucher_no_timeout_hour));
}
}
if (isset($data['account_id'])) { //收款账号
$data['account_name'] = SysAccount::where('id', $data['account_id'])->value('account_name')??'';
$data['account_short_desc'] = SysAccount::where('id', $data['account_id'])->value('short_desc')??'';
}
if (isset($data['country_id'])) //付款来源国家
$data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr')??'';
if (isset($data['currency_id'])) //付款币种
$data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name')??'';
$OssService = new OssService();
if (!empty($data['fx_receipt_file'])){
$data['fx_receipt_file'] = json_decode($data['fx_receipt_file'], true);
foreach ($data['fx_receipt_file'] as $key => $value) {
$data['fx_receipt_file'][$key] = [
'file_src' => $value['file_src'],
'file_full' => $OssService->generatePrivateUrl($value['file_src']),
'file_name' => $value['file_name'],
];
}
}else{
$data['fx_receipt_file'] = [];
}
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['arrived_at']))
$data['arrived_at'] = date('Y-m-d H:i:s', $data['arrived_at']);
if (isset($data['received_at']))
$data['received_at'] = date('Y-m-d H:i:s', $data['received_at']);
if (isset($data['account_id'])) { //收款账号
$data['account_name'] = SysAccount::where('id', $data['account_id'])->value('account_name')??'';
$data['account_short_desc'] = SysAccount::where('id', $data['account_id'])->value('short_desc')??'';
}
if (isset($data['country_id'])) //付款来源国家
$data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr')??'';
if (isset($data['currency_id'])) //付款币种
$data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name')??'';
$OssService = new OssService();
if (!empty($data['fx_receipt_file'])){
$data['fx_receipt_file'] = json_decode($data['fx_receipt_file'], true);
foreach ($data['fx_receipt_file'] as $key => $value) {
$data['fx_receipt_file'][$key] = [
'file_src' => $value['file_src'],
'file_full' => $OssService->generatePrivateUrl($value['file_src']),
'file_name' => $value['file_name'],
];
}
}else{
$data['fx_receipt_file'] = [];
}
//查询关联的付款记录
if (!empty($data['payment_apply_id'])) {
$paymentApply = FinPaymentApply::where('id', $data['payment_apply_id'])->first();
if(!$paymentApply)
return $data;
$paymentApply = $paymentApply->toArray();
$paymentApply['created_at'] = strtotime($paymentApply['created_at']);
$paymentApply['updated_at'] = strtotime($paymentApply['updated_at']);
$paymentApply = (new FinPaymentApplyController())->showFormat($paymentApply);
$data['payment_apply'] = $paymentApply;
}
return $data;
}
/**
* 收款记录统计
* @param Request $request
* @return \support\Response
*/
public function statistics(Request $request)
{
try {
$raw = $this->service->statistics();
return $this->success($raw);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,98 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\model\Country;
use app\common\model\SysAccount;
use app\common\model\SysCurrency;
use app\common\model\User;
use app\common\service\OssService;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\FinReceiptHisService;
use support\Request;
class FinReceiptHisController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new FinReceiptHisService();
}
/**
* 列表页数据格式化
*
* @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['arrived_at']))
$data['arrived_at'] = date('Y-m-d H:i:s', $data['arrived_at']);
if (isset($data['received_at']))
$data['received_at'] = date('Y-m-d H:i:s', $data['received_at']);
if (isset($data['account_id'])) { //收款账号
$data['account_name'] = SysAccount::where('id', $data['account_id'])->value('account_name')??'';
$data['account_short_desc'] = SysAccount::where('id', $data['account_id'])->value('short_desc')??'';
}
if (isset($data['country_id'])) //付款来源国家
$data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr')??'';
if (isset($data['currency_id'])) //付款币种
$data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name')??'';
if (!empty($data['fx_receipt_file'])){
$data['fx_receipt_file_full'] = (new OssService)->generatePrivateUrl($data['fx_receipt_file']);
}elseif (isset($data['fx_receipt_file'])){
$data['fx_receipt_file_full'] = '';
}
if (isset($data['created_by']))
$data['created_by'] = User::where('id', $data['created_by'])->value('name')??'';
if (isset($data['updated_by']))
$data['updated_by'] = User::where('id', $data['updated_by'])->value('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']);
if (isset($data['arrived_at']))
$data['arrived_at'] = date('Y-m-d H:i:s', $data['arrived_at']);
if (isset($data['received_at']))
$data['received_at'] = date('Y-m-d H:i:s', $data['received_at']);
if (isset($data['account_id'])){ //收款账号
$data['account_name'] = SysAccount::where('id', $data['account_id'])->value('account_name')??'';
$data['account_short_desc'] = SysAccount::where('id', $data['account_id'])->value('short_desc')??'';
}
if (isset($data['country_id'])) //付款来源国家
$data['country_name'] = Country::where('id', $data['country_id'])->value('cn_addr')??'';
if (isset($data['currency_id'])) //付款币种
$data['currency_name'] = SysCurrency::where('id', $data['currency_id'])->value('currency_name')??'';
if (!empty($data['fx_receipt_file'])){
$data['fx_receipt_file_full'] = (new OssService)->generatePrivateUrl($data['fx_receipt_file']);
}elseif (isset($data['fx_receipt_file'])){
$data['fx_receipt_file_full'] = '';
}
if (isset($data['created_by']))
$data['created_by'] = User::where('id', $data['created_by'])->value('name')??'';
if (isset($data['updated_by']))
$data['updated_by'] = User::where('id', $data['updated_by'])->value('name')??'';
return $data;
}
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionApproveService;
class InvRequisitionApproveController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new InvRequisitionApproveService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionAttachmentService;
class InvRequisitionAttachmentController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new InvRequisitionAttachmentService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionItemService;
class InvRequisitionItemController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new InvRequisitionItemService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionItemReturnAttachmentService;
class InvRequisitionItemReturnAttachmentController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new InvRequisitionItemReturnAttachmentService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\InvRequisitionItemReturnService;
class InvRequisitionItemReturnController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new InvRequisitionItemReturnService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,52 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\MessageNotificationsService;
use app\common\model\MessageNotifications;
use support\Request;
class MessageNotificationsController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new MessageNotificationsService();
}
/**
* 列表页数据格式化
*
* @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']);
return $data;
}
protected function showFormat($data)
{
if (isset($data['created_at']))
$data['created_at'] = date('Y-m-d H:i:s', $data['created_at']);
return $data;
}
public function push(Request $request)
{
try {
$data = $this->validate($this->service->getValidator(), $request->post(), 'store');
$res = $this->service->servicePush($request, $data);
return $this->success($res, '推送成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,95 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\MessageUserStatusService;
use support\Request;
class MessageUserStatusController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new MessageUserStatusService();
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if (isset($data['read_at']) && $data['read_at'] !== null) {
$data['read_at'] = date('Y-m-d H:i:s', $data['read_at']);
} else {
$data['read_at'] = ' - ';
}
if (isset($data['message']))
$data['message']['created_at'] = date('Y-m-d H:i:s', $data['message']['created_at']);
return $data;
}
protected function showFormat($data)
{
if (isset($data['read_at']) && $data['read_at'] !== null) {
$data['read_at'] = date('Y-m-d H:i:s', $data['read_at']);
} else {
$data['read_at'] = ' - ';
}
if (isset($data['message']))
$data['message']['created_at'] = date('Y-m-d H:i:s', $data['message']['created_at']);
return $data;
}
protected function unReadFormat($data)
{
foreach ($data as &$item) {
if (isset($item['read_at']) && $item['read_at'] !== null) {
$item['read_at'] = date('Y-m-d H:i:s', $item['read_at']);
} else {
$item['read_at'] = ' - ';
}
if (isset($item['message'])) {
$item['message']['created_at'] = date('Y-m-d H:i:s', $item['message']['created_at']);
}
}
return $data;
}
public function read(Request $request)
{
try {
$data = $this->validate($this->service->getValidator(), $request->post(), 'read');
$this->service->serviceRead($request, $data);
return $this->success([], '操作成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function listUnRead(Request $request)
{
try {
$raw = $this->service->serviceListUnRead($request);
$data = $this->transformData($raw, method_exists($this, 'unReadFormat')
? [$this, 'unReadFormat']
: null);
$data = [
'list' => $data,
'counts' => count($data)
];
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
+136
View File
@@ -0,0 +1,136 @@
<?php
namespace app\common\controller;
use support\Request;
use support\Response;
use app\common\utils\FeishuMessage;
use app\inquiry\service\InquiryLogService;
use app\common\model\CrmCustomer;
use app\common\model\InquiryLog;
use app\common\model\User;
use support\exception\BusinessException;
class NotifyController
{
/**
* 不用头部数据
* @var array
*/
protected $noNeedHeaderData = ['feishuCallback', 'feishuEvent'];
/**
* 不登录不鉴权
* @var array
*/
protected $noNeedLogin = ['feishuCallback', 'feishuEvent'];
/**
* 飞书回调
* @param Request $request
* @return Response
*/
public function feishuCallback(Request $request)
{
try {
$param = $request->post();
// 解析数据
// $param = json_decode($param['event'], true);
$orderSn = $param['event']['action']['value'];
if (strpos($orderSn, '"') !== false) {
$orderSn = str_replace('"', '', $orderSn);
}
// 处理询单&客户线索信息
$openId = $param['event']['operator']['open_id'];
// 获取询单
$order = InquiryLog::with(['channelInfo', 'countryInfo', 'enter'])->where('order_no', $orderSn)->first();
if (!$order) {
return $this->error('未找到询单记录');
}
// 获取客户xians
$customer = CrmCustomer::where('sn', $orderSn)->first();
if (!$customer) {
return $this->error('未找到客户线索');
}
// 获取用户
$uinfo = User::where('open_id', $openId)->first();
// 更新客户线索
$customer->user_id = $uinfo->id;
// 更新询单数据
$order->recipient = $uinfo->id;
$order->status = 2;
$order->t_time = time();
// 保存
if (!$order->save() || !$customer->save()) {
return $this->error('跟踪失败');
}
// 获取飞书消息模板
$feishuMessage = new FeishuMessage();
$content = $feishuMessage->groupUpdateTemplates(
(new InquiryLogService())->qualityName($order->quality),
$order->order_no,
$order->channelInfo ? $order->channelInfo->name : '',
$order->countryInfo ? $order->countryInfo->cn_addr : '',
$order->enter ? $order->enter->name : '',
$order->r_time ? date('Y-m-d H:i:s', $order->r_time) : '',
$order->t_time ? date('Y-m-d H:i:s', $order->t_time) : ''
);
// 组装飞书消息模板
$data = '{
"toast": {
"type": "success",
"content": "操作成功"
},
"card": {
"type": "raw",
"data": '.$content.'
}
}';
// 响应消息
return new Response(200, ['Content-Type' => 'application/json'], $data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function error($msg = '')
{
$data = '{
"toast": {
"type": "error",
"content": "'.$msg.'"
}
}';
return new Response(200, ['Content-Type' => 'application/json'], $data);
}
/**
* 飞书事件
* @param Request $request
* @return Response
*/
public function feishuEvent(Request $request)
{
try {
$data = $request->post();
var_dump($data);
return json($data);
} catch (\Throwable $e) {
return json($e->getMessage());
}
}
}
+233
View File
@@ -0,0 +1,233 @@
<?php
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;
use app\common\service\SystemsService;
use app\common\service\UserService;
use support\Cache;
use app\common\service\PermService;
use app\common\service\UserGroupService;
class PresetController extends BaseController
{
protected $noNeedLogin = ['corps', 'feishuApp', 'systems'];
protected $noNeedHeaderData = ['corps', 'feishuApp', 'systems'];
public function corps()
{
try {
$result = (new CorpService())->getList();
return $this->success($result, '获取公司列表');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function feishuApp(Request $request)
{
try {
$corpId = $request->get('corp_id');
$systemId = $request->get('system_id');
$result = (new CorpFeishuAppService())->getFeishuApp($corpId, $systemId);
return $this->success($result, '获取飞书应用信息');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function systems()
{
try {
$result = (new SystemsService())->getList();
return $this->success($result, '获取系统列表');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function users(Request $request)
{
try {
$result = (new UserService())->getList($request);
return $this->success($result, '获取用户列表');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function roles()
{
try {
$result = (new RoleService)->getList();
return $this->success($result, '获取角色列表');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
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(Request $request)
{
try {
$params = $request->all();
$result = (new SysPortService)->getList($params);
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()
{
try {
Cache::clear();
return $this->success([], '操作成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function menus(Request $request)
{
try {
$uid = $request->user->uid;
$systemCode = $request->system_code;
$permService = new PermService();
$menuTree = $permService->getMenuTree($uid, $systemCode);
$permissionCodes = $permService->getPermissionCodes($uid, $systemCode);
$result = [
'menu' => $menuTree,
'permissions' => $permissionCodes
];
return $this->success($result, '获取菜单权限');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function userGroup(Request $request)
{
try {
$result = (new UserGroupService)->userGroup($request);
return $this->success($result, '获取分组');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
public function userGroupScene(Request $request)
{
try {
$result = (new UserGroupService)->userGroupScene($request);
return $this->success($result, '获取分组场景');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\PurchaseOrderItemsService;
class PurchaseOrderItemsController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new PurchaseOrderItemsService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,137 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\PurchaseOrdersService;
use support\Request;
class PurchaseOrdersController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new PurchaseOrdersService();
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if (isset($data['records']) && count($data['records']) > 0) {
foreach ($data['records'] as &$record) {
$contractFile = $record['contract_file'] ? explode(',', $record['contract_file']) : [];
$contractFileUrl = [];
if (count($contractFile) > 0) {
foreach ($contractFile as $file) {
$contractFileUrl[] = (new \app\common\service\OssService)->generatePrivateUrl($file);
}
}
$result = [
'id' => $record['id'],
'order_no' => $record['order_no'],
'pi_no' => $record['pi_no'],
'buyer_id' => $record['buyer_id'],
'buyer_name' => $record['buyer_name'],
'contract_file' => $contractFile,
'contract_file_url' => $contractFileUrl,
'status' => $record['status'],
'status_text' => array_flip(\app\common\service\SysDictService::pluckKeyValueByCode('purchase_status'))[$record['status']],
'remark' => $record['remark'],
'created_at' => date('Y-m-d H:i:s', $record['created_at']),
'updated_at' => date('Y-m-d H:i:s', $record['updated_at']),
];
$record = $result;
}
unset($record);
}
return $data;
}
/**
* 详情页数据格式化
*
* @param array $data
* @return array
*/
protected function showFormat($data)
{
$contractFile = $data['contract_file'] ? explode(',', $data['contract_file']) : [];
$contractFileUrl = [];
if (count($contractFile) > 0) {
foreach ($contractFile as $file) {
$contractFileUrl[] = (new \app\common\service\OssService)->generatePrivateUrl($file);
}
}
$result = [
'id' => $data['id'],
'order_no' => $data['order_no'],
'pi_no' => $data['pi_no'],
'buyer_id' => $data['buyer_id'],
'buyer_name' => $data['buyer_name'],
'contract_file' => $contractFile,
'contract_file_url' => $contractFileUrl,
'status' => $data['status'],
'remark' => $data['remark']
];
$temps = [];
if (isset($data['items']) && count($data['items']) > 0) {
foreach ($data['items'] as $record) {
if (!in_array($record['stockOrder']['id'], array_keys($temps))) {
$temps[$record['stockOrder']['id']] = [
'id' => $record['stockOrder']['id'],
'order_no' => $record['stockOrder']['order_no'],
'salesperson_snapshot' => $record['stockOrder']['salesperson_snapshot'],
'biz_date' => date('Y-m-d', $record['stockOrder']['biz_date'])
];
}
$temps[$record['stockOrder']['id']]['stock_order_items'][] =[
'id' => $record['stockOrderItems']['id'],
'model_snapshot' => $record['stockOrderItems']['model_snapshot'],
'unique_id' => $record['stockOrderItems']['unique_id'],
];
}
}
$result['stock_order'] = array_values($temps);
return $result;
}
/**
* 前置查询处理
*
* @param Request $request
* @return array
*/
public function preQueryData(Request $request)
{
try {
$data = $this->service->preQueryData($request->all());
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 重提
*
* @param Request $request
* @return mixed
*/
public function resubmit(Request $request)
{
try {
$raw = $this->service->serviceResubmit($request, $request->all());
return $this->success($raw);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,82 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\ResourceService;
use support\Request;
class ResourceController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new ResourceService();
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function allFormat($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 listTree(Request $request)
{
try {
$raw = $this->service->serviceListAll($request);
$data = $this->transformData($raw, method_exists($this, 'allFormat')
? [$this, 'allFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 菜单
*/
public function menuList(Request $request)
{
try {
$raw = $this->service->serviceMenuList($request);
$data = $this->transformData($raw, method_exists($this, 'allFormat')
? [$this, 'allFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 菜单
*/
public function menuTreeList(Request $request)
{
try {
$raw = $this->service->serviceMenuTreeList($request);
$data = $this->transformData($raw, method_exists($this, 'allFormat')
? [$this, 'allFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\StockOrdersFilesService;
class StockOrdersFilesController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new StockOrdersFilesService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\SysOpLogService;
class SysOpLogController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new SysOpLogService();
}
/**
* 列表页数据格式化
*
* @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;
}
}
@@ -0,0 +1,53 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\model\Country;
use app\common\traits\crud\CrudControllerTrait;
use app\admin\service\SysPortService;
class SysPortController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
}
}
@@ -0,0 +1,35 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\SysUpdateLogService;
class SysUpdateLogController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new SysUpdateLogService();
}
/**
* 列表页数据格式化
*
* @param array $data
* @return array
*/
protected function indexFormat($data)
{
if (isset($data['update_time']))
$data['update_time'] = date('Y-m-d H:i:s', $data['update_time']);
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;
}
}
+302
View File
@@ -0,0 +1,302 @@
<?php
namespace app\common\controller;
use app\common\service\OssService;
use app\common\service\UploadedFilesService;
use app\common\service\UploadService;
use app\common\traits\ResponseTrait;
use support\Log;
use support\Request;
use support\exception\BusinessException;
use Shopwwi\WebmanFilesystem\Facade\Storage;
class UploadController
{
use ResponseTrait;
protected $noNeedLogin = ['proxy'];
protected $noNeedHeaderData = ['proxy'];
public function upload(Request $request)
{
try {
$scene = $request->input('scene', 'image');
$file = $request->file('file');
if ($file && $file->isValid()) {
$fileName = md5($file->getUploadName() . time()).'.'.$file->getUploadExtension();
$pathUrl = '/uploads/'.$scene.'/'.date('Ymd').'/'.$fileName;
$fullPathUrl = public_path() . $pathUrl;
$file->move($fullPathUrl);
$data = [
'domain' => getenv('MAIN_DOMAIN'),
'file_url' => $pathUrl,
'full_url' => getenv('MAIN_DOMAIN') . $pathUrl,
'scene' => $scene,
];
// 记录文件信息到数据库
try {
$uploadedFilesService = new UploadedFilesService();
$partition = $scene;
$category = $request->input('category', 'general');
$fileInfo = [
'file_name' => basename($fileName),
'file_path' => $pathUrl,
'file_size' => $file->getSize(),
'file_type' => $file->getUploadMimeType(),
'original_name' => $file->getUploadName(),
];
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category);
$data['file_id'] = $recordResult['id'];
$data['partition'] = $partition;
$data['category'] = $category;
} catch (\Throwable $e) {
// 记录失败不影响上传结果,只记录日志
Log::error('记录文件信息失败: ' . $e->getMessage());
}
return $this->success($data, 'upload success');
}
return $this->error('file not found');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
// 上传单文件附件
public function uploadFile(Request $request)
{
try {
$scene = $request->input('scene');
$file = $request->file('file');
if (!$file || !$file->isValid()) {
return $this->error('上传失败');
}
if (empty($scene)) {
// return $this->error('上传场景不能为空');
$sceneUrl = '';
}else{
$sceneUrl = $scene . '/';
}
$originalName = $file->getUploadName();
$ossservice = new OssService();
$mimes = $ossservice->getMimeTypes(['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'zip', 'rar']);
$result = Storage::adapter('oss')
->path(config('oss.oss_main_dir') . $sceneUrl . date('Ymd'))
->size(1024*1024*5)
->extYes($mimes)
->upload($file);
$data = [
'original_name' => $originalName,
'file_name' => $result->file_name,
'file_url' => $ossservice->generatePrivateUrl($result->file_name)
];
// 记录文件信息到数据库
$category = $request->input('category', 'general');
$res = $this->recordFileInfo($result,$request,$file,$scene,$category);
$data = array_merge($data, $res);
return $this->success($data);
}catch (\Throwable $e){
return $this->error($e->getMessage());
}
}
// 上传单文件图片
public function uploadImage(Request $request)
{
try {
$scene = $request->input('scene');
$file = $request->file('image');
if (!$file || !$file->isValid()) {
return $this->error('上传失败');
}
if (empty($scene)) {
// return $this->error('上传场景不能为空');
$sceneUrl = '';
}else{
$sceneUrl = $scene . '/';
}
$result = Storage::adapter('oss')
->path(config('oss.oss_main_dir') . $sceneUrl . date('Ymd'))
->size(1024*1024*5)
->extYes(['image/jpeg','image/png'])
->extNo(['image/gif'])
->upload($file);
$ossservice = new OssService();
$data = [
'href' => $result->file_name,
'alt' => '',
'url' => $ossservice->generatePrivateUrl($result->file_name)
];
// 记录文件信息到数据库
$category = $request->input('category', 'general');
$res = $this->recordFileInfo($result,$request,$file,$scene,$category);
$data = array_merge($data, $res);
return json(['errno' => 0, 'data' => $data]);
// return $this->success($data);
} catch (\Throwable $e) {
return json(['errno' => 1, 'message' => $e->getMessage()]);
// return $this->error($e->getMessage());
}
}
public function recordFileInfo($result, $request, $file, $scene, $category)
{
try {
$uploadedFilesService = new UploadedFilesService();
$partition = $scene;
$fileInfo = [
'file_name' => basename($result->file_name),
'file_path' => $result->file_name, // OSS存储路径
'file_size' => $file->getSize(),
'file_type' => $file->getUploadMimeType(),
'original_name' => $file->getUploadName(),
];
$partition = !empty($partition)?$partition:'other';
$category = !empty($category)?$category:'other';
$recordResult = $uploadedFilesService->recordFileInfo($fileInfo, $request, $partition, $category);
$data = [];
$data['file_id'] = $recordResult['id'];
$data['partition'] = $partition;
$data['category'] = $category;
return $data;
} catch (\Throwable $e) {
// 记录失败不影响上传结果,只记录日志
Log::error('记录文件信息失败: ' . $e->getMessage());
return [];
}
}
/**
* 获取文件信息
*
* @param Request $request
* @return \support\Response
*/
public function getFileInfo(Request $request)
{
try {
$fileId = $request->input('id');
if (!$fileId) {
return $this->error('文件ID不能为空');
}
$uploadedFilesService = new UploadedFilesService();
$fileInfo = $uploadedFilesService->getFileInfo($fileId);
if (!$fileInfo) {
return $this->error('文件不存在');
}
return $this->success($fileInfo);
} catch (\Throwable $e) {
return $this->error('获取文件信息失败: ' . $e->getMessage());
}
}
/**
* 删除文件
*
* @param Request $request
* @return \support\Response
*/
public function deleteFile(Request $request)
{
try {
$fileId = $request->input('id');
$path = $request->input('path');
$uploadedFilesService = new UploadedFilesService();
if(!empty($path) && empty($fileId)){
$where = ['file_path' => $path];
$file = $uploadedFilesService->getFile($where);
$fileId = $file->id;
}elseif(empty($path) && !empty($fileId)){
$where = ['id' => $fileId];
$file = $uploadedFilesService->getFile($where);
$path = $file->file_path;
}
if (!$fileId) {
return $this->error('文件ID与路径不能为空');
}
// 删除 OSS 上的文件
$ossService = new OssService();
$ossService->deleteFile($path);
$result = $uploadedFilesService->deleteFile($fileId);
if ($result) {
return $this->success([], '文件删除成功');
} else {
return $this->error('文件删除失败');
}
} catch (\Throwable $e) {
return $this->error('文件删除失败: ' . $e->getMessage());
}
}
/**
* 获取分区配置
*
* @param Request $request
* @return \support\Response
*/
public function getPartitionConfig(Request $request)
{
try {
$uploadedFilesService = new UploadedFilesService();
$config = $uploadedFilesService->getPartitionConfig();
return $this->success($config);
} catch (\Throwable $e) {
return $this->error('获取分区配置失败: ' . $e->getMessage());
}
}
public function proxy(Request $request)
{
$filePath = $request->get('file'); // 原OSS文件路径
try {
// 生成签名URL
$signedUrl = (new \app\common\service\OssService())->generatePrivateUrl($filePath);
// 获取图片数据并返回
$imageData = file_get_contents($signedUrl);
// 根据文件类型设置Content-Type
$mime = mime_content_type('data://application/octet-stream;base64,'.base64_encode($imageData));
return response($imageData, 200, [
'Content-Type' => $mime,
'Cache-Control' => 'public, max-age=600' // 客户端缓存10分钟
]);
} catch (\Exception $e) {
return response('Image not found '.$e->getMessage(), 404);
}
}
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\UsedcarCrawlResultsService;
class UsedcarCrawlResultsController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new UsedcarCrawlResultsService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\UsedcarCrawlResultsImagesService;
class UsedcarCrawlResultsImagesController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new UsedcarCrawlResultsImagesService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
+128
View File
@@ -0,0 +1,128 @@
<?php
namespace app\common\controller;
use app\common\traits\crud\CrudControllerTrait;
use support\Request;
use app\common\service\UserService;
class UserController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new UserService();
}
/**
* 获取组员列表
*
* @param Request $request 请求对象
* @return mixed 返回分页数据及总数
*/
public function team(Request $request)
{
try {
$raw = $this->service->serviceTeam($request);
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
? [$this, 'indexFormat']
: null);
return $this->success($data);
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 标记组员离职
*
* @param Request $request 请求对象
* @return mixed 返回分页数据及总数
*/
public function resignMember(Request $request)
{
try {
$userId = $request->get('user_id');
if(empty($userId)){
return $this->error('组员id不能为空');
}
$user = $this->service->resignMember($request);
return $this->success($user, '获取用户信息');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 用户信息(登录后调用)
*/
public function info(Request $request)
{
try {
$uid = $request->user->uid;
$systemCode = $request->system_code;
$result = (new UserService())->getUserInfo($uid, $systemCode);
return $this->success($result, '获取用户信息');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 用户信息
*/
public function getUser(Request $request)
{
try {
$uid = $request->user->uid;
$corp_abbr = $request->basic_data['corp_abbr'];
$result = (new UserService())->getUser($uid,$corp_abbr);
return $this->success($result, '获取用户信息');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 编辑用户
*/
public function edit(Request $request)
{
try {
$uid = $request->user->uid;
$data = $request->all();
$result = (new UserService())->edit($uid,$data);
unset($result['password']);
unset($result['union_id']);
unset($result['open_id']);
unset($result['tenant_key']);
return $this->success($result, '编辑成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
/**
* 修改密码
* @param Request $request
* @return \support\Response
* @throws \Random\RandomException
*/
public function savePassword(Request $request)
{
try {
$uid = $request->user->uid;
$data = $request->all();
$result = (new UserService())->savePassword($uid,$data);;
return $this->success($result, '编辑成功');
} catch (\Throwable $e) {
return $this->error($e->getMessage());
}
}
}
@@ -0,0 +1,56 @@
<?php
namespace app\common\controller;
use app\common\model\User;
use app\common\traits\crud\CrudControllerTrait;
use app\admin\service\VehColorService;
class VehColorController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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']);
if (isset($data['created_by']) && $data['created_by'])
$data['created_by_name'] = User::where('id', $data['created_by'])->value('name');
if (isset($data['updated_by']) && $data['updated_by'])
$data['updated_by_name'] = User::where('id', $data['updated_by'])->value('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']);
if (isset($data['created_by']) && $data['created_by'])
$data['created_by_name'] = User::where('id', $data['created_by'])->value('name');
if (isset($data['updated_by']) && $data['updated_by'])
$data['updated_by_name'] = User::where('id', $data['updated_by'])->value('name');
return $data;
}
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\VehDictI18nService;
class VehDictI18nController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\VehDictMappingService;
class VehDictMappingController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
// }
}
@@ -0,0 +1,47 @@
<?php
namespace app\common\controller;
use app\common\traits\crud\CrudControllerTrait;
use app\admin\service\VehModificationService;
class VehModificationController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
}
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\VehMoneyValueService;
class VehMoneyValueController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->service = new VehMoneyValueService();
}
/**
* 列表页数据格式化
*
* @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;
// }
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\VehVehicleListingService;
class VehVehicleListingController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
// }
}
@@ -0,0 +1,223 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\model\BrandSeries;
use app\common\service\VehModificationService;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\VehVehicleSkuService;
use support\exception\BusinessException;
use support\Request;
class VehVehicleSkuController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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)
{
return $this->error('请优先抓取车辆信息,如抓取不到相应车型请联系管理员,暂停手动录入车辆信息');
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 preset(Request $request){
try {
$series_id = $request->input('series_id');
$series_code = BrandSeries::where('id', $series_id)->value('series_code');
$data = [
'series_code' => $series_code,
];
$result = $this->service->getList($data);
return $this->success($result, '获取车型列表');
} 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',
];
}
}
@@ -0,0 +1,33 @@
<?php
namespace app\common\controller;
use app\common\controller\BaseController;
use app\common\traits\crud\CrudControllerTrait;
use app\common\service\VehVehicleUnitService;
class VehVehicleUnitController extends BaseController
{
use CrudControllerTrait;
protected $service;
public function __construct()
{
$this->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;
// }
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\ApprovalFlows;
class ApprovalFlowsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = ApprovalFlows::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\ApprovalInstances;
class ApprovalInstancesLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = ApprovalInstances::class;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\ApprovalRecords;
class ApprovalRecordsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = ApprovalRecords::class;
}
+597
View File
@@ -0,0 +1,597 @@
<?php
namespace app\common\logic;
use app\common\model\Corp;
use app\common\model\CorpFeishuApp;
use app\common\model\Resource;
use app\common\model\UserTokenLog;
use app\common\model\Systems;
use app\common\model\User;
use app\common\model\UserSn;
use app\common\utils\Feishu;
use app\common\utils\Jwt;
use support\Redis;
use support\exception\BusinessException;
use support\Log;
class AuthLogic
{
/**
* 账号密码登录
*/
public function uPwdLogin(array $data): array
{
$user = $this->validateUser($data['account'], $data['password']);
$system = $this->validateSystem($data['system_code']);
$this->validateSystemPermission($user, $system);
return $this->generateTokensAndReturn($user, $system, $data);
}
/**
* 飞书登录
* 如果用户不存在则新增用户信息
*/
public function feishuLogin(array $data): array
{
$feishuUserInfo = $this->getFeishuUserInfo($data);
var_dump($feishuUserInfo);
return $feishuUserInfo;
$user = $this->getOrCreateUser($feishuUserInfo);
$system = $this->validateSystem($data['system_code']);
if ($user->isLogin) {
$this->validateSystemPermission($user, $system);
}
return $this->generateTokensAndReturn($user, $system, $data);
}
/**
* 注册
*/
public function register(array $data)
{
try {
// 获取可用用户编号
$sn = $this->getAvailableUserSn();
$data['sn'] = $sn->user_sn;
// 对密码进行哈希处理
$data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
// 获取企业ID
$corpInfo = $this->validateCorp($data['corp_abbr']);
$data['corp_id'] = $corpInfo->id;
// 处理账户
$data = $data + normalizeAccount($data['account']);
// 创建用户记录
$user = $this->createUser($data);
// 更新用户编号的用户 ID
$this->updateUserId($user->id, $sn->user_sn);
$system = $this->validateSystem($data['system_code']);
return $this->generateTokensAndReturn($user, $system, $data);
} catch (\Throwable $e) {
throw $e;
}
}
/**
* 查找或创建飞书用户
*/
private function getOrCreateUser(array $feishuUserInfo)
{
try {
$phone = $this->sanitizePhone($feishuUserInfo['mobile'] ?? '');
$email = $feishuUserInfo['enterprise_email'];
// $user = User::where('corp_id', $feishuUserInfo['corp_id'])
// ->where(function($query) use ($phone, $email) {
// $query->where('phone', $phone)
// ->orWhere('email', $email);
// })
// ->first();
$userByPhone = User::where('corp_id', $feishuUserInfo['corp_id'])
->where('phone', $phone)
->where('phone', '!=', '')
->first();
$userByEmail = User::where('corp_id', $feishuUserInfo['corp_id'])
->where('email', $email)
->where('email', '!=', '')
->first();
$user = $userByPhone ?: $userByEmail;
if (!$user) {
// 获取编号
$userSn = $this->getAvailableUserSn();
// 创建用户
$user = User::create([
'name' => $feishuUserInfo['name'],
'avatar' => $feishuUserInfo['avatar_middle'],
'phone' => $this->sanitizePhone($feishuUserInfo['mobile'] ?? ''),
'email' => $feishuUserInfo['enterprise_email'],
'union_id' => $feishuUserInfo['union_id'],
'user_id' => $feishuUserInfo['user_id'],
'open_id' => $feishuUserInfo['open_id'],
'tenant_key' => $feishuUserInfo['tenant_key'],
'corp_id' => $feishuUserInfo['corp_id'],
'password' => password_hash($userSn->user_sn, PASSWORD_DEFAULT)
]);
// 更新使用
$this->updateUserId($user->id, $userSn->user_sn);
// 更新编号
if (!$user->update(['sn'=>$userSn->user_sn])) {
throw new BusinessException('编号绑定失败');
}
// 是否登陆
$user->isLogin = false;
$options = [
'corp_id' => $user->corp_id,
'user_id' => $user->id
];
\Webman\RedisQueue\Redis::send('perm-agt', $options);
} else {
$updated = [
'union_id' => $feishuUserInfo['union_id'],
'user_id' => $feishuUserInfo['user_id'],
'open_id' => $feishuUserInfo['open_id'],
'tenant_key' => $feishuUserInfo['tenant_key']
];
if ($phone && $phone == $user->phone) {
$updated['phone'] = $phone;
}
if ($phone && $phone == $user->phone) {
$updated['email'] = $email;
}
// 更新飞书信息
$user->update($updated);
// 是否登陆
$user->isLogin = true;
}
return $user;
} catch (\Throwable $e) {
throw $e;
}
}
/**
* 过滤和格式化手机号
*/
private function sanitizePhone($mobile)
{
return isset($mobile) ? str_replace('+86', '', $mobile) : '';
}
/**
* 生成并记录token,返回包含token的响应数据
*/
private function generateTokensAndReturn(User $user, Systems $system, array $data): array
{
$payload = $this->buildJwtPayload($user, $system);
$token = $this->generateAccessToken($payload);
$refreshToken = $this->generateRefreshToken($user->id, $data['system_code']);
$homeUrl = $this->getHome($system->id, $payload);
// 记录 token 到 Redis 和 MySQL
$this->recordUserToken($user->id, $token, $data['system_code']);
return [
'access_token' => $token,
'refresh_token' => $refreshToken,
'expires_in' => config('jwt.jwt_expiration'),
'system_code' => $data['system_code'],
'corp_abbr' => $data['corp_abbr'],
'login_type' => $data['login_type'],
'home_url' => $homeUrl,
// 'payload' => $payload,
];
}
/**
* 获取飞书用户信息
*/
private function getFeishuUserInfo(array $data)
{
$app = [
'cli_a8033d607cba500d' => 'OZW2UOeJ0g4HJfXKSn6skcymCOyYIdDR',
];
if(empty($app[$data['app_id']])){
throw new BusinessException('app_id非法');
}
$feishu = new Feishu($data['app_id'], $app[$data['app_id']]);
//回调地址
$redirect_uri = $data['r_url'];
$userAccessToken = $feishu->userAccessToken($data['feishu_code'], $redirect_uri);
$userInfo = $feishu->userInfo($userAccessToken['access_token']);
if ($userInfo['code'] != 0) {
throw new BusinessException('授权失败,请重试');
}
return $userInfo['data'] + $data ;
}
/**
* 更新用户编号
*/
private function updateUserId($userId, $userSn)
{
$updated = UserSn::where('user_sn', $userSn)
->update(['user_id' => $userId]);
if ($updated === 0) {
throw new BusinessException('用户编号不存在或更新失败');
}
return $updated;
}
/**
* 记录用户token到 Redis 和 MySQL
*/
protected function recordUserToken(int $userId, string $token, string $systemCode)
{
$request = request();
$ip = $request ? $request->getRealIp() : '';
$ua = $request ? $request->header('user-agent', '') : '';
$now = time();
$expireAt = $now + config('jwt.jwt_expiration');
// Redis Set 用户token集合
Redis::sAdd("user_tokens:{$userId}:{$systemCode}", $token);
Redis::expire("user_tokens:{$userId}:{$systemCode}", config('jwt.jwt_expiration'));
// Redis Hash token元信息
$meta = [
'system_code' => $systemCode,
'login_ip' => $ip,
'user_agent' => $ua,
'login_time' => $now,
'expired_at' => $expireAt,
];
Redis::hMSet("user_token_meta:{$token}", $meta);
Redis::expire("user_token_meta:{$token}", config('jwt.jwt_expiration'));
// 可选:MySQL 持久化
try {
UserTokenLog::create([
'user_id' => $userId,
'token' => $token,
'system_code'=> $systemCode,
'login_ip' => $ip,
'user_agent' => $ua,
'login_time' => $now,
'expired_at' => $expireAt,
'is_valid' => 1,
]);
} catch (\Throwable $e) {
Log::error('Token log write failed: '.$e->getMessage());
}
}
/**
* 校验token有效性
*/
public function verifyToken(string $token, string $systemCode): array
{
if (!$systemCode) throw new BusinessException('缺少system_code', 422);
$payload = (new Jwt())->verifyToken($token);
// 校验黑名单
if (Redis::has("token_blacklist:{$token}")) {
throw new BusinessException('token已失效', 403);
}
// 强制校验aud(系统隔离)
if ($systemCode && $payload['aud'] != $systemCode && $payload['aud'] != ($payload['system_code'] ?? '')) {
throw new BusinessException('token不属于当前系统', 403);
}
return (array)$payload;
}
/**
* 获取飞书应用信息
*/
public function feishuAppInfo(string $app_id, string $systemCode)
{
$fsAppInfo = CorpFeishuApp::where('app_id', $app_id)->first();
var_dump($fsAppInfo);
return [
'app_id' => $fsAppInfo->app_id,
'app_secret' => $fsAppInfo->app_secret,
'r_url' => $fsAppInfo->r_url,
'scope' => $fsAppInfo->scopes,
'state' => $fsAppInfo->state,
];
}
/**
* 验证用户信息
*/
private function validateUser(string $account, string $password)
{
$user = User::byAccount($account)->first();
if (!$user || !password_verify($password, $user->password)) {
throw new BusinessException('账号或密码错误', 401);
}
if ($user->status != 1) {
throw new BusinessException('账号已禁用', 403);
}
return $user;
}
/**
* 验证系统信息
*/
private function validateSystem(string $systemCode)
{
$system = Systems::where('code', $systemCode)->first();
if (!$system) {
throw new BusinessException('系统不存在', 403);
}
return $system;
}
/**
* 验证公司信息
*/
private function validateCorp(string $corpAbbr)
{
$corp = Corp::where('abbr', $corpAbbr)->first();
if (!$corp) {
throw new BusinessException('公司不存在', 403);
}
return $corp;
}
/**
* 验证飞书应用信息
*/
private function validateFeishuApp(int $corpId, int $systemId)
{
$feishuAppInfo = CorpFeishuApp::where('corp_id', $corpId)->where('system_id', $systemId)->first();
if (!$feishuAppInfo) {
throw new BusinessException('飞书应用不存在', 403);
}
return $feishuAppInfo;
}
/**
* 验证用户系统权限
*/
private function validateSystemPermission(User $user, Systems $system)
{
if ($system->is_role) {
$systemIds = $user->systems->pluck('id')->toArray();
if (!in_array($system->id, $systemIds)) {
throw new BusinessException('无该系统权限', 403);
}
}
}
/**
* 获取可用的用户编号
*
* @return \app\common\model\UserSn 用户编号模型实例
* @throws BusinessException 当未找到适用编号时抛出
*/
private function getAvailableUserSn(): \app\common\model\UserSn
{
$userSnModel = new UserSn();
$sn = $userSnModel->where('user_id', '=', 0)->inRandomOrder()->first();
if (!$sn) {
Log::error('用户注册时未找到适用编号');
throw new BusinessException('未找到适用编号');
}
return $sn;
}
/**
* 创建用户记录
*
* @param array $data 包含用户信息的数组
* @return \app\common\model\User 用户模型实例
*/
private function createUser(array $data): \app\common\model\User
{
try {
return User::create($data);
} catch (\Throwable $e) {
Log::error('用户注册时创建用户记录失败', [
'data' => $data,
'error' => $e->getMessage()
]);
throw new BusinessException('用户注册失败,请稍后重试', 500);
}
}
/**
* JWT payload 构建
* 可扩展 payload 字段
*/
private function buildJwtPayload(User $user, ?Systems $system = null): array
{
$now = time();
$exp = $now + config('jwt.jwt_expiration');
$system_ids = $user->systems ? $user->systems->pluck('id')->toArray() : [];
$role_ids = $user->roles ? $user->roles->pluck('id')->toArray() : [];
return [
'sub' => 'user_' . $user->id,
'aud' => $system->code,
'iat' => $now,
'nbf' => $now,
'exp' => $exp,
'typ' => 'access',
'uid' => $user->id,
'uname' => $user->name,
'role_ids' => $role_ids,
'system_ids' => $system_ids
];
}
/**
* JWT签发
*/
private function generateAccessToken(array $payload)
{
return (new Jwt())->generateToken($payload);
}
/**
* 刷新令牌生成
*/
private function generateRefreshToken(int $userId, string $systemCode)
{
$refreshToken = bin2hex(random_bytes(32));
// user_id+system_code只允许一个refresh_token生效
Redis::set("refresh_token:{$userId}:{$systemCode}", $refreshToken, config('jwt.jwt_refresh_token_expiration'));
// 建立refresh_token到user_id+system_code映射,便于校验
Redis::set("refresh_token_map:{$refreshToken}:{$systemCode}", $userId, config('jwt.jwt_refresh_token_expiration'));
return $refreshToken;
}
/**
* 刷新token
* @param string $refreshToken
* @param string|null $systemCode 可选,指定系统
* @return array
*/
public function refreshToken(string $refreshToken, ?string $systemCode = null): array
{
if (!$systemCode) throw new BusinessException('缺少system_code', 422);
// 校验refresh_token
$userId = Redis::get("refresh_token_map:{$refreshToken}:{$systemCode}");
if (!$userId) {
throw new BusinessException('refresh_token无效或已过期', 401);
}
$validToken = Redis::get("refresh_token:{$userId}:{$systemCode}");
if ($validToken !== $refreshToken) {
throw new BusinessException('refresh_token无效或已过期', 401);
}
$user = User::find($userId);
if (!$user || $user->status != 1) {
throw new BusinessException('用户无效', 403);
}
$system = $this->validateSystem($systemCode);
$this->validateSystemPermission($user, $system);
$payload = $this->buildJwtPayload($user, $system);
$token = $this->generateAccessToken($payload);
$refreshToken = $this->generateRefreshToken($user->id, $systemCode);
$this->recordUserToken($user->id, $token, $systemCode);
return [
'access_token' => $token,
'refresh_token' => $refreshToken,
'expires_in' => config('jwt.jwt_expiration'),
// 'payload' => $payload,
];
}
/**
* 登出/失效token
*/
public function logout(?string $token, ?string $systemCode = null)
{
if ($token) {
Redis::set("token_blacklist:{$token}", 1, config('jwt.jwt_expiration'));
$payload = null;
try { $payload = (new Jwt())->verifyToken($token); } catch (\Throwable $e) {}
$userId = $payload['uid'] ?? null;
$aud = $payload['aud'] ?? null;
$sc = $systemCode ?? $aud;
if ($userId && $sc) {
Redis::sRem("user_tokens:{$userId}:{$sc}", $token);
}
Redis::del("user_token_meta:{$token}");
UserTokenLog::where('token', $token)->update(['is_valid'=>0]);
}
}
/**
* 强制拉黑token
*/
public function blockToken(string $token, ?string $systemCode = null)
{
if (!$token) {
throw new BusinessException('token不能为空', 422);
}
Redis::set("token_blacklist:{$token}", 1, config('jwt.jwt_expiration'));
$payload = null;
try { $payload = (new Jwt())->verifyToken($token); } catch (\Throwable $e) {}
$userId = $payload['uid'] ?? null;
$aud = $payload['aud'] ?? null;
$sc = $systemCode ?? $aud;
if ($userId && $sc) {
Redis::sRem("user_tokens:{$userId}:{$sc}", $token);
}
Redis::del("user_token_meta:{$token}");
UserTokenLog::where('token', $token)->update(['is_valid'=>0]);
}
public function getHome($systemId, $data)
{
// 2025.10.30 临时处理 ====== start
if ($systemId == 1) {
if (in_array(1, $data['role_ids'])) {
return '/dashboard/console';
}
if (count($data['role_ids']) == 1 && in_array(5, $data['role_ids'])) {
return '/dashboard/console/backoffice';
}
if (count($data['role_ids']) == 1 && in_array(6, $data['role_ids'])) {
return '/dashboard/console/finance';
}
}
// 2025.10.30 临时处理 ====== end
$info = Resource::where('system_id', $systemId)
->where('is_home', 1)
->first();
if (!$info) {
return '/dashboard/console';
}
// 递归拼接 URL
$url = $this->buildParentUrl($info);
return $url ?: '/dashboard/console';
}
/**
* 递归构建父级 URL
* @param Resource $resource
* @return string
*/
protected function buildParentUrl(Resource $resource)
{
$url = $resource->url ?? '';
// 如果存在父级,则递归拼接
if ($resource->parent_id != 0) {
$parent = Resource::find($resource->parent_id);
if ($parent) {
$parentUrl = $this->buildParentUrl($parent);
$url = $parentUrl . ($url ? '/' . ltrim($url, '/') : '');
}
}
return $url;
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\Brand;
class BrandLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = Brand::class;
public function getList()
{
return Brand::where('status', 1)->orderBy('hot','desc')->orderBy('sort','desc')->get(['id', 'brand_code', 'brand_name', 'logo', 'description']);
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\BrandSeries;
class BrandSeriesLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = BrandSeries::class;
public function getList($where)
{
return BrandSeries::where('status', 1)->where($where)->orderBy('sort','desc')->get(['id', 'series_code', 'series_name', 'description']);
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\CorpFeishuApp;
class CorpFeishuAppLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = CorpFeishuApp::class;
public function getFeishuApp($corpId, $systemId)
{
return CorpFeishuApp::where('corp_id', $corpId)->where('system_id', $systemId)->first(['id', 'corp_id', 'name', 'app_id', 'r_url', 'state']);
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\Corp;
class CorpLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = Corp::class;
public function getList()
{
return Corp::where('status', 1)->orderBy('sort', 'asc')->get(['id', 'name', 'abbr', 'tenant_key']);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\CorpFeishuApp;
class CountryLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = CorpFeishuApp::class;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\FinPaymentApply;
class FinPaymentApplyLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = FinPaymentApply::class;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\FinReceiptHis;
class FinReceiptHisLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = FinReceiptHis::class;
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\FinReceipt;
class FinReceiptLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = FinReceipt::class;
public function credit($id, $data)
{
return FinReceipt::where('id', $id)->update($data);
}
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\FinanceReconDubaiFiles;
class FinanceReconDubaiFilesLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = FinanceReconDubaiFiles::class;
}
+262
View File
@@ -0,0 +1,262 @@
<?php
namespace app\common\logic;
/**
* Fingerprint
*
* 目标:
* - 默认“强制所有字段参与计算”,保证相同记录生成同一指纹
* - 通过统一规范化策略,避免无意义差异(空白、大小写、JSON键序)导致指纹抖动
* - 仅排除技术字段:id、fingerprint(可通过参数自行增删)
*
* 用法:
* $hash = Fingerprint::makeFromArray($payload); // 创建前
* $hash = Fingerprint::makeFromModel($skuModel); // 已有模型
* $hash = Fingerprint::makeFromArray($payload, ['exclude'=>['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;
}
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InquiryTransmitConfig;
class InquiryTransmitConfigLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InquiryTransmitConfig::class;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InquiryTransmit;
class InquiryTransmitLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InquiryTransmit::class;
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InvItem;
class InvItemLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvItem::class;
public function getList()
{
return InvItem::where('status',1)->orderBy('sort','desc')->get();
}
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InvRequisitionApprove;
class InvRequisitionApproveLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvRequisitionApprove::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InvRequisitionAttachment;
class InvRequisitionAttachmentLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvRequisitionAttachment::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InvRequisitionItem;
class InvRequisitionItemLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvRequisitionItem::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InvRequisitionItemReturnAttachment;
class InvRequisitionItemReturnAttachmentLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvRequisitionItemReturnAttachment::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InvRequisitionItemReturn;
class InvRequisitionItemReturnLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvRequisitionItemReturn::class;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\InvRequisition;
class InvRequisitionLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = InvRequisition::class;
}
@@ -0,0 +1,29 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\MessageNotifications;
class MessageNotificationsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = MessageNotifications::class;
public function logicDeleteBy($config)
{
$msg = $this->logicShow($config);
if ($msg) {
// 删除关联的用户状态记录
$msg->userStatuses()->delete();
// 删除消息本身
$msg->delete();
}
return true;
}
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\MessageUserStatus;
class MessageUserStatusLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = MessageUserStatus::class;
}
+101
View File
@@ -0,0 +1,101 @@
<?php
namespace app\common\logic;
final class ModelNaming
{
/** 生成稳定的 model_code(只用 *_code 与关键数字) */
public static function buildModelCode(array $s): string
{
$brand = self::tok($s['brand_code'] ?? '');
$series = self::tok($s['series_code'] ?? '');
$fuel = self::tok($s['fuel_type_code'] ?? 'UNK');
$parts = [$brand, $series];
$key = [];
switch ($fuel) {
case 'EV':
$key[] = 'EV';
if (!empty($s['range_km'])) {
$key[] = (string) (round((int)$s['range_km'] / 10) * 10); // 到十位
} elseif (!empty($s['battery_kwh'])) {
$key[] = self::numToken($s['battery_kwh']) . 'KWH';
}
break;
case 'GAS':
if (!empty($s['engine_disp_l'])) $key[] = self::dispToken($s['engine_disp_l']); // 1.5L -> 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';
}
}
+144
View File
@@ -0,0 +1,144 @@
<?php
namespace app\common\logic;
use app\common\model\User;
use app\common\model\Resource;
use app\common\model\Systems;
class PermLogic
{
/**
* 获取用户所有资源(合并角色+直接分配),并加入公共菜单,排序按sort字段
*/
public function getUserResources(int $userId, string $systemCode)
{
$system = Systems::where('code', $systemCode)->first();
// 获取用户及其关联角色资源和直接分配的资源
$user = User::with(['roles.resources', 'resources'])->find($userId);
if (!$user) {
return collect();
}
$all = collect();
// 遍历用户的所有角色,合并每个角色所拥有的资源
foreach ($user->roles as $role) {
$all = $all->merge(
// 过滤当前角色的资源列表
$role->resources->filter(function ($resource) use($system) {
// 资源过滤条件:
// 1. !$resource->no_auth:资源需要权限认证(排除公共资源)
// 2. 系统匹配条件:
// - $system->id == $resource->system_id:资源属于当前系统
// - $resource->system_id == 0:资源为全局公共资源(所有系统可用)
return !$resource->no_auth && ($system->id == $resource->system_id || $resource->system_id == 0);
})
);
}
// 合并用户直接分配的资源,排除不需要权限认证的资源
$all = $all->merge(
$user->resources->filter(function ($resource) {
// 只保留需要权限认证的资源(或公共资源)
return !$resource->no_auth;
})
);
// 加入公共菜单,公共菜单不管是否授权,所有人都能访问
$publicResources = Resource::where('no_auth', 1)
->orderBy('sort', 'asc') // 按 sort 字段升序排序
->get();
// 合并所有公共资源
$all = $all->merge($publicResources);
// 返回唯一的资源列表,并按 id 排序
// 使用 sortBy('sort') 来确保最终结果根据 'sort' 字段排序
return $all->unique('id')->values()->sortBy('sort');
}
/**
* 构建目录/菜单树
*
* @param \Illuminate\Support\Collection $resources 全部资源集合
* @param int $parentId 当前父级资源 ID
* @param string $parentPath 父级完整路径(用于递归)
* @return array
*/
public function buildTree($resources, int $parentId = 0, string $parentPath = ''): array
{
$tree = [];
foreach ($resources as $node) {
if ($node->parent_id !== $parentId) continue;
// 拼接完整路径
$currentPath = $parentPath;
if ($currentPath && substr($currentPath, -1) === '/') {
$currentPath = rtrim($currentPath, '/');
}
if (!empty($node->url)) {
if (!$currentPath) {
$currentPath = $node->url;
} else {
$url = ltrim($node->url, '/');
$currentPath = $currentPath . '/' . $url;
}
}
// 子节点递归
$children = [];
if ($node->type === 'directory') {
$children = $this->buildTree($resources, $node->id, $currentPath);
}
// 权限
$authList = $resources
->filter(fn($r) => $r->type === 'permission' && $r->parent_id === $node->id)
->map(fn($r) => [
'id' => $r->id,
'title' => $r->name,
'auth_mark' => $r->code,
])->values()->all();
// 判断是否有子级菜单(非权限)
$hasChildrenMenu = collect($resources)->where('parent_id', $node->id)
->whereIn('type', ['directory', 'menu'])->isNotEmpty();
$componentValue = $hasChildrenMenu ? '/index/index' : $currentPath;
$tree[] = [
'id' => $node->id,
'name' => $node->name,
'path' => $node->url,
'component' => $componentValue,
'meta' => [
'title' => $node->name,
'icon' => $node->icon,
'keepAlive' => $node->keep_alive == 1 ? true : false,
'authList' => $authList,
'openType' => $node->open_type,
'isHide' => $node->is_hide == 0 ? false : true,
'isHideTab' => $node->is_hide_tab == 0 ? false : true
],
'children' => $children,
];
}
return $tree;
}
/**
* 获取用户所有权限code
*/
public function getPermissionCodes(int $userId, string $systemCode): array
{
$resources = $this->getUserResources($userId, $systemCode);
return $resources
->filter(fn($res) => $res->type === 'permission')
->pluck('code')
->unique()
->values()
->all();
}
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\PurchaseOrderItems;
class PurchaseOrderItemsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = PurchaseOrderItems::class;
}
+52
View File
@@ -0,0 +1,52 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\PurchaseOrders;
use app\common\model\StockOrderItems;
use app\common\utils\CrudUtil;
use app\common\model\StockOrders;
class PurchaseOrdersLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = PurchaseOrders::class;
/**
* 获取备货单PI号
*/
public function getPiList()
{
return (new StockOrders())->where('pi_no', '!=', '')
->select('pi_no', 'salesperson_snapshot')
->distinct()
->get();
}
/**
* 根据PI号获取备货单
*/
public function getOrderNoListByPiNo($piNo)
{
return (new StockOrders())->where('pi_no', $piNo)
->where('approval_status', 2)
->select('order_no', 'biz_date', 'salesperson_snapshot', 'id as stock_orders_id', 'salesperson_id')
->get();
}
/**
* 根据备货单号获取备货单明细
*/
public function getOrderItemsListByOrderNo($stockOrdersId)
{
return (new StockOrderItems())->where('order_id', $stockOrdersId)
->select('model_snapshot', 'color_interior_snapshot', 'color_exterior_snapshot', 'unique_id', 'id as stock_order_items_id')
->get();
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\Resource;
use support\Request;
class ResourceLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = Resource::class;
public function logicListAllResources(Request $request, array $config)
{
$data = $this->logicListAll($config);
if ($request->get('role_id')) {
$selected = (new RoleLogic())->getRoleResources($request->get('role_id'));
} else if ($request->get('user_id')) {
$selected = (new RoleLogic())->getUserResources($request->get('user_id'));
} else {
$selected = [];
}
foreach ($data as &$item) {
$item['selected'] = in_array($item['id'], $selected) ? true : false;
}
return $data;
}
}
+85
View File
@@ -0,0 +1,85 @@
<?php
namespace app\common\logic;
use support\Db;
class RoleLogic
{
/**
* 更新角色资源权限
*
* @param array $data 包含 role_id 和 resources 的数据
* @return bool 操作是否成功
*/
public function updateRoleResources(array $data): bool
{
$roleId = $data['role_id'] ?? 0;
$resources = $data['resources'] ?? [];
if (empty($roleId)) {
return false;
}
Db::beginTransaction();
try {
// 删除原有角色资源关联
Db::table('role_resources')->where('role_id', $roleId)->delete();
// 批量插入新角色资源关联
if (!empty($resources)) {
$insertData = [];
foreach ($resources as $resourceId) {
$insertData[] = [
'role_id' => $roleId,
'resource_id' => $resourceId
];
}
Db::table('role_resources')->insert($insertData);
}
Db::commit();
return true;
} catch (\Throwable $exception) {
Db::rollBack();
return false;
}
}
/**
* 获取角色资源
*
* @param int $roleId 角色ID
* @return array 资源ID列表
*/
public function getRoleResources(int $roleId): array
{
if (empty($roleId)) {
return [];
}
return Db::table('role_resources')
->where('role_id', $roleId)
->pluck('resource_id')
->toArray();
}
/**
* 获取用户资源
*
* @param int $userId 用户ID
* @return array 资源ID列表
*/
public function getUserResources(int $userId): array
{
if (empty($userId)) {
return [];
}
return Db::table('user_resources')
->where('user_id', $userId)
->pluck('resource_id')
->toArray();
}
}
+233
View File
@@ -0,0 +1,233 @@
<?php
namespace app\common\logic;
use app\common\model\VehVehicleSku;
/**
* SKU 生成器
* - 输入: 车辆规格数组(以 *_code 为主)
* - 输出: 稳定、人读友好的 sku_code (<= 40 默认)
*/
final class SkuCodeBuilder
{
/** 压缩映射(可按需扩充) */
private const ABBR = [
// level
'FLAGSHIP' => '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;
}
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\StockOrderAccounts;
class StockOrderAccountsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = StockOrderAccounts::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\StockOrderItemOptions;
class StockOrderItemOptionsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = StockOrderItemOptions::class;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\StockOrderItems;
class StockOrderItemsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = StockOrderItems::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\StockOrdersFiles;
class StockOrdersFilesLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = StockOrdersFiles::class;
}
+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;
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\SysAccount;
class SysAccountLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysAccount::class;
public function getList()
{
return SysAccount::where('status', 1)->orderBy('sort','desc')->get(['id', 'account_name', 'currency_id', 'account_number', 'bank_name', 'bank_branch', 'description', 'short_desc']);
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\model\SysConfig;
use app\common\model\SysCurrency;
use app\common\traits\crud\CrudLogicTrait;
class SysConfigLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysCurrency::class;
public function findByKey(string $key)
{
return SysConfig::where('status', 1)->where('config_key', $key)->get(['id', 'config_key', 'config_value']);
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace app\common\logic;
use app\common\model\SysCurrency;
use app\common\traits\crud\CrudLogicTrait;
class SysCurrencyLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysCurrency::class;
public function getList()
{
return SysCurrency::where('status', 1)->get(['id', 'country_id', 'currency_code', 'currency_name', 'currency_symbol', 'exchange_rate', 'float_percent_up', 'float_percent_down']);
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\SysDictItem;
class SysDictItemLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysDictItem::class;
public function getList($where)
{
return SysDictItem::where('status', 1)->where($where)->orderBy('sort','desc')->get(['id', 'item_label', 'item_value', 'remark', 'dict_id']);
}
}
+27
View File
@@ -0,0 +1,27 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\SysDict;
class SysDictLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysDict::class;
public function getDictByCode($code)
{
return SysDict::where('status', 1)->where('code', $code)->orderBy('sort','desc')->first(['id']);
}
public function getList()
{
return SysDict::where('status', 1)->get(['id', 'dict_name', 'dict_code', 'description']);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\SysOpLog;
class SysOpLogLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysOpLog::class;
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\SysPort;
class SysPortLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysPort::class;
public function getList($where)
{
return SysPort::where('status', 1)->where($where)->orderBy('sort','desc')->get(['id', 'port_code', 'port_name', 'port_name_en', 'country_id', 'description']);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\SysUpdateLog;
class SysUpdateLogLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = SysUpdateLog::class;
}
+21
View File
@@ -0,0 +1,21 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\Systems;
class SystemsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = Systems::class;
public function getList()
{
return Systems::where('status', 1)->orderBy('sort', 'asc')->get(['id', 'name', 'code', 'type', 'type']);
}
}
+169
View File
@@ -0,0 +1,169 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\UploadedFiles;
class UploadedFilesLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = UploadedFiles::class;
/**
* 根据分区获取文件列表
*
* @param string $partition
* @param int $limit
* @param int $page
* @return mixed
*/
public function getFilesByPartition(string $partition, int $limit = 15, int $page = 1)
{
$config = [
'model' => $this->modelClass,
'where' => ['partition' => $partition],
'order' => ['created_at' => 'desc', 'id' => 'desc']
];
return $this->logicList($config, $limit, $page);
}
/**
* 根据分类获取文件列表
*
* @param string $category
* @param int $limit
* @param int $page
* @return mixed
*/
public function getFilesByCategory(string $category, int $limit = 15, int $page = 1)
{
$config = [
'model' => $this->modelClass,
'where' => ['category' => $category],
'order' => ['created_at' => 'desc', 'id' => 'desc']
];
return $this->logicList($config, $limit, $page);
}
/**
* 根据文件类型获取文件列表
*
* @param string $fileType
* @param int $limit
* @param int $page
* @return mixed
*/
public function getFilesByType(string $fileType, int $limit = 15, int $page = 1)
{
$config = [
'model' => $this->modelClass,
'where' => ['file_type' => $fileType],
'order' => ['created_at' => 'desc', 'id' => 'desc']
];
return $this->logicList($config, $limit, $page);
}
/**
* 搜索文件
*
* @param string $keyword
* @param int $limit
* @param int $page
* @return mixed
*/
public function searchFiles(string $keyword, int $limit = 15, int $page = 1)
{
$config = [
'model' => $this->modelClass,
'where' => [
'or' => [
['file_name', 'like', '%' . $keyword . '%'],
['original_name', 'like', '%' . $keyword . '%'],
['category', 'like', '%' . $keyword . '%']
]
],
'order' => ['created_at' => 'desc', 'id' => 'desc']
];
return $this->logicList($config, $limit, $page);
}
/**
* 获取文件统计信息
*
* @return array
*/
public function getFileStatistics(): array
{
$model = new $this->modelClass();
$totalFiles = $model->count();
$totalSize = $model->sum('file_size');
$partitionStats = $model->selectRaw('partition, COUNT(*) as count, SUM(file_size) as size')
->groupBy('partition')
->get()
->toArray();
$categoryStats = $model->selectRaw('category, COUNT(*) as count, SUM(file_size) as size')
->groupBy('category')
->get()
->toArray();
$typeStats = $model->selectRaw('file_type, COUNT(*) as count, SUM(file_size) as size')
->groupBy('file_type')
->get()
->toArray();
return [
'total_files' => $totalFiles,
'total_size' => $totalSize,
'partition_stats' => $partitionStats,
'category_stats' => $categoryStats,
'type_stats' => $typeStats
];
}
/**
* 清理过期文件
*
* @param int $days 保留天数
* @return int 清理的文件数量
*/
public function cleanExpiredFiles(int $days = 30): int
{
$expiredTime = time() - ($days * 24 * 60 * 60);
$config = [
'model' => $this->modelClass,
'where' => [
['created_at', '<', $expiredTime]
]
];
$files = $this->logicListAll($config);
$count = 0;
foreach ($files as $file) {
// 删除物理文件
$fullPath = public_path() . $file->file_path;
if (file_exists($fullPath)) {
unlink($fullPath);
}
// 删除数据库记录
$this->logicDeleteBy(['where' => ['id' => $file->id]]);
$count++;
}
return $count;
}
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\UsedcarCrawlResultsImages;
class UsedcarCrawlResultsImagesLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = UsedcarCrawlResultsImages::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\UsedcarCrawlResults;
class UsedcarCrawlResultsLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = UsedcarCrawlResults::class;
}
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\UserGroup;
use app\common\model\UserGroupMembers;
class UserGroupLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = UserGroup::class;
public function createGroup(array $data): UserGroup
{
$created = UserGroup::create($data);
if (isset($data['user_ids']) && is_array($data['user_ids']) && count($data['user_ids']) > 0) {
foreach ($data['user_ids'] as $member) {
$this->addUserGroupMembers($member, $created->id);
}
}
if ((int)$data['leader_id'] > 0) {
$leader = UserGroupMembers::where('user_id', $data['leader_id'])->where('group_id', $created->id)->first();
if ($leader) {
$leader->is_leader = 1;
$leader->save();
} else {
$this->addUserGroupMembers($data['leader_id'], $created->id, 1);
}
}
return $created;
}
public function updateGroup(UserGroup $userGroup, array $data)
{
$userGroup->title = $data['title'];
$userGroup->sort = $data['sort'] ?? 0;
$userGroup->status = $data['status'];
$userGroup->scenario_code = $data['scenario_code'] ?? '';
$userGroup->save();
// 删除所有成员
UserGroupMembers::where('group_id', $userGroup->id)->delete();
if (isset($data['user_ids']) && is_array($data['user_ids']) && count($data['user_ids']) > 0) {
foreach ($data['user_ids'] as $member) {
$this->addUserGroupMembers($member, $userGroup->id);
}
}
if ((int)$data['leader_id'] > 0) {
$leader = UserGroupMembers::where('user_id', $data['leader_id'])->where('group_id', $userGroup->id)->first();
if ($leader) {
$leader->is_leader = 1;
$leader->save();
} else {
$this->addUserGroupMembers($data['leader_id'], $userGroup->id, 1);
}
}
return $userGroup;
}
public function addUserGroupMembers(int $userId, int $groupId, int $isLeader = 0)
{
$udata = [
'user_id' => $userId,
'group_id' => $groupId,
'is_leader' => $isLeader
];
return UserGroupMembers::create($udata);
}
}
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\UserGroupMembers;
class UserGroupMembersLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = UserGroupMembers::class;
public function deleteUserGroupMembers(int $groupId)
{
return UserGroupMembers::where('group_id', $groupId)->delete();
}
}
+110
View File
@@ -0,0 +1,110 @@
<?php
namespace app\common\logic;
use app\common\model\User;
use app\common\model\UserGroupMembers;
use app\common\traits\crud\CrudLogicTrait;
use support\exception\BusinessException;
use support\Request;
use app\common\model\UserRoles;
class UserLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = User::class;
/**
* 用户信息
*/
public function userInfo(int $uid)
{
$user = User::with('reportToInfo')->find($uid);
if (!$user) {
throw new BusinessException('账户不存在', 404);
}
if ($user->status != 1) {
throw new BusinessException('账号已禁用', 403);
}
return $user;
}
/**
* 用户信息
*/
public function edit(int $uid, array $data)
{
//
$user = User::find($uid);
if (!$user) {
throw new BusinessException('账户不存在', 404);
}
$user->fill($data);
$user->save();
// 绑定内勤 10.13 add
if (isset($data['office_clerk_id']) && $data['office_clerk_id'] > 0) {
$ug = UserGroupMembers::where('user_id', $uid)->where('status', 1)->first();
if ($ug) {
$ug->delete();
}
$group = UserGroupMembers::where('user_id', $data['office_clerk_id'])->where('is_leader', 1)->where('status', 1)->first();
if (!$group) {
throw new BusinessException('该内勤还未创建分组', 404);
}
UserGroupMembers::create([
'user_id' => $uid,
'group_id' => $group->group_id,
'is_leader' => 0,
'status' => 1
]);
}
return $user;
}
/**
* 修改密码
*/
public function savePassword(int $uid, array $data)
{
$password = password_hash($data['password_new'], PASSWORD_DEFAULT);
$res = User::where('id',$uid)->update(['password' => $password]);
return $res;
}
/**
* 获取用户列表
*/
public function getList(Request $request)
{
$p = $request->all();
$user = User::where('status', 1);
if (isset($p['role_id']) && $p['role_id'] > 0) {
$userIds = UserRoles::where('role_id', $p['role_id'])->pluck('user_id');
$user->whereIn('id', $userIds);
}
$list = $user->orderBy('id', 'desc')->get();
$arr = [];
foreach ($list->toArray() as $item) {
$arr[] = [
'name' => $item['name'],
'id' => $item['id'],
];
}
return $arr;
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehColor;
class VehColorLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehColor::class;
public function getList($where)
{
return VehColor::where('status', 1)->where($where)->orderBy('sort','desc')->get(['id', 'color_code', 'color_text']);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehDictI18n;
class VehDictI18nLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehDictI18n::class;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehDictMapping;
class VehDictMappingLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehDictMapping::class;
}
+22
View File
@@ -0,0 +1,22 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehModification;
class VehModificationLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehModification::class;
public function getList()
{
return VehModification::where('status', 1)->orderBy('sort','desc')->get(['id', 'code', 'name', 'type', 'price']);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehMoneyValue;
class VehMoneyValueLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehMoneyValue::class;
}
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehVehicleListing;
class VehVehicleListingLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehVehicleListing::class;
}
+60
View File
@@ -0,0 +1,60 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehVehicleSku;
class VehVehicleSkuLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehVehicleSku::class;
/**
* 指纹 = “稳定可复现的事实串”做 sha256
* - 仅纳入稳定维度:品牌/车系/年款/能源/驱动/变速/车身 + 关键数值
* - 不纳入营销名(trim/edition)、颜色文本等
* - corp 维度:若你未来希望租户内去重,可传 $scopeCorp=true
*/
public static function fingerprintMake(array $sku, bool $scopeCorp = false): string
{
$norm = function ($v) {
if ($v === null || $v === '') return '';
if (is_float($v)) return rtrim(rtrim(number_format($v, 3, '.', ''), '0'), '.'); // 规范小数
return (string)$v;
};
$parts = [
$scopeCorp ? ($sku['corp_id'] ?? 0) : '',
strtoupper($sku['brand_code'] ?? ''),
strtoupper($sku['series_code'] ?? ''),
(int)($sku['model_year'] ?? 0),
strtoupper($sku['fuel_type_code'] ?? ''),
strtoupper($sku['drive_type_code']?? ''),
strtoupper($sku['transmission_code'] ?? ''),
strtoupper($sku['body_type_code'] ?? ''),
$norm($sku['engine_disp_l'] ?? null),
(int)($sku['engine_turbo'] ?? 0),
$norm($sku['battery_kwh'] ?? null),
(int)($sku['range_km'] ?? 0),
strtoupper($sku['range_std_code'] ?? ''),
strtoupper($sku['emission_std_code'] ?? ''),
];
$plain = implode('|', $parts);
return hash('sha256', $plain);
}
public function getList($data)
{
return VehVehicleSku::where($data)->orderBy('id','desc')->get(['id', 'sku_code', 'brand_code', 'brand_code', 'series_code', 'series_name', 'model_code', 'model_name', 'model_year', 'msrp']);
}
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace app\common\logic;
use app\common\traits\crud\CrudLogicTrait;
use app\common\model\VehVehicleUnit;
class VehVehicleUnitLogic
{
use CrudLogicTrait;
/**
* 指定当前要操作的模型
*/
protected string $modelClass = VehVehicleUnit::class;
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace app\common\model;
use support\Model;
class ApprovalCcs extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'approval_ccs';
/**
* 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', 'instance_id', 'user_id', 'notified_at', 'read_at', 'created_at', 'updated_at'];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
}
+53
View File
@@ -0,0 +1,53 @@
<?php
namespace app\common\model;
use support\Model;
class ApprovalFlows extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'approval_flows';
/**
* 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', 'name', 'type', 'steps', 'is_active', 'timeout_hours', 'timeout_action', 'created_at', 'updated_at'];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
protected $casts = [
'steps' => 'array',
];
}
+122
View File
@@ -0,0 +1,122 @@
<?php
namespace app\common\model;
use app\common\model\StockOrders;
use app\common\model\User;
use support\Model;
class ApprovalInstances extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'approval_instances';
/**
* 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', 'flow_type', 'biz_id', 'biz_type', 'form_data', 'initiator_id', 'status', 'current_step', 'finished_at', 'deadline_at', 'created_at', 'updated_at'];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
protected $fillable = [
'flow_type',
'biz_id',
'biz_type',
'form_data',
'initiator_id',
'status',
'current_step',
'finished_at',
'deadline_at',
'round'
];
protected $casts = [
'form_data' => 'array', // 自动转换 JSON 字段为数组
'finished_at' => 'datetime',
'deadline_at' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
// ====== ====== ====== 映射业务表 ====== ====== ======
protected const BIZ_CLASS = [
'stock_orders' => \app\common\model\StockOrders::class,
'stock_orders_nullify' => \app\common\model\StockOrders::class,
'purchase_orders' => \app\common\model\PurchaseOrders::class,
];
public function getBizTypeAttribute($value)
{
return self::BIZ_CLASS[$value] ?? $value;
}
public function bizInfo()
{
return $this->morphTo('bizInfo', 'biz_type', 'biz_id')->withTrashed();
}
// ====== ====== ====== 映射表业务 ====== ====== ======
public function records()
{
return $this->hasMany(ApprovalRecords::class, 'instance_id', 'id');
}
public function flows()
{
return $this->belongsTo(ApprovalFlows::class, 'flow_type', 'type');
}
public function initiator()
{
return $this->belongsTo(User::class, 'initiator_id', 'id');
}
// public function bizInfo2()
// {
// return $this->belongsTo(StockOrders::class, 'biz_id', 'id');
// }
/**
* 获取当前步骤的所有审批记录(pending 状态)
*/
public function currentStepRecords()
{
return $this->approvalRecords()->where('step_index', $this->current_step)->where('status', 'pending');
}
}
+79
View File
@@ -0,0 +1,79 @@
<?php
namespace app\common\model;
use app\common\model\User;
use support\Model;
class ApprovalRecords extends Model
{
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'mysql';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'approval_records';
/**
* 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', 'instance_id', 'approver_id', 'step_index', 'action', 'comment', 'approved_at', 'created_at', 'updated_at'];
/**
* 不允许自动填充模型字段
*/
protected $guarded = [];
protected $fillable = [
'instance_id',
'approver_id',
'step_index',
'action',
'status',
'comment',
'approved_at',
'round'
];
protected $casts = [
'approved_at' => 'datetime',
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
public function instance()
{
return $this->belongsTo(ApprovalInstances::class, 'instance_id', 'id');
}
public function approver()
{
return $this->belongsTo(User::class, 'approver_id', 'id');
}
}

Some files were not shown because too many files have changed in this diff Show More