feat(admin): 订单页筛选改版并支持用户与商品模糊搜索
收起次要筛选项,去掉过滤测试;列表可按用户编号/昵称/备注/手机与商品名称/规格查询。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -74,6 +74,56 @@ body.admin-col-resizing * {
|
|||||||
user-select: none !important;
|
user-select: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 订单页筛选:第一行常驻,第二行起可收起 */
|
||||||
|
.admin-orders-filter-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px 16px;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-row--tools {
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-item {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-item--sm {
|
||||||
|
width: 140px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-item--md {
|
||||||
|
width: 168px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-item--search {
|
||||||
|
width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-item--status {
|
||||||
|
width: 220px;
|
||||||
|
min-width: 180px;
|
||||||
|
flex: 1 1 180px;
|
||||||
|
max-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-item--date {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-filter-actions {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-orders-date-picker {
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
/* 列表页顶栏:标题左、主操作右、列设置最右 */
|
/* 列表页顶栏:标题左、主操作右、列设置最右 */
|
||||||
.admin-list-header {
|
.admin-list-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
Alert,
|
Alert,
|
||||||
Button,
|
Button,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Col,
|
|
||||||
Collapse,
|
Collapse,
|
||||||
DatePicker,
|
DatePicker,
|
||||||
Descriptions,
|
Descriptions,
|
||||||
@@ -14,7 +13,6 @@ import {
|
|||||||
InputNumber,
|
InputNumber,
|
||||||
Modal,
|
Modal,
|
||||||
Radio,
|
Radio,
|
||||||
Row,
|
|
||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Table,
|
Table,
|
||||||
@@ -24,6 +22,7 @@ import {
|
|||||||
} from 'antd';
|
} from 'antd';
|
||||||
import type { ColumnsType } from 'antd/es/table';
|
import type { ColumnsType } from 'antd/es/table';
|
||||||
import dayjs, { type Dayjs } from 'dayjs';
|
import dayjs, { type Dayjs } from 'dayjs';
|
||||||
|
import { DownOutlined, UpOutlined } from '@ant-design/icons';
|
||||||
import { ORDER_TYPE_LABELS } from '@dukang/shared-types';
|
import { ORDER_TYPE_LABELS } from '@dukang/shared-types';
|
||||||
import { request, type AdminOrderItem, type AdminOrderRow, type HqProfile, type Paginated } from '../lib/api';
|
import { request, type AdminOrderItem, type AdminOrderRow, type HqProfile, type Paginated } from '../lib/api';
|
||||||
import { useAdminListColumns } from '../lib/useAdminListColumns';
|
import { useAdminListColumns } from '../lib/useAdminListColumns';
|
||||||
@@ -150,8 +149,9 @@ type OrderExportFilters = {
|
|||||||
orderType?: string;
|
orderType?: string;
|
||||||
cityId?: string;
|
cityId?: string;
|
||||||
receiverPhone?: string;
|
receiverPhone?: string;
|
||||||
|
userKeyword?: string;
|
||||||
|
productKeyword?: string;
|
||||||
fulfillmentHold?: boolean;
|
fulfillmentHold?: boolean;
|
||||||
excludeTest?: boolean;
|
|
||||||
deliveryType?: string;
|
deliveryType?: string;
|
||||||
promoCodeId?: string;
|
promoCodeId?: string;
|
||||||
dateRange?: [Dayjs, Dayjs];
|
dateRange?: [Dayjs, Dayjs];
|
||||||
@@ -213,6 +213,8 @@ const DATE_PRESETS: Array<{ key: 'day' | 'week' | 'month' | 'quarter' | 'year';
|
|||||||
{ key: 'year', label: '当年' },
|
{ key: 'year', label: '当年' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const FILTERS_COLLAPSED_KEY = 'admin-orders-filters-collapsed';
|
||||||
|
|
||||||
function formatUserWithRemark(user?: {
|
function formatUserWithRemark(user?: {
|
||||||
userNo?: string;
|
userNo?: string;
|
||||||
hqRemark?: string | null;
|
hqRemark?: string | null;
|
||||||
@@ -254,9 +256,10 @@ function buildExportPayload(
|
|||||||
if (filters.orderType) payload.orderType = filters.orderType;
|
if (filters.orderType) payload.orderType = filters.orderType;
|
||||||
if (filters.cityId) payload.cityId = filters.cityId;
|
if (filters.cityId) payload.cityId = filters.cityId;
|
||||||
if (filters.receiverPhone) payload.receiverPhone = filters.receiverPhone;
|
if (filters.receiverPhone) payload.receiverPhone = filters.receiverPhone;
|
||||||
|
if (filters.userKeyword) payload.userKeyword = filters.userKeyword;
|
||||||
|
if (filters.productKeyword) payload.productKeyword = filters.productKeyword;
|
||||||
if (filters.deliveryType) payload.deliveryType = filters.deliveryType;
|
if (filters.deliveryType) payload.deliveryType = filters.deliveryType;
|
||||||
if (filters.fulfillmentHold) payload.fulfillmentHold = true;
|
if (filters.fulfillmentHold) payload.fulfillmentHold = true;
|
||||||
if (filters.excludeTest) payload.excludeTest = true;
|
|
||||||
if (filters.promoCodeId) payload.promoCodeId = filters.promoCodeId;
|
if (filters.promoCodeId) payload.promoCodeId = filters.promoCodeId;
|
||||||
if (filters.dateRange?.[0]) payload.createdFrom = filters.dateRange[0].format('YYYY-MM-DD');
|
if (filters.dateRange?.[0]) payload.createdFrom = filters.dateRange[0].format('YYYY-MM-DD');
|
||||||
if (filters.dateRange?.[1]) payload.createdTo = filters.dateRange[1].format('YYYY-MM-DD');
|
if (filters.dateRange?.[1]) payload.createdTo = filters.dateRange[1].format('YYYY-MM-DD');
|
||||||
@@ -335,6 +338,13 @@ export default function OrdersPage() {
|
|||||||
const [trackOpen, setTrackOpen] = useState(false);
|
const [trackOpen, setTrackOpen] = useState(false);
|
||||||
const [exporting, setExporting] = useState(false);
|
const [exporting, setExporting] = useState(false);
|
||||||
const [exportFormat, setExportFormat] = useState<OrderExportFormat>('xlsx');
|
const [exportFormat, setExportFormat] = useState<OrderExportFormat>('xlsx');
|
||||||
|
const [filtersCollapsed, setFiltersCollapsed] = useState(() => {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(FILTERS_COLLAPSED_KEY) === '1';
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
const canDeleteOrders = (profile?.permissionKeys ?? []).includes('orders_delete');
|
const canDeleteOrders = (profile?.permissionKeys ?? []).includes('orders_delete');
|
||||||
const canProxyOrder = (profile?.permissionKeys ?? []).includes('orders');
|
const canProxyOrder = (profile?.permissionKeys ?? []).includes('orders');
|
||||||
const canExportOrders = (profile?.permissionKeys ?? []).includes('orders');
|
const canExportOrders = (profile?.permissionKeys ?? []).includes('orders');
|
||||||
@@ -404,8 +414,9 @@ export default function OrdersPage() {
|
|||||||
if (values.orderType) qs.set('orderType', values.orderType);
|
if (values.orderType) qs.set('orderType', values.orderType);
|
||||||
if (values.cityId) qs.set('cityId', values.cityId);
|
if (values.cityId) qs.set('cityId', values.cityId);
|
||||||
if (values.receiverPhone) qs.set('receiverPhone', values.receiverPhone);
|
if (values.receiverPhone) qs.set('receiverPhone', values.receiverPhone);
|
||||||
|
if (values.userKeyword) qs.set('userKeyword', values.userKeyword);
|
||||||
|
if (values.productKeyword) qs.set('productKeyword', values.productKeyword);
|
||||||
if (values.fulfillmentHold) qs.set('fulfillmentHold', 'true');
|
if (values.fulfillmentHold) qs.set('fulfillmentHold', 'true');
|
||||||
if (values.excludeTest) qs.set('excludeTest', 'true');
|
|
||||||
if (values.deliveryType) qs.set('deliveryType', values.deliveryType);
|
if (values.deliveryType) qs.set('deliveryType', values.deliveryType);
|
||||||
if (initialPromoCodeId) qs.set('promoCodeId', initialPromoCodeId);
|
if (initialPromoCodeId) qs.set('promoCodeId', initialPromoCodeId);
|
||||||
if (values.dateRange?.[0]) qs.set('createdFrom', values.dateRange[0].format('YYYY-MM-DD'));
|
if (values.dateRange?.[0]) qs.set('createdFrom', values.dateRange[0].format('YYYY-MM-DD'));
|
||||||
@@ -843,14 +854,72 @@ export default function OrdersPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Form form={form} layout="vertical" onFinish={() => { setPage(1); void load(); }}>
|
<Form form={form} layout="vertical" onFinish={() => { setPage(1); void load(); }}>
|
||||||
<Row gutter={[16, 8]}>
|
<div className="admin-orders-filter-row">
|
||||||
<Col xs={24} md={14} lg={12}>
|
<Form.Item name="cityId" label="城市" className="admin-orders-filter-item admin-orders-filter-item--sm">
|
||||||
<Form.Item label="下单日期" style={{ marginBottom: 12 }}>
|
<Select
|
||||||
<Space direction="vertical" size={8} style={{ width: '100%' }}>
|
allowClear
|
||||||
<Form.Item name="dateRange" noStyle>
|
showSearch
|
||||||
<DatePicker.RangePicker allowClear style={{ width: '100%' }} />
|
optionFilterProp="label"
|
||||||
</Form.Item>
|
placeholder="全部"
|
||||||
|
options={cities.map((c) => ({ value: c.id, label: c.name }))}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="receiverPhone" label="手机号" className="admin-orders-filter-item admin-orders-filter-item--md">
|
||||||
|
<Input allowClear placeholder="手机号" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="userKeyword" label="用户" className="admin-orders-filter-item admin-orders-filter-item--search">
|
||||||
|
<Input allowClear placeholder="编号/昵称/备注/手机" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="productKeyword" label="商品" className="admin-orders-filter-item admin-orders-filter-item--search">
|
||||||
|
<Input allowClear placeholder="名称/规格" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="status" label="状态" className="admin-orders-filter-item admin-orders-filter-item--status">
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
allowClear
|
||||||
|
maxTagCount="responsive"
|
||||||
|
placeholder="全部"
|
||||||
|
options={Object.entries(ORDER_STATUS_LABELS).map(([value, label]) => ({ value, label }))}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="orderType" label="类型" className="admin-orders-filter-item admin-orders-filter-item--sm">
|
||||||
|
<Select allowClear placeholder="全部" options={ORDER_TYPE_OPTIONS} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item name="deliveryType" label="配送" className="admin-orders-filter-item admin-orders-filter-item--sm">
|
||||||
|
<Select allowClear placeholder="全部" options={DELIVERY_TYPE_OPTIONS} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label=" " colon={false} className="admin-orders-filter-item admin-orders-filter-actions">
|
||||||
|
<Space size={8} wrap>
|
||||||
|
<Button type="primary" htmlType="submit">查询</Button>
|
||||||
|
<Button
|
||||||
|
type="link"
|
||||||
|
icon={filtersCollapsed ? <DownOutlined /> : <UpOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
setFiltersCollapsed((prev) => {
|
||||||
|
const next = !prev;
|
||||||
|
try {
|
||||||
|
localStorage.setItem(FILTERS_COLLAPSED_KEY, next ? '1' : '0');
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{filtersCollapsed ? '展开' : '收起'}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!filtersCollapsed ? (
|
||||||
|
<>
|
||||||
|
<div className="admin-orders-filter-row">
|
||||||
|
<Form.Item label="下单日期" className="admin-orders-filter-item admin-orders-filter-item--date">
|
||||||
<Space size={8} wrap>
|
<Space size={8} wrap>
|
||||||
|
<Form.Item name="dateRange" noStyle>
|
||||||
|
<DatePicker.RangePicker allowClear className="admin-orders-date-picker" />
|
||||||
|
</Form.Item>
|
||||||
{DATE_PRESETS.map((preset) => (
|
{DATE_PRESETS.map((preset) => (
|
||||||
<Button
|
<Button
|
||||||
key={preset.key}
|
key={preset.key}
|
||||||
@@ -861,107 +930,60 @@ export default function OrdersPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</Space>
|
</Space>
|
||||||
</Space>
|
</Form.Item>
|
||||||
</Form.Item>
|
</div>
|
||||||
</Col>
|
|
||||||
<Col xs={24} sm={12} md={8} lg={6}>
|
<div className="admin-orders-filter-row admin-orders-filter-row--tools">
|
||||||
<Form.Item name="status" label="状态" style={{ marginBottom: 12 }}>
|
{canExportOrders ? (
|
||||||
<Select
|
<Space size={12} wrap>
|
||||||
mode="multiple"
|
<Radio.Group
|
||||||
allowClear
|
optionType="button"
|
||||||
maxTagCount="responsive"
|
buttonStyle="solid"
|
||||||
placeholder="全部"
|
value={exportFormat}
|
||||||
options={Object.entries(ORDER_STATUS_LABELS).map(([value, label]) => ({ value, label }))}
|
onChange={(e) => setExportFormat(e.target.value)}
|
||||||
/>
|
>
|
||||||
</Form.Item>
|
<Radio.Button value="xlsx">Excel</Radio.Button>
|
||||||
</Col>
|
<Radio.Button value="pdf">PDF</Radio.Button>
|
||||||
<Col xs={12} sm={6} md={5} lg={3}>
|
</Radio.Group>
|
||||||
<Form.Item name="orderType" label="类型" style={{ marginBottom: 12 }}>
|
<Button
|
||||||
<Select allowClear placeholder="全部" options={ORDER_TYPE_OPTIONS} />
|
disabled={!selectedRowKeys.length}
|
||||||
</Form.Item>
|
loading={exporting}
|
||||||
</Col>
|
onClick={() => void submitExport('selected')}
|
||||||
<Col xs={12} sm={6} md={5} lg={3}>
|
>
|
||||||
<Form.Item name="deliveryType" label="配送" style={{ marginBottom: 12 }}>
|
导出已勾选{selectedRowKeys.length ? `(${selectedRowKeys.length})` : ''}
|
||||||
<Select allowClear placeholder="全部" options={DELIVERY_TYPE_OPTIONS} />
|
</Button>
|
||||||
</Form.Item>
|
<Button loading={exporting} onClick={() => void submitExport('filter')}>
|
||||||
</Col>
|
导出全部筛选
|
||||||
<Col xs={12} sm={6} md={5} lg={3}>
|
</Button>
|
||||||
<Form.Item name="cityId" label="城市" style={{ marginBottom: 12 }}>
|
</Space>
|
||||||
<Select
|
) : <span />}
|
||||||
allowClear
|
<Space size={12} wrap>
|
||||||
showSearch
|
|
||||||
optionFilterProp="label"
|
|
||||||
placeholder="全部"
|
|
||||||
options={cities.map((c) => ({ value: c.id, label: c.name }))}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col xs={12} sm={8} md={6} lg={6}>
|
|
||||||
<Form.Item name="receiverPhone" label="收货手机" style={{ marginBottom: 12 }}>
|
|
||||||
<Input allowClear placeholder="手机号" />
|
|
||||||
</Form.Item>
|
|
||||||
</Col>
|
|
||||||
<Col xs={12} sm={8} md={8} lg={8}>
|
|
||||||
<Form.Item label=" " colon={false} style={{ marginBottom: 12 }}>
|
|
||||||
<Space size={16} wrap>
|
|
||||||
<Form.Item name="fulfillmentHold" valuePropName="checked" noStyle>
|
<Form.Item name="fulfillmentHold" valuePropName="checked" noStyle>
|
||||||
<Checkbox>大单拦截</Checkbox>
|
<Checkbox>大单拦截</Checkbox>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="excludeTest" valuePropName="checked" noStyle>
|
<Button
|
||||||
<Checkbox>过滤测试</Checkbox>
|
onClick={() => {
|
||||||
</Form.Item>
|
form.resetFields();
|
||||||
|
setPage(1);
|
||||||
|
if (initialPromoCodeId || initialOrderNo || initialStatuses.length) navigate('/orders');
|
||||||
|
else void load();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
重置
|
||||||
|
</Button>
|
||||||
|
{canDeleteOrders ? (
|
||||||
|
<Button
|
||||||
|
danger
|
||||||
|
disabled={!selectedRowKeys.length}
|
||||||
|
onClick={() => setBatchDeleteOpen(true)}
|
||||||
|
>
|
||||||
|
批量删除{selectedRowKeys.length ? `(${selectedRowKeys.length})` : ''}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
</Space>
|
</Space>
|
||||||
</Form.Item>
|
</div>
|
||||||
</Col>
|
</>
|
||||||
</Row>
|
) : null}
|
||||||
|
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', margin: '8px 0 16px', gap: 12, flexWrap: 'wrap' }}>
|
|
||||||
{canExportOrders ? (
|
|
||||||
<Space size={12} wrap>
|
|
||||||
<Radio.Group
|
|
||||||
optionType="button"
|
|
||||||
buttonStyle="solid"
|
|
||||||
value={exportFormat}
|
|
||||||
onChange={(e) => setExportFormat(e.target.value)}
|
|
||||||
>
|
|
||||||
<Radio.Button value="xlsx">Excel</Radio.Button>
|
|
||||||
<Radio.Button value="pdf">PDF</Radio.Button>
|
|
||||||
</Radio.Group>
|
|
||||||
<Button
|
|
||||||
disabled={!selectedRowKeys.length}
|
|
||||||
loading={exporting}
|
|
||||||
onClick={() => void submitExport('selected')}
|
|
||||||
>
|
|
||||||
导出已勾选{selectedRowKeys.length ? `(${selectedRowKeys.length})` : ''}
|
|
||||||
</Button>
|
|
||||||
<Button loading={exporting} onClick={() => void submitExport('filter')}>
|
|
||||||
导出全部筛选
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
) : <span />}
|
|
||||||
<Space size={12} wrap>
|
|
||||||
<Button type="primary" htmlType="submit">查询</Button>
|
|
||||||
<Button
|
|
||||||
onClick={() => {
|
|
||||||
form.resetFields();
|
|
||||||
setPage(1);
|
|
||||||
if (initialPromoCodeId || initialOrderNo || initialStatuses.length) navigate('/orders');
|
|
||||||
else void load();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
重置
|
|
||||||
</Button>
|
|
||||||
{canDeleteOrders ? (
|
|
||||||
<Button
|
|
||||||
danger
|
|
||||||
disabled={!selectedRowKeys.length}
|
|
||||||
onClick={() => setBatchDeleteOpen(true)}
|
|
||||||
>
|
|
||||||
批量删除{selectedRowKeys.length ? `(${selectedRowKeys.length})` : ''}
|
|
||||||
</Button>
|
|
||||||
) : null}
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<Table
|
<Table
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ export interface AdminOrdersListQuery extends AdminListQuery {
|
|||||||
status?: string | string[];
|
status?: string | string[];
|
||||||
orderType?: string;
|
orderType?: string;
|
||||||
userId?: string;
|
userId?: string;
|
||||||
|
userKeyword?: string;
|
||||||
|
productKeyword?: string;
|
||||||
cityId?: string;
|
cityId?: string;
|
||||||
receiverPhone?: string;
|
receiverPhone?: string;
|
||||||
fulfillmentHold?: string | boolean;
|
fulfillmentHold?: string | boolean;
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ type OrderFilterInput = Pick<
|
|||||||
| 'status'
|
| 'status'
|
||||||
| 'orderType'
|
| 'orderType'
|
||||||
| 'userId'
|
| 'userId'
|
||||||
|
| 'userKeyword'
|
||||||
|
| 'productKeyword'
|
||||||
| 'cityId'
|
| 'cityId'
|
||||||
| 'receiverPhone'
|
| 'receiverPhone'
|
||||||
| 'fulfillmentHold'
|
| 'fulfillmentHold'
|
||||||
@@ -177,8 +179,28 @@ export class AdminOrdersService {
|
|||||||
}
|
}
|
||||||
if (query.orderType) where.orderType = query.orderType as Prisma.EnumOrderTypeFilter['equals'];
|
if (query.orderType) where.orderType = query.orderType as Prisma.EnumOrderTypeFilter['equals'];
|
||||||
if (query.userId) where.userId = BigInt(query.userId);
|
if (query.userId) where.userId = BigInt(query.userId);
|
||||||
|
const userKeyword = query.userKeyword?.trim();
|
||||||
|
if (userKeyword) {
|
||||||
|
const userOr: Prisma.UserWhereInput[] = [
|
||||||
|
{ userNo: { contains: userKeyword } },
|
||||||
|
{ nickname: { contains: userKeyword } },
|
||||||
|
{ hqRemark: { contains: userKeyword } },
|
||||||
|
{ phone: { contains: userKeyword } },
|
||||||
|
];
|
||||||
|
if (/^\d+$/.test(userKeyword)) {
|
||||||
|
userOr.push({ id: BigInt(userKeyword) });
|
||||||
|
}
|
||||||
|
where.user = { OR: userOr };
|
||||||
|
}
|
||||||
if (query.cityId) where.cityId = BigInt(query.cityId);
|
if (query.cityId) where.cityId = BigInt(query.cityId);
|
||||||
if (query.receiverPhone) where.receiverPhone = { contains: query.receiverPhone };
|
if (query.receiverPhone) where.receiverPhone = { contains: query.receiverPhone };
|
||||||
|
const productKeyword = query.productKeyword?.trim();
|
||||||
|
if (productKeyword) {
|
||||||
|
where.OR = [
|
||||||
|
{ productName: { contains: productKeyword } },
|
||||||
|
{ productSpec: { contains: productKeyword } },
|
||||||
|
];
|
||||||
|
}
|
||||||
if (query.deliveryType) {
|
if (query.deliveryType) {
|
||||||
where.deliveryType = query.deliveryType as Prisma.EnumDeliveryTypeFilter['equals'];
|
where.deliveryType = query.deliveryType as Prisma.EnumDeliveryTypeFilter['equals'];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,6 +93,16 @@ export class AdminOrdersQueryDto extends PaginationQueryDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
userId?: string;
|
userId?: string;
|
||||||
|
|
||||||
|
/** 用户编号 / 昵称 / 备注 / 手机 模糊匹配 */
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
userKeyword?: string;
|
||||||
|
|
||||||
|
/** 商品名称 / 规格 模糊匹配 */
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
productKeyword?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
cityId?: string;
|
cityId?: string;
|
||||||
@@ -159,6 +169,14 @@ export class AdminOrdersExportDto {
|
|||||||
@IsString()
|
@IsString()
|
||||||
cityId?: string;
|
cityId?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
userKeyword?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
productKeyword?: string;
|
||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsString()
|
@IsString()
|
||||||
receiverPhone?: string;
|
receiverPhone?: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user