refactor(api): 统一查询参数处理逻辑,使用where对象集中管理
将分散的查询参数如status、customer_id、ids等统一迁移到where对象中处理 简化DTO结构,移除冗余字段 适配器层统一从where对象获取查询条件
This commit is contained in:
parent
450105972b
commit
0f5610e02e
|
|
@ -550,7 +550,7 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapReviewSearchParams(params: UnifiedSearchParamsDTO): any {
|
private mapReviewSearchParams(params: UnifiedSearchParamsDTO): any {
|
||||||
const { search, page, per_page, status } = params;
|
const { search, page, per_page, where } = params;
|
||||||
const shopyyParams: any = {
|
const shopyyParams: any = {
|
||||||
page: page || 1,
|
page: page || 1,
|
||||||
limit: per_page || 10,
|
limit: per_page || 10,
|
||||||
|
|
@ -560,8 +560,8 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
shopyyParams.search = search;
|
shopyyParams.search = search;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status) {
|
if (where.status) {
|
||||||
shopyyParams.status = status;
|
shopyyParams.status = where.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (product_id) {
|
// if (product_id) {
|
||||||
|
|
|
||||||
|
|
@ -159,26 +159,10 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
const page = Number(params.page ?? 1);
|
const page = Number(params.page ?? 1);
|
||||||
const per_page = Number( params.per_page ?? 20);
|
const per_page = Number( params.per_page ?? 20);
|
||||||
const where = params.where && typeof params.where === 'object' ? params.where : {};
|
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 = {
|
const mapped: any = {
|
||||||
...(params.search ? { search: params.search } : {}),
|
...(params.search ? { search: params.search } : {}),
|
||||||
...(params.status ? { status: params.status } : {}),
|
...(where.status ? { status: where.status } : {}),
|
||||||
...(orderby ? { orderby } : {}),
|
|
||||||
...(order ? { order } : {}),
|
|
||||||
page,
|
page,
|
||||||
per_page,
|
per_page,
|
||||||
};
|
};
|
||||||
|
|
@ -224,10 +208,6 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
if (where.virtual !== undefined) mapped.virtual = Boolean(where.virtual);
|
if (where.virtual !== undefined) mapped.virtual = Boolean(where.virtual);
|
||||||
if (where.downloadable !== undefined) mapped.downloadable = Boolean(where.downloadable);
|
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;
|
return mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -237,30 +217,12 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
const per_page = Number( params.per_page ?? 20);
|
const per_page = Number( params.per_page ?? 20);
|
||||||
// 解析排序参数 支持从 order 对象推导
|
// 解析排序参数 支持从 order 对象推导
|
||||||
const where = params.where && typeof params.where === 'object' ? params.where : {};
|
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 = {
|
const mapped: any = {
|
||||||
...(params.search ? { search: params.search } : {}),
|
...(params.search ? { search: params.search } : {}),
|
||||||
...(orderby ? { orderby } : {}),
|
// ...(orderBy ? { orderBy } : {}),
|
||||||
...(orderDir ? { order: orderDir } : {}),
|
|
||||||
page,
|
page,
|
||||||
per_page,
|
per_page,
|
||||||
};
|
};
|
||||||
|
|
@ -287,13 +249,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
// 集合过滤参数
|
// 集合过滤参数
|
||||||
if (where.exclude) mapped.exclude = toArray(where.exclude);
|
if (where.exclude) mapped.exclude = toArray(where.exclude);
|
||||||
if (where.include) mapped.include = toArray(where.include);
|
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 (toNumber(where.offset) !== undefined) mapped.offset = Number(where.offset);
|
||||||
if (where.parent ?? where.parentId) mapped.parent = toArray(where.parent ?? where.parentId);
|
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);
|
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) {
|
if (statusSource !== undefined) {
|
||||||
mapped.status = Array.isArray(statusSource)
|
mapped.status = Array.isArray(statusSource)
|
||||||
? statusSource.map(s => String(s))
|
? 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 productVal = where.product ?? where.product_id;
|
||||||
const dpVal = where.dp;
|
const dpVal = where.dp;
|
||||||
if (toNumber(customerVal) !== undefined) mapped.customer = Number(customerVal);
|
if (toNumber(customerVal) !== undefined) mapped.customer = Number(customerVal);
|
||||||
|
|
@ -321,28 +283,10 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
const page = Number(params.page ?? 1);
|
const page = Number(params.page ?? 1);
|
||||||
const per_page = Number(params.per_page ?? 20);
|
const per_page = Number(params.per_page ?? 20);
|
||||||
const where = params.where && typeof params.where === 'object' ? params.where : {};
|
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 = {
|
const mapped: any = {
|
||||||
...(params.search ? { search: params.search } : {}),
|
...(params.search ? { search: params.search } : {}),
|
||||||
...(orderby ? { orderby } : {}),
|
|
||||||
...(orderDir ? { order: orderDir } : {}),
|
|
||||||
page,
|
page,
|
||||||
per_page,
|
per_page,
|
||||||
};
|
};
|
||||||
|
|
@ -361,11 +305,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
|
|
||||||
if (where.exclude) mapped.exclude = toArray(where.exclude);
|
if (where.exclude) mapped.exclude = toArray(where.exclude);
|
||||||
if (where.include) mapped.include = toArray(where.include);
|
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 (toNumber(where.offset) !== undefined) mapped.offset = Number(where.offset);
|
||||||
|
|
||||||
if (where.email) mapped.email = String(where.email);
|
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);
|
if (roleSource !== undefined) mapped.role = String(roleSource);
|
||||||
|
|
||||||
return mapped;
|
return mapped;
|
||||||
|
|
|
||||||
|
|
@ -270,8 +270,8 @@ export class SiteApiController {
|
||||||
page += 1;
|
page += 1;
|
||||||
}
|
}
|
||||||
let items = all;
|
let items = all;
|
||||||
if (query.ids) {
|
if (query.where?.ids) {
|
||||||
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
|
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
|
||||||
items = items.filter(i => ids.has(String(i.id)));
|
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'];
|
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 {
|
try {
|
||||||
const adapter = await this.siteApiService.getAdapter(siteId);
|
const adapter = await this.siteApiService.getAdapter(siteId);
|
||||||
const where = { ...(query.where || {}) };
|
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 });
|
const data = await adapter.getOrders({ ...query, where });
|
||||||
this.logger.info(`[Site API] 获取订单列表成功, siteId: ${siteId}, 共获取到 ${data.total} 个订单`);
|
this.logger.info(`[Site API] 获取订单列表成功, siteId: ${siteId}, 共获取到 ${data.total} 个订单`);
|
||||||
return successResponse(data);
|
return successResponse(data);
|
||||||
|
|
@ -623,8 +619,8 @@ export class SiteApiController {
|
||||||
this.logger.info(`[Site API] 获取客户订单列表开始, siteId: ${siteId}, customerId: ${customerId}, query: ${JSON.stringify(query)}`);
|
this.logger.info(`[Site API] 获取客户订单列表开始, siteId: ${siteId}, customerId: ${customerId}, query: ${JSON.stringify(query)}`);
|
||||||
try {
|
try {
|
||||||
const adapter = await this.siteApiService.getAdapter(siteId);
|
const adapter = await this.siteApiService.getAdapter(siteId);
|
||||||
const where = { ...(query.where || {}), customer: customerId, customer_id: customerId };
|
const where = { ...(query.where || {}), customer: customerId };
|
||||||
const data = await adapter.getOrders({ ...query, where, customer_id: customerId });
|
const data = await adapter.getOrders({ ...query, where });
|
||||||
this.logger.info(`[Site API] 获取客户订单列表成功, siteId: ${siteId}, customerId: ${customerId}, 共获取到 ${data.total} 个订单`);
|
this.logger.info(`[Site API] 获取客户订单列表成功, siteId: ${siteId}, customerId: ${customerId}, 共获取到 ${data.total} 个订单`);
|
||||||
return successResponse(data);
|
return successResponse(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -652,8 +648,8 @@ export class SiteApiController {
|
||||||
page += 1;
|
page += 1;
|
||||||
}
|
}
|
||||||
let items = all;
|
let items = all;
|
||||||
if (query.ids) {
|
if (query.where?.ids) {
|
||||||
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
|
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
|
||||||
items = items.filter(i => ids.has(String(i.id)));
|
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'];
|
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;
|
page += 1;
|
||||||
}
|
}
|
||||||
let items = all;
|
let items = all;
|
||||||
if (query.ids) {
|
if (query.where?.ids) {
|
||||||
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
|
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
|
||||||
items = items.filter(i => ids.has(String(i.id)));
|
items = items.filter(i => ids.has(String(i.id)));
|
||||||
}
|
}
|
||||||
const header = ['id', 'status', 'customer_id', 'billing_period', 'billing_interval', 'start_date', 'next_payment_date'];
|
const header = ['id', 'status', 'customer_id', 'billing_period', 'billing_interval', 'start_date', 'next_payment_date'];
|
||||||
|
|
@ -1055,8 +1051,8 @@ export class SiteApiController {
|
||||||
page += 1;
|
page += 1;
|
||||||
}
|
}
|
||||||
let items = all;
|
let items = all;
|
||||||
if (query.ids) {
|
if (query.where?.ids) {
|
||||||
const ids = new Set(String(query.ids).split(',').map(v => v.trim()).filter(Boolean));
|
const ids = new Set(String(query.where.ids).split(',').map(v => v.trim()).filter(Boolean));
|
||||||
items = items.filter(i => ids.has(String(i.id)));
|
items = items.filter(i => ids.has(String(i.id)));
|
||||||
}
|
}
|
||||||
const header = ['id', 'title', 'media_type', 'mime_type', 'source_url', 'date_created'];
|
const header = ['id', 'title', 'media_type', 'mime_type', 'source_url', 'date_created'];
|
||||||
|
|
@ -1220,10 +1216,6 @@ export class SiteApiController {
|
||||||
page += 1;
|
page += 1;
|
||||||
}
|
}
|
||||||
let items = all;
|
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 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) => [
|
const formatAddress = (addr: any) => [
|
||||||
addr?.fullname,
|
addr?.fullname,
|
||||||
|
|
|
||||||
|
|
@ -529,7 +529,7 @@ export class UploadMediaDTO {
|
||||||
filename: string;
|
filename: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UnifiedSearchParamsDTO {
|
export class UnifiedSearchParamsDTO<Where=Record<string, any>> {
|
||||||
// 统一查询参数DTO用于承载分页与筛选与排序参数
|
// 统一查询参数DTO用于承载分页与筛选与排序参数
|
||||||
@ApiProperty({ description: '页码', example: 1, required: false })
|
@ApiProperty({ description: '页码', example: 1, required: false })
|
||||||
page?: number;
|
page?: number;
|
||||||
|
|
@ -537,36 +537,18 @@ export class UnifiedSearchParamsDTO {
|
||||||
@ApiProperty({ description: '每页数量', example: 20, required: false })
|
@ApiProperty({ description: '每页数量', example: 20, required: false })
|
||||||
per_page?: number;
|
per_page?: number;
|
||||||
|
|
||||||
@ApiProperty({ description: '每页数量别名', example: 20, required: false })
|
|
||||||
page_size?: number;
|
|
||||||
|
|
||||||
@ApiProperty({ description: '搜索关键词', required: false })
|
@ApiProperty({ description: '搜索关键词', required: false })
|
||||||
search?: string;
|
search?: string;
|
||||||
|
|
||||||
@ApiProperty({ description: '状态', required: false })
|
|
||||||
status?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: '客户ID,用于筛选订单', required: false })
|
|
||||||
customer_id?: number;
|
|
||||||
|
|
||||||
@ApiProperty({ description: '过滤条件对象', type: 'object', required: false })
|
@ApiProperty({ description: '过滤条件对象', type: 'object', required: false })
|
||||||
where?: Record<string, any>;
|
where?: Where;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: '排序对象,例如 { "sku": "desc" }',
|
description: '排序对象,例如 { "sku": "desc" }',
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: false,
|
required: false,
|
||||||
})
|
})
|
||||||
order?: Record<string, 'asc' | 'desc'> | string;
|
orderBy?: 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UnifiedWebhookDTO {
|
export class UnifiedWebhookDTO {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue