feat(订单): 订单列表与统计支持按字段搜索和独立订单号筛选

This commit is contained in:
From-wh 2026-10-23 15:01:15 +08:00 committed by 吴昊天
parent 53bdad2339
commit 0ae6971cbd
3 changed files with 81 additions and 32 deletions

View File

@ -2428,6 +2428,47 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
return $chartdata;
}
/**
* 构建关键词搜索闭包(后台订单列表/统计共用)
* 按 search_field 限定搜索字段:order_no=订单号前缀、contact_name=收货人、
* contact_phone=联系电话、uid=用户ID精确匹配,all/其它=订单号+联系人+电话
* 收货人/电话存于 extra_info JSON,走 JSON 路径匹配
* @param string $keyword 关键词(调用方需先 trim)
* @param string $searchField 搜索字段标识
* @return \Closure 可放入 where 数组或 ->where() 的闭包
*/
public function buildKeywordFilterClosure(string $keyword, string $searchField = 'all'): \Closure
{
$escaped = addcslashes($keyword, '%_');
return function ($query) use ($escaped, $keyword, $searchField) {
$query->where(function ($q) use ($escaped, $keyword, $searchField) {
switch ($searchField) {
case 'order_no':
// 仅按订单号前缀搜索
$q->where('order_no', 'LIKE', "{$escaped}%");
break;
case 'contact_name':
// 仅按收货人姓名搜索
$q->whereRaw("extra_info->>'$.contact.name' LIKE ?", ["%{$escaped}%"]);
break;
case 'contact_phone':
// 仅按联系电话搜索
$q->whereRaw("extra_info->>'$.contact.phone' LIKE ?", ["%{$escaped}%"]);
break;
case 'uid':
// 用户ID精确匹配
$q->where('uid', '=', (int) $keyword);
break;
default:
// 全部字段:订单号前缀 + 收货人 + 电话
$q->whereOr('order_no', 'LIKE', "{$escaped}%")
->whereOrRaw("extra_info->>'$.contact.name' LIKE ?", ["%{$escaped}%"])
->whereOrRaw("extra_info->>'$.contact.phone' LIKE ?", ["%{$escaped}%"]);
}
});
};
}
/**
* 后台订单列表(带完整筛选和售后状态合并)
* 支持多维度筛选和搜索,返回分页数据
@ -2474,14 +2515,15 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
if (!empty($where['uid'])) {
$searchWhere[] = ['uid', '=', $where['uid']];
}
// 关键词搜索(订单号、收货人姓名、联系电话,联系信息走 extra_info JSON 路径)
if (!empty($where['keyword'])) {
$searchWhere[] = function ($query) use ($where) {
$keyword = addcslashes($where['keyword'], '%_');
$query->whereOr('order_no', 'LIKE', "{$keyword}%")
->whereOrRaw("extra_info->>'$.contact.name' LIKE ?", ["%{$keyword}%"])
->whereOrRaw("extra_info->>'$.contact.phone' LIKE ?", ["%{$keyword}%"]);
};
// 订单号独立搜索框:前缀匹配,与其它条件 AND 组合
$orderNo = trim((string) ($where['order_no'] ?? ''));
if ($orderNo !== '') {
$searchWhere[] = ['order_no', 'LIKE', addcslashes($orderNo, '%_') . '%'];
}
// 关键词搜索(search_field 指定字段:订单号、收货人姓名、联系电话、UID;联系信息走 extra_info JSON 路径)
$keyword = trim((string) ($where['keyword'] ?? ''));
if ($keyword !== '') {
$searchWhere[] = $this->buildKeywordFilterClosure($keyword, (string) ($where['search_field'] ?? 'all'));
}
// 日期范围筛选
if (!empty($where['date_range'])) {
@ -2727,16 +2769,15 @@ class OrderCenterServices extends BaseService implements OrderCenterSyncInterfac
if (!empty($where['pay_type'])) {
$baseWhere[] = ['pay_type', '=', $where['pay_type']];
}
// 按关键词搜索(订单号、联系人姓名、联系电话)
if (!empty($where['keyword'])) {
$keyword = addcslashes($where['keyword'], '%_');
$baseWhere[] = function ($query) use ($keyword) {
$query->where(function ($q) use ($keyword) {
$q->whereOr('order_no', 'LIKE', "{$keyword}%")
->whereOrRaw("extra_info->>'$.contact.name' LIKE ?", ["%{$keyword}%"])
->whereOrRaw("extra_info->>'$.contact.phone' LIKE ?", ["%{$keyword}%"]);
});
};
// 按订单号搜索(独立订单号搜索框,前缀匹配,与列表口径一致)
$statOrderNo = trim((string) ($where['order_no'] ?? ''));
if ($statOrderNo !== '') {
$baseWhere[] = ['order_no', 'LIKE', addcslashes($statOrderNo, '%_') . '%'];
}
// 按关键词搜索(search_field 指定字段:订单号、联系人姓名、联系电话、UID)
$statKeyword = trim((string) ($where['keyword'] ?? ''));
if ($statKeyword !== '') {
$baseWhere[] = $this->buildKeywordFilterClosure($statKeyword, (string) ($where['search_field'] ?? 'all'));
}
// 按状态统计订单数和金额

View File

@ -44,6 +44,8 @@ class OrderController extends AuthController
// 提取前端搜索参数,与 list() 一致
$params = $this->request->getMore([
['keyword', ''],
['search_field', ''],
['order_no', ''],
['date_range', ''],
['pay_type', ''],
['type', ''],
@ -59,6 +61,8 @@ class OrderController extends AuthController
'order_category' => 'goods',
'product_type' => 'normal',
'keyword' => $params['keyword'] ?? '',
'search_field' => $params['search_field'] ?? '',
'order_no' => $params['order_no'] ?? '',
'date_range' => $params['date_range'] ?? '',
'pay_type' => $params['pay_type'] ?? '',
'activity_type' => $activityType,
@ -70,8 +74,8 @@ class OrderController extends AuthController
['product_type', '=', 'normal'],
];
// 构建公共筛选条件(关键词、日期范围、支付方式)
$commonFilter = $this->buildSearchFilter($params);
// 构建公共筛选条件(订单号、关键词、日期范围、支付方式)
$commonFilter = $this->buildSearchFilter($params, $centerServices);
$businessStats = [];
@ -143,23 +147,25 @@ class OrderController extends AuthController
/**
* 根据前端搜索参数构建公共筛选条件(闭包数组)
* 与 getAdminList 的筛选逻辑保持一致
* @param array $params [keyword, date_range, pay_type, type]
* 关键词/订单号筛选逻辑与 OrderCenterServices::getAdminList 保持一致
* @param array $params [keyword, search_field, order_no, date_range, pay_type, type]
* @param OrderCenterServices $centerServices 订单中台服务(复用关键词搜索闭包构建)
* @return array 闭包数组,每个闭包可直接传给 $query->where()
*/
private function buildSearchFilter(array $params): array
private function buildSearchFilter(array $params, OrderCenterServices $centerServices): array
{
$filters = [];
if (!empty($params['keyword'])) {
$keyword = addcslashes($params['keyword'], '%_');
$filters[] = function ($query) use ($keyword) {
$query->where(function ($q) use ($keyword) {
$q->whereOr('order_no', 'LIKE', "{$keyword}%")
->whereOrRaw("extra_info->>'$.contact.name' LIKE ?", ["%{$keyword}%"])
->whereOrRaw("extra_info->>'$.contact.phone' LIKE ?", ["%{$keyword}%"]);
});
};
// 订单号独立搜索框:前缀匹配
if (!empty($params['order_no'])) {
$orderNo = addcslashes(trim((string) $params['order_no']), '%_');
$filters[] = fn($q) => $q->where('order_no', 'LIKE', "{$orderNo}%");
}
// 关键词搜索(search_field 指定字段,口径与中台列表一致)
$keyword = trim((string) ($params['keyword'] ?? ''));
if ($keyword !== '') {
$filters[] = $centerServices->buildKeywordFilterClosure($keyword, (string) ($params['search_field'] ?? 'all'));
}
if (!empty($params['date_range'])) {

View File

@ -320,7 +320,9 @@ function getList() {
*/
function getStatistics() {
const params = {
order_no: searchParams.value.order_no || '',
keyword: searchParams.value.keyword || '',
search_field: searchParams.value.search_field || 'all',
date_range: searchParams.value.date_range || '',
pay_type: searchParams.value.pay_type || '',
type: searchParams.value.type || '',