refactor(api): 统一查询参数处理逻辑,使用where对象集中管理

将分散的查询参数如status、customer_id、ids等统一迁移到where对象中处理
简化DTO结构,移除冗余字段
适配器层统一从where对象获取查询条件
This commit is contained in:
tikkhun 2025-12-22 17:30:47 +08:00 committed by 黄珑
parent bc1d4de446
commit a02758a926
4 changed files with 28 additions and 110 deletions

View File

@ -550,7 +550,7 @@ export class ShopyyAdapter implements ISiteAdapter {
}
private mapReviewSearchParams(params: UnifiedSearchParamsDTO): any {
const { search, page, per_page, status } = params;
const { search, page, per_page, where } = params;
const shopyyParams: any = {
page: page || 1,
limit: per_page || 10,
@ -560,8 +560,8 @@ export class ShopyyAdapter implements ISiteAdapter {
shopyyParams.search = search;
}
if (status) {
shopyyParams.status = status;
if (where.status) {
shopyyParams.status = where.status;
}
// if (product_id) {

View File

@ -159,26 +159,10 @@ export class WooCommerceAdapter implements ISiteAdapter {
const page = Number(params.page ?? 1);
const per_page = Number( params.per_page ?? 20);
const where = params.where && typeof params.where === 'object' ? params.where : {};
let orderby: string | undefined = params.orderby;
let order: 'asc' | 'desc' | undefined = params.orderDir as any;
if (!orderby && params.order && typeof params.order === 'object') {
const entries = Object.entries(params.order as Record<string, any>);
if (entries.length > 0) {
const [field, dir] = entries[0];
let mappedField = field;
if (['created_at', 'date_created', 'date'].includes(field)) mappedField = 'date';
else if (['name', 'title'].includes(field)) mappedField = 'title';
else if (['id', 'ID'].includes(field)) mappedField = 'id';
else if (['price', 'regular_price', 'sale_price'].includes(field)) mappedField = 'price';
orderby = mappedField;
order = String(dir).toLowerCase() === 'desc' ? 'desc' : 'asc';
}
}
const mapped: any = {
...(params.search ? { search: params.search } : {}),
...(params.status ? { status: params.status } : {}),
...(orderby ? { orderby } : {}),
...(order ? { order } : {}),
...(where.status ? { status: where.status } : {}),
page,
per_page,
};
@ -224,10 +208,6 @@ export class WooCommerceAdapter implements ISiteAdapter {
if (where.virtual !== undefined) mapped.virtual = Boolean(where.virtual);
if (where.downloadable !== undefined) mapped.downloadable = Boolean(where.downloadable);
if (params.ids) {
const idsArr = String(params.ids).split(',').map(v => v.trim()).filter(Boolean);
mapped.include = idsArr;
}
return mapped;
}
@ -237,30 +217,12 @@ export class WooCommerceAdapter implements ISiteAdapter {
const per_page = Number( params.per_page ?? 20);
// 解析排序参数 支持从 order 对象推导
const where = params.where && typeof params.where === 'object' ? params.where : {};
let orderby: string | undefined = params.orderby;
let orderDir: 'asc' | 'desc' | undefined = params.orderDir as any;
if (!orderby && params.order && typeof params.order === 'object') {
const entries = Object.entries(params.order as Record<string, any>);
if (entries.length > 0) {
const [field, dir] = entries[0];
let mappedField = field;
if (['created_at', 'date_created', 'date'].includes(field)) mappedField = 'date';
else if (['modified', 'date_modified'].includes(field)) mappedField = 'modified';
else if (['id', 'ID'].includes(field)) mappedField = 'id';
else if (['name', 'title'].includes(field)) mappedField = 'title';
else if (['slug'].includes(field)) mappedField = 'slug';
else if (['include'].includes(field)) mappedField = 'include';
orderby = mappedField;
orderDir = String(dir).toLowerCase() === 'asc' ? 'asc' : 'desc';
}
} else if (!orderDir && typeof params.order === 'string') {
orderDir = String(params.order).toLowerCase() === 'asc' ? 'asc' : 'desc';
}
// if (params.orderBy && typeof params.orderBy === 'object') {
// }
const mapped: any = {
...(params.search ? { search: params.search } : {}),
...(orderby ? { orderby } : {}),
...(orderDir ? { order: orderDir } : {}),
// ...(orderBy ? { orderBy } : {}),
page,
per_page,
};
@ -287,13 +249,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
// 集合过滤参数
if (where.exclude) mapped.exclude = toArray(where.exclude);
if (where.include) mapped.include = toArray(where.include);
if (params.ids) mapped.include = String(params.ids).split(',').map(v => v.trim()).filter(Boolean);
if (where.ids) mapped.include = toArray(where.ids);
if (toNumber(where.offset) !== undefined) mapped.offset = Number(where.offset);
if (where.parent ?? where.parentId) mapped.parent = toArray(where.parent ?? where.parentId);
if (where.parent_exclude ?? where.parentExclude) mapped.parent_exclude = toArray(where.parent_exclude ?? where.parentExclude);
// 状态过滤 参数支持数组或逗号分隔字符串
const statusSource = params.status ?? where.status;
const statusSource = where.status;
if (statusSource !== undefined) {
mapped.status = Array.isArray(statusSource)
? statusSource.map(s => String(s))
@ -301,7 +263,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
}
// 客户与产品过滤
const customerVal = params.customer_id ?? where.customer ?? where.customer_id;
const customerVal = where.customer ?? where.customer_id;
const productVal = where.product ?? where.product_id;
const dpVal = where.dp;
if (toNumber(customerVal) !== undefined) mapped.customer = Number(customerVal);
@ -321,28 +283,10 @@ export class WooCommerceAdapter implements ISiteAdapter {
const page = Number(params.page ?? 1);
const per_page = Number(params.per_page ?? 20);
const where = params.where && typeof params.where === 'object' ? params.where : {};
let orderby: string | undefined = params.orderby;
let orderDir: 'asc' | 'desc' | undefined = params.orderDir as any;
if (!orderby && params.order && typeof params.order === 'object') {
const entries = Object.entries(params.order as Record<string, any>);
if (entries.length > 0) {
const [field, dir] = entries[0];
let mappedField = field;
if (['id', 'ID'].includes(field)) mappedField = 'id';
else if (['include'].includes(field)) mappedField = 'include';
else if (['name', 'username'].includes(field)) mappedField = 'name';
else if (['registered_date', 'date_created', 'registered', 'registeredDate'].includes(field)) mappedField = 'registered_date';
orderby = mappedField;
orderDir = String(dir).toLowerCase() === 'asc' ? 'asc' : 'desc';
}
} else if (!orderDir && typeof params.order === 'string') {
orderDir = String(params.order).toLowerCase() === 'asc' ? 'asc' : 'desc';
}
const mapped: any = {
...(params.search ? { search: params.search } : {}),
...(orderby ? { orderby } : {}),
...(orderDir ? { order: orderDir } : {}),
page,
per_page,
};
@ -361,11 +305,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
if (where.exclude) mapped.exclude = toArray(where.exclude);
if (where.include) mapped.include = toArray(where.include);
if (params.ids) mapped.include = String(params.ids).split(',').map(v => v.trim()).filter(Boolean);
if (where.ids) mapped.include = toArray(where.ids);
if (toNumber(where.offset) !== undefined) mapped.offset = Number(where.offset);
if (where.email) mapped.email = String(where.email);
const roleSource = where.role ?? params.status;
const roleSource = where.role;
if (roleSource !== undefined) mapped.role = String(roleSource);
return mapped;

View File

@ -270,8 +270,8 @@ export class SiteApiController {
page += 1;
}
let items = all;
if (query.ids) {
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
if (query.where?.ids) {
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
items = items.filter(i => ids.has(String(i.id)));
}
const header = ['id', 'name', 'type', 'status', 'sku', 'regular_price', 'sale_price', 'price', 'stock_status', 'stock_quantity', 'image_src'];
@ -600,10 +600,6 @@ export class SiteApiController {
try {
const adapter = await this.siteApiService.getAdapter(siteId);
const where = { ...(query.where || {}) };
if (query.customer_id) {
where.customer = query.customer_id;
where.customer_id = query.customer_id;
}
const data = await adapter.getOrders({ ...query, where });
this.logger.info(`[Site API] 获取订单列表成功, siteId: ${siteId}, 共获取到 ${data.total} 个订单`);
return successResponse(data);
@ -623,8 +619,8 @@ export class SiteApiController {
this.logger.info(`[Site API] 获取客户订单列表开始, siteId: ${siteId}, customerId: ${customerId}, query: ${JSON.stringify(query)}`);
try {
const adapter = await this.siteApiService.getAdapter(siteId);
const where = { ...(query.where || {}), customer: customerId, customer_id: customerId };
const data = await adapter.getOrders({ ...query, where, customer_id: customerId });
const where = { ...(query.where || {}), customer: customerId };
const data = await adapter.getOrders({ ...query, where });
this.logger.info(`[Site API] 获取客户订单列表成功, siteId: ${siteId}, customerId: ${customerId}, 共获取到 ${data.total} 个订单`);
return successResponse(data);
} catch (error) {
@ -652,8 +648,8 @@ export class SiteApiController {
page += 1;
}
let items = all;
if (query.ids) {
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
if (query.where?.ids) {
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
items = items.filter(i => ids.has(String(i.id)));
}
const header = ['id', 'number', 'status', 'currency', 'total', 'customer_id', 'customer_name', 'email', 'payment_method', 'phone', 'billing_full_address', 'shipping_full_address', 'date_created'];
@ -1005,8 +1001,8 @@ export class SiteApiController {
page += 1;
}
let items = all;
if (query.ids) {
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
if (query.where?.ids) {
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
items = items.filter(i => ids.has(String(i.id)));
}
const header = ['id', 'status', 'customer_id', 'billing_period', 'billing_interval', 'start_date', 'next_payment_date'];
@ -1055,8 +1051,8 @@ export class SiteApiController {
page += 1;
}
let items = all;
if (query.ids) {
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
if (query.where?.ids) {
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
items = items.filter(i => ids.has(String(i.id)));
}
const header = ['id', 'title', 'media_type', 'mime_type', 'source_url', 'date_created'];
@ -1220,10 +1216,6 @@ export class SiteApiController {
page += 1;
}
let items = all;
if (query.ids) {
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
items = items.filter(i => ids.has(String(i.id)));
}
const header = ['id', 'email', 'first_name', 'last_name', 'fullname', 'username', 'phone', 'orders', 'total_spend', 'role', 'billing_full_address', 'shipping_full_address', 'date_created'];
const formatAddress = (addr: any) => [
addr?.fullname,

View File

@ -529,7 +529,7 @@ export class UploadMediaDTO {
filename: string;
}
export class UnifiedSearchParamsDTO {
export class UnifiedSearchParamsDTO<Where=Record<string, any>> {
// 统一查询参数DTO用于承载分页与筛选与排序参数
@ApiProperty({ description: '页码', example: 1, required: false })
page?: number;
@ -537,36 +537,18 @@ export class UnifiedSearchParamsDTO {
@ApiProperty({ description: '每页数量', example: 20, required: false })
per_page?: number;
@ApiProperty({ description: '每页数量别名', example: 20, required: false })
page_size?: number;
@ApiProperty({ description: '搜索关键词', required: false })
search?: string;
@ApiProperty({ description: '状态', required: false })
status?: string;
@ApiProperty({ description: '客户ID,用于筛选订单', required: false })
customer_id?: number;
@ApiProperty({ description: '过滤条件对象', type: 'object', required: false })
where?: Record<string, any>;
where?: Where;
@ApiProperty({
description: '排序对象,例如 { "sku": "desc" }',
type: 'object',
required: false,
})
order?: Record<string, 'asc' | 'desc'> | string;
@ApiProperty({ description: '排序字段(兼容旧入参)', required: false })
orderby?: string;
@ApiProperty({ description: '排序方式(兼容旧入参)', required: false })
orderDir?: 'asc' | 'desc';
@ApiProperty({ description: '选中ID列表,逗号分隔', required: false })
ids?: string;
orderBy?: Record<string, 'asc' | 'desc'> | string;
}
export class UnifiedWebhookDTO {