From 8f7f35c538731563e532398231b2e3c5c2bd44f9 Mon Sep 17 00:00:00 2001 From: tikkhun Date: Tue, 23 Dec 2025 19:33:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(adapter):=20=E6=B7=BB=E5=8A=A0getAll?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E6=94=AF=E6=8C=81=E6=89=B9=E9=87=8F=E8=8E=B7?= =?UTF-8?q?=E5=8F=96=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现WooCommerceAdapter中的getAllProducts、getAllOrders等方法 添加ISiteAdapter接口中的对应方法定义 更新customer.service使用getAllCustomers方法 --- .gitignore | 4 +- src/adapter/shopyy.adapter.ts | 37 +++++++++++++++- src/adapter/woocommerce.adapter.ts | 57 ++++++++++++++++++++++++- src/interface/site-adapter.interface.ts | 31 ++++++++++++++ src/service/customer.service.ts | 6 +-- src/service/wp.service.ts | 12 +++--- 6 files changed, 133 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index e2c1f24..b52a73d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,6 @@ yarn.lock **/config.local.ts container scripts -ai tmp_uploads/ -.trae \ No newline at end of file +.trae +docs \ No newline at end of file diff --git a/src/adapter/shopyy.adapter.ts b/src/adapter/shopyy.adapter.ts index 2568db1..b4837a0 100644 --- a/src/adapter/shopyy.adapter.ts +++ b/src/adapter/shopyy.adapter.ts @@ -321,6 +321,11 @@ export class ShopyyAdapter implements ISiteAdapter { }; } + async getAllProducts(params?: UnifiedSearchParamsDTO): Promise { + // Shopyy getAllProducts 暂未实现 + throw new Error('Shopyy getAllProducts 暂未实现'); + } + async getProduct(id: string | number): Promise { // 使用ShopyyService获取单个产品 const product = await this.shopyyService.getProduct(this.site, id); @@ -385,6 +390,11 @@ export class ShopyyAdapter implements ISiteAdapter { }; } + async getAllOrders(params?: UnifiedSearchParamsDTO): Promise { + // Shopyy getAllOrders 暂未实现 + throw new Error('Shopyy getAllOrders 暂未实现'); + } + async getOrder(id: string | number): Promise { 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 { + // Shopyy getAllSubscriptions 暂未实现 + throw new Error('Shopyy getAllSubscriptions 暂未实现'); + } + async getMedia( params: UnifiedSearchParamsDTO ): Promise> { @@ -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 { + // Shopyy getAllMedia 暂未实现 + throw new Error('Shopyy getAllMedia 暂未实现'); + } + async createMedia(file: any): Promise { 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 { + // Shopyy getAllReviews 暂未实现 + throw new Error('Shopyy getAllReviews 暂未实现'); + } + async getReview(id: string | number): Promise { 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 { + // Shopyy getAllWebhooks 暂未实现 + throw new Error('Shopyy getAllWebhooks 暂未实现'); + } + async getWebhook(id: string | number): Promise { 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 { + // Shopyy getAllCustomers 暂未实现 + throw new Error('Shopyy getAllCustomers 暂未实现'); + } + async getCustomer(id: string | number): Promise { const customer = await this.shopyyService.getCustomer(this.site, id); return this.mapCustomer(customer); diff --git a/src/adapter/woocommerce.adapter.ts b/src/adapter/woocommerce.adapter.ts index 9b200cf..9c5260b 100644 --- a/src/adapter/woocommerce.adapter.ts +++ b/src/adapter/woocommerce.adapter.ts @@ -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 { + 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 { try { @@ -466,6 +477,13 @@ export class WooCommerceAdapter implements ISiteAdapter { }; } + async getAllProducts(params?: UnifiedSearchParamsDTO): Promise { + // 使用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 { // 获取单个产品详情并映射为统一产品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 { + // 使用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): Promise { // 创建订单并返回统一订单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 { + // 使用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> { @@ -666,6 +698,13 @@ export class WooCommerceAdapter implements ISiteAdapter { }; } + async getAllMedia(params?: UnifiedSearchParamsDTO): Promise { + // 使用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 { + // 使用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 { 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 { + // 使用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 { const api = (this.wpService as any).createApi(this.site, 'wc/v3'); const res = await api.get(`customers/${id}`); diff --git a/src/interface/site-adapter.interface.ts b/src/interface/site-adapter.interface.ts index 0ae0179..b480ea6 100644 --- a/src/interface/site-adapter.interface.ts +++ b/src/interface/site-adapter.interface.ts @@ -22,6 +22,11 @@ export interface ISiteAdapter { */ getProducts(params: UnifiedSearchParamsDTO): Promise>; + /** + * 获取所有产品 + */ + getAllProducts(params?: UnifiedSearchParamsDTO): Promise; + /** * 获取单个产品 */ @@ -32,6 +37,11 @@ export interface ISiteAdapter { */ getOrders(params: UnifiedSearchParamsDTO): Promise>; + /** + * 获取所有订单 + */ + getAllOrders(params?: UnifiedSearchParamsDTO): Promise; + /** * 获取单个订单 */ @@ -42,11 +52,21 @@ export interface ISiteAdapter { */ getSubscriptions(params: UnifiedSearchParamsDTO): Promise>; + /** + * 获取所有订阅 + */ + getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise; + /** * 获取媒体列表 */ getMedia(params: UnifiedSearchParamsDTO): Promise>; + /** + * 获取所有媒体 + */ + getAllMedia(params?: UnifiedSearchParamsDTO): Promise; + /** * 创建媒体 */ @@ -57,6 +77,11 @@ export interface ISiteAdapter { */ getReviews(params: UnifiedSearchParamsDTO): Promise>; + /** + * 获取所有评论 + */ + getAllReviews(params?: UnifiedSearchParamsDTO): Promise; + /** * 创建评论 */ @@ -111,6 +136,7 @@ export interface ISiteAdapter { batchProcessOrders?(data: BatchOperationDTO): Promise; getCustomers(params: UnifiedSearchParamsDTO): Promise>; + getAllCustomers(params?: UnifiedSearchParamsDTO): Promise; getCustomer(id: string | number): Promise; createCustomer(data: Partial): Promise; updateCustomer(id: string | number, data: Partial): Promise; @@ -123,6 +149,11 @@ export interface ISiteAdapter { */ getWebhooks(params: UnifiedSearchParamsDTO): Promise; + /** + * 获取所有webhooks + */ + getAllWebhooks(params?: UnifiedSearchParamsDTO): Promise; + /** * 获取单个webhook */ diff --git a/src/service/customer.service.ts b/src/service/customer.service.ts index 76bb4fb..7d28467 100644 --- a/src/service/customer.service.ts +++ b/src/service/customer.service.ts @@ -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, diff --git a/src/service/wp.service.ts b/src/service/wp.service.ts index 0c22b58..f3e35b7 100644 --- a/src/service/wp.service.ts +++ b/src/service/wp.service.ts @@ -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 { - throw new Error('Method not implemented.'); - } + @Inject() private readonly siteService: SiteService; + getCustomer(site: any, id: number): Promise { + 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(api: WooCommerceRestApi, resource: string, params: Record = {}, maxPages: number = MAX_PAGE_SIZE): Promise { + async sdkGetAll(api: WooCommerceRestApi, resource: string, params: Record = {}, maxPages: number = MAX_PAGE_SIZE): Promise { return this.sdkGetAllConcurrent(api, resource, params, maxPages); } @@ -101,8 +102,7 @@ export class WPService implements IPlatformService { ): Promise { // 设置默认排序为 date_created 倒序,确保获取最新数据 const defaultParams = { - orderby: 'date_created', - order: 'desc', + order: 'desc', // 倒序,优先获取最新数据 per_page: MAX_PAGE_SIZE, ...params };