feat: 新增备货单公共 API 接口(PI 号/VIN 号列表)
- 新增 ApiKeyAuth 中间件(hash_equals 防时序攻击) - 新增 PublicApiController(piList/vinList 两个只读接口) - 仅返回已审批通过(approval_status=2)的数据,支持分页和模糊搜索 - LIKE 通配符已转义,异常信息不暴露内部细节 - 附对接文档 docs/public-stock-api.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\controller;
|
||||
|
||||
use app\common\model\StockOrders;
|
||||
use app\common\model\StockOrderItems;
|
||||
use support\Request;
|
||||
|
||||
class PublicApiController extends BaseController
|
||||
{
|
||||
protected $noNeedLogin = ['piList', 'vinList'];
|
||||
protected $noNeedHeaderData = ['piList', 'vinList'];
|
||||
|
||||
/**
|
||||
* PI 号列表(含关联的 VIN 和车型名称)
|
||||
* GET /common/public/pi/list
|
||||
*/
|
||||
public function piList(Request $request)
|
||||
{
|
||||
try {
|
||||
$page = (int)($request->input('page', 1));
|
||||
$pageSize = (int)($request->input('page_size', 20));
|
||||
$piNo = $request->input('pi_no', '');
|
||||
|
||||
if ($page < 1) $page = 1;
|
||||
if ($pageSize < 1 || $pageSize > 200) $pageSize = 20;
|
||||
|
||||
$query = StockOrders::where('approval_status', 2)
|
||||
->whereNotNull('pi_no')
|
||||
->where('pi_no', '<>', '');
|
||||
|
||||
if ($piNo !== '') {
|
||||
$query->where('pi_no', 'like', '%' . addcslashes($piNo, '%_') . '%');
|
||||
}
|
||||
|
||||
$query->with(['items' => function ($q) {
|
||||
$q->select('id', 'order_id', 'vin', 'model_snapshot');
|
||||
}]);
|
||||
|
||||
$paginator = $query->orderBy('id', 'desc')
|
||||
->paginate($pageSize, ['id', 'pi_no'], 'page', $page);
|
||||
|
||||
$data = $paginator->getCollection()->map(function ($order) {
|
||||
return [
|
||||
'pi_no' => $order->pi_no,
|
||||
'vins' => $order->items->pluck('vin')->filter()->values()->toArray(),
|
||||
'model_names' => $order->items->pluck('model_snapshot')->filter()->values()->toArray(),
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
return $this->success([
|
||||
'total' => $paginator->total(),
|
||||
'per_page' => $paginator->perPage(),
|
||||
'current_page' => $paginator->currentPage(),
|
||||
'data' => $data,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error('查询失败,请稍后重试');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* VIN 号列表(含车型名称)
|
||||
* GET /common/public/vin/list
|
||||
*/
|
||||
public function vinList(Request $request)
|
||||
{
|
||||
try {
|
||||
$page = (int)($request->input('page', 1));
|
||||
$pageSize = (int)($request->input('page_size', 20));
|
||||
$vin = $request->input('vin', '');
|
||||
|
||||
if ($page < 1) $page = 1;
|
||||
if ($pageSize < 1 || $pageSize > 200) $pageSize = 20;
|
||||
|
||||
$query = StockOrderItems::whereHas('order', function ($q) {
|
||||
$q->where('approval_status', 2);
|
||||
})->whereNotNull('vin')
|
||||
->where('vin', '<>', '');
|
||||
|
||||
if ($vin !== '') {
|
||||
$query->where('vin', 'like', '%' . addcslashes($vin, '%_') . '%');
|
||||
}
|
||||
|
||||
$paginator = $query->orderBy('id', 'desc')
|
||||
->paginate($pageSize, ['id', 'vin', 'model_snapshot'], 'page', $page);
|
||||
|
||||
$data = $paginator->getCollection()->map(function ($item) {
|
||||
return [
|
||||
'vin' => $item->vin,
|
||||
'model_name' => $item->model_snapshot,
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
return $this->success([
|
||||
'total' => $paginator->total(),
|
||||
'per_page' => $paginator->perPage(),
|
||||
'current_page' => $paginator->currentPage(),
|
||||
'data' => $data,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error('查询失败,请稍后重试');
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user