forked from yoone/API
1
0
Fork 0

feat(adapter): 添加getAll方法支持批量获取数据

实现WooCommerceAdapter中的getAllProducts、getAllOrders等方法
添加ISiteAdapter接口中的对应方法定义
更新customer.service使用getAllCustomers方法
This commit is contained in:
tikkhun 2025-12-23 19:33:12 +08:00 committed by 黄珑
parent 8e7ec2372d
commit 8f7f35c538
6 changed files with 133 additions and 14 deletions

4
.gitignore vendored
View File

@ -16,6 +16,6 @@ yarn.lock
**/config.local.ts
container
scripts
ai
tmp_uploads/
.trae
.trae
docs

View File

@ -321,6 +321,11 @@ export class ShopyyAdapter implements ISiteAdapter {
};
}
async getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]> {
// Shopyy getAllProducts 暂未实现
throw new Error('Shopyy getAllProducts 暂未实现');
}
async getProduct(id: string | number): Promise<UnifiedProductDTO> {
// 使用ShopyyService获取单个产品
const product = await this.shopyyService.getProduct(this.site, id);
@ -385,6 +390,11 @@ export class ShopyyAdapter implements ISiteAdapter {
};
}
async getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]> {
// Shopyy getAllOrders 暂未实现
throw new Error('Shopyy getAllOrders 暂未实现');
}
async getOrder(id: string | number): Promise<UnifiedOrderDTO> {
const data = await this.shopyyService.getOrder(String(this.site.id), String(id));
return this.mapOrder(data);
@ -478,6 +488,11 @@ export class ShopyyAdapter implements ISiteAdapter {
throw new Error('Shopyy does not support subscriptions.');
}
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
// Shopyy getAllSubscriptions 暂未实现
throw new Error('Shopyy getAllSubscriptions 暂未实现');
}
async getMedia(
params: UnifiedSearchParamsDTO
): Promise<UnifiedPaginationDTO<UnifiedMediaDTO>> {
@ -488,7 +503,7 @@ export class ShopyyAdapter implements ISiteAdapter {
requestParams
);
return {
items: items.map(this.mapMedia),
items: items.map(this.mapMedia.bind(this)),
total,
totalPages,
page,
@ -496,6 +511,11 @@ export class ShopyyAdapter implements ISiteAdapter {
};
}
async getAllMedia(params?: UnifiedSearchParamsDTO): Promise<UnifiedMediaDTO[]> {
// Shopyy getAllMedia 暂未实现
throw new Error('Shopyy getAllMedia 暂未实现');
}
async createMedia(file: any): Promise<UnifiedMediaDTO> {
const createdMedia = await this.shopyyService.createMedia(this.site, file);
return this.mapMedia(createdMedia);
@ -527,6 +547,11 @@ export class ShopyyAdapter implements ISiteAdapter {
};
}
async getAllReviews(params?: UnifiedSearchParamsDTO): Promise<UnifiedReviewDTO[]> {
// Shopyy getAllReviews 暂未实现
throw new Error('Shopyy getAllReviews 暂未实现');
}
async getReview(id: string | number): Promise<UnifiedReviewDTO> {
const review = await this.shopyyService.getReview(this.site, id);
return this.mapReview(review);
@ -607,6 +632,11 @@ export class ShopyyAdapter implements ISiteAdapter {
};
}
async getAllWebhooks(params?: UnifiedSearchParamsDTO): Promise<UnifiedWebhookDTO[]> {
// Shopyy getAllWebhooks 暂未实现
throw new Error('Shopyy getAllWebhooks 暂未实现');
}
async getWebhook(id: string | number): Promise<UnifiedWebhookDTO> {
const webhook = await this.shopyyService.getWebhook(this.site, id);
return this.mapWebhook(webhook);
@ -657,6 +687,11 @@ export class ShopyyAdapter implements ISiteAdapter {
};
}
async getAllCustomers(params?: UnifiedSearchParamsDTO): Promise<UnifiedCustomerDTO[]> {
// Shopyy getAllCustomers 暂未实现
throw new Error('Shopyy getAllCustomers 暂未实现');
}
async getCustomer(id: string | number): Promise<UnifiedCustomerDTO> {
const customer = await this.shopyyService.getCustomer(this.site, id);
return this.mapCustomer(customer);

View File

@ -1,5 +1,4 @@
import { ISiteAdapter } from '../interface/site-adapter.interface';
import { IPlatformService } from '../interface/platform.interface';
import {
UnifiedMediaDTO,
UnifiedOrderDTO,
@ -26,10 +25,11 @@ import {
WooProductSearchParams,
} from '../dto/woocommerce.dto';
import { Site } from '../entity/site.entity';
import { WPService } from '../service/wp.service';
export class WooCommerceAdapter implements ISiteAdapter {
// 构造函数接收站点配置与服务实例
constructor(private site: Site, private wpService: IPlatformService) {
constructor(private site: Site, private wpService: WPService) {
this.mapProduct = this.mapProduct.bind(this);
this.mapReview = this.mapReview.bind(this);
this.mapCustomer = this.mapCustomer.bind(this);
@ -71,6 +71,17 @@ export class WooCommerceAdapter implements ISiteAdapter {
}
}
// 获取所有webhooks
async getAllWebhooks(params?: UnifiedSearchParamsDTO): Promise<UnifiedWebhookDTO[]> {
try {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const webhooks = await this.wpService.sdkGetAll(api, 'webhooks', params);
return webhooks.map((webhook: any) => this.mapWebhook(webhook));
} catch (error) {
throw new Error(`Failed to get all webhooks: ${error instanceof Error ? error.message : String(error)}`);
}
}
// 获取单个 webhook 详情
async getWebhook(id: string | number): Promise<UnifiedWebhookDTO> {
try {
@ -466,6 +477,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
};
}
async getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]> {
// 使用sdkGetAll获取所有产品数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const products = await this.wpService.sdkGetAll(api, 'products', params);
return products.map((product: any) => this.mapProduct(product));
}
async getProduct(id: string | number): Promise<UnifiedProductDTO> {
// 获取单个产品详情并映射为统一产品DTO
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
@ -546,6 +564,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
return this.mapOrder(res.data);
}
async getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]> {
// 使用sdkGetAll获取所有订单数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const orders = await this.wpService.sdkGetAll(api, 'orders', params);
return orders.map((order: any) => this.mapOrder(order));
}
async createOrder(data: Partial<UnifiedOrderDTO>): Promise<UnifiedOrderDTO> {
// 创建订单并返回统一订单DTO
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
@ -649,6 +674,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
};
}
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
// 使用sdkGetAll获取所有订阅数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const subscriptions = await this.wpService.sdkGetAll(api, 'subscriptions', params);
return subscriptions.map((subscription: any) => this.mapSubscription(subscription));
}
async getMedia(
params: UnifiedSearchParamsDTO
): Promise<UnifiedPaginationDTO<UnifiedMediaDTO>> {
@ -666,6 +698,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
};
}
async getAllMedia(params?: UnifiedSearchParamsDTO): Promise<UnifiedMediaDTO[]> {
// 使用sdkGetAll获取所有媒体数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const media = await this.wpService.sdkGetAll(api, 'media', params);
return media.map((mediaItem: any) => this.mapMedia(mediaItem));
}
private mapReview(item: any): UnifiedReviewDTO & {raw: any} {
// 将 WooCommerce 评论数据映射为统一评论DTO
return {
@ -701,6 +740,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
};
}
async getAllReviews(params?: UnifiedSearchParamsDTO): Promise<UnifiedReviewDTO[]> {
// 使用sdkGetAll获取所有评论数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const reviews = await this.wpService.sdkGetAll(api, 'products/reviews', params);
return reviews.map((review: any) => this.mapReview(review));
}
async createReview(data: any): Promise<UnifiedReviewDTO> {
const res = await this.wpService.createReview(this.site, data);
return this.mapReview(res);
@ -769,6 +815,13 @@ export class WooCommerceAdapter implements ISiteAdapter {
};
}
async getAllCustomers(params?: UnifiedSearchParamsDTO): Promise<UnifiedCustomerDTO[]> {
// 使用sdkGetAll获取所有客户数据不受分页限制
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const customers = await this.wpService.sdkGetAll(api, 'customers', params);
return customers.map((customer: any) => this.mapCustomer(customer));
}
async getCustomer(id: string | number): Promise<UnifiedCustomerDTO> {
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
const res = await api.get(`customers/${id}`);

View File

@ -22,6 +22,11 @@ export interface ISiteAdapter {
*/
getProducts(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedProductDTO>>;
/**
*
*/
getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]>;
/**
*
*/
@ -32,6 +37,11 @@ export interface ISiteAdapter {
*/
getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>>;
/**
*
*/
getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]>;
/**
*
*/
@ -42,11 +52,21 @@ export interface ISiteAdapter {
*/
getSubscriptions(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>>;
/**
*
*/
getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]>;
/**
*
*/
getMedia(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedMediaDTO>>;
/**
*
*/
getAllMedia(params?: UnifiedSearchParamsDTO): Promise<UnifiedMediaDTO[]>;
/**
*
*/
@ -57,6 +77,11 @@ export interface ISiteAdapter {
*/
getReviews(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedReviewDTO>>;
/**
*
*/
getAllReviews(params?: UnifiedSearchParamsDTO): Promise<UnifiedReviewDTO[]>;
/**
*
*/
@ -111,6 +136,7 @@ export interface ISiteAdapter {
batchProcessOrders?(data: BatchOperationDTO): Promise<BatchOperationResultDTO>;
getCustomers(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedCustomerDTO>>;
getAllCustomers(params?: UnifiedSearchParamsDTO): Promise<UnifiedCustomerDTO[]>;
getCustomer(id: string | number): Promise<UnifiedCustomerDTO>;
createCustomer(data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO>;
updateCustomer(id: string | number, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO>;
@ -123,6 +149,11 @@ export interface ISiteAdapter {
*/
getWebhooks(params: UnifiedSearchParamsDTO): Promise<UnifiedWebhookPaginationDTO>;
/**
* webhooks
*/
getAllWebhooks(params?: UnifiedSearchParamsDTO): Promise<UnifiedWebhookDTO[]>;
/**
* webhook
*/

View File

@ -171,17 +171,17 @@ export class CustomerService {
try {
// 第一步:获取适配器并从站点获取客户数据
const adapter = await this.siteApiService.getAdapter(siteId);
const siteCustomersResult = await adapter.getCustomers(params || {});
const siteCustomers = await adapter.getAllCustomers(params || {});
// 第二步:将站点客户数据转换为客户实体数据
const customersData = siteCustomersResult.items.map(siteCustomer => {
const customersData = siteCustomers.map(siteCustomer => {
return this.mapSiteCustomerToCustomer(siteCustomer, siteId);
});
// 第三步批量upsert客户数据
const upsertResult = await this.upsertManyCustomers(customersData);
return {
total: siteCustomersResult.total,
total: siteCustomers.length,
processed: upsertResult.customers.length,
synced: upsertResult.customers.length,
updated: upsertResult.updated,

View File

@ -16,12 +16,13 @@ import * as fs from 'fs';
const MAX_PAGE_SIZE = 100;
@Provide()
export class WPService implements IPlatformService {
getCustomer(site: any, id: number): Promise<any> {
throw new Error('Method not implemented.');
}
@Inject()
private readonly siteService: SiteService;
getCustomer(site: any, id: number): Promise<any> {
throw new Error('Method not implemented.');
}
/**
* URL,, / /
* 使用示例:this.buildURL(wpApiUrl, '/wp-json', 'wc/v3/products', productId)
@ -83,7 +84,7 @@ export class WPService implements IPlatformService {
* 使,
* date_created ,
*/
private async sdkGetAll<T>(api: WooCommerceRestApi, resource: string, params: Record<string, any> = {}, maxPages: number = MAX_PAGE_SIZE): Promise<T[]> {
async sdkGetAll<T>(api: WooCommerceRestApi, resource: string, params: Record<string, any> = {}, maxPages: number = MAX_PAGE_SIZE): Promise<T[]> {
return this.sdkGetAllConcurrent<T>(api, resource, params, maxPages);
}
@ -101,8 +102,7 @@ export class WPService implements IPlatformService {
): Promise<T[]> {
// 设置默认排序为 date_created 倒序,确保获取最新数据
const defaultParams = {
orderby: 'date_created',
order: 'desc',
order: 'desc', // 倒序,优先获取最新数据
per_page: MAX_PAGE_SIZE,
...params
};