From 0f81499ccc0db09f754b76dc15519d99e09bb89c Mon Sep 17 00:00:00 2001 From: tikkhun Date: Wed, 7 Jan 2026 20:33:23 +0800 Subject: [PATCH] =?UTF-8?q?refactor(api):=20=E7=BB=9F=E4=B8=80=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=8F=82=E6=95=B0=E4=B8=BA=E5=AF=B9=E8=B1=A1=E5=BD=A2?= =?UTF-8?q?=E5=BC=8F=E5=B9=B6=E6=94=AF=E6=8C=81=E5=A4=9A=E6=9D=A1=E4=BB=B6?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重构所有接口方法,将直接传递id参数改为接受where条件对象 支持通过id、sku、email等多条件查询实体 优化产品服务逻辑,支持通过sku直接查询产品 统一各适配器实现,确保接口一致性 --- src/adapter/shopyy.adapter.ts | 140 ++++++++++------ src/adapter/woocommerce.adapter.ts | 213 ++++++++++++------------ src/controller/site-api.controller.ts | 42 ++--- src/interface/site-adapter.interface.ts | 34 ++-- src/service/order.service.ts | 2 +- src/service/site-api.service.ts | 28 +--- src/service/wp.service.ts | 8 +- 7 files changed, 248 insertions(+), 219 deletions(-) diff --git a/src/adapter/shopyy.adapter.ts b/src/adapter/shopyy.adapter.ts index 12c85e6..44766e3 100644 --- a/src/adapter/shopyy.adapter.ts +++ b/src/adapter/shopyy.adapter.ts @@ -122,8 +122,11 @@ export class ShopyyAdapter implements ISiteAdapter { return data } - async getCustomer(id: string | number): Promise { - const customer = await this.shopyyService.getCustomer(this.site, id); + async getCustomer(where: {id?: string | number,email?: string,phone?: string}): Promise { + if(!where.id && !where.email && !where.phone){ + throw new Error('必须传入 id 或 email 或 phone') + } + const customer = await this.shopyyService.getCustomer(this.site, where.id); return this.mapPlatformToUnifiedCustomer(customer); } @@ -149,13 +152,13 @@ export class ShopyyAdapter implements ISiteAdapter { return this.mapPlatformToUnifiedCustomer(createdCustomer); } - async updateCustomer(id: string | number, data: Partial): Promise { - const updatedCustomer = await this.shopyyService.updateCustomer(this.site, id, data); + async updateCustomer(where: {id: string | number}, data: Partial): Promise { + const updatedCustomer = await this.shopyyService.updateCustomer(this.site, where.id, data); return this.mapPlatformToUnifiedCustomer(updatedCustomer); } - async deleteCustomer(id: string | number): Promise { - return await this.shopyyService.deleteCustomer(this.site, id); + async deleteCustomer(where: {id: string | number}): Promise { + return await this.shopyyService.deleteCustomer(this.site, where.id); } batchProcessCustomers?(data: BatchOperationDTO): Promise { @@ -208,13 +211,13 @@ export class ShopyyAdapter implements ISiteAdapter { return this.mapPlatformToUnifiedMedia(createdMedia); } - async updateMedia(id: string | number, data: any): Promise { - const updatedMedia = await this.shopyyService.updateMedia(this.site, id, data); + async updateMedia(where: {id: string | number}, data: any): Promise { + const updatedMedia = await this.shopyyService.updateMedia(this.site, where.id, data); return this.mapPlatformToUnifiedMedia(updatedMedia); } - async deleteMedia(id: string | number): Promise { - return await this.shopyyService.deleteMedia(this.site, id); + async deleteMedia(where: {id: string | number}): Promise { + return await this.shopyyService.deleteMedia(this.site, where.id); } mapMediaSearchParams(params: UnifiedSearchParamsDTO): any { @@ -530,8 +533,8 @@ export class ShopyyAdapter implements ISiteAdapter { return params; } - async getOrder(id: string | number): Promise { - const data = await this.shopyyService.getOrder(this.site.id, String(id)); + async getOrder(where: {id: string | number}): Promise { + const data = await this.shopyyService.getOrder(this.site.id, String(where.id)); return this.mapPlatformToUnifiedOrder(data); } @@ -577,14 +580,14 @@ export class ShopyyAdapter implements ISiteAdapter { return this.mapPlatformToUnifiedOrder(createdOrder); } - async updateOrder(id: string | number, data: Partial): Promise { + async updateOrder(where: {id: string | number}, data: Partial): Promise { // 使用映射方法转换参数 const requestParams = this.mapUpdateOrderParams(data); - return await this.shopyyService.updateOrder(this.site, String(id), requestParams); + return await this.shopyyService.updateOrder(this.site, String(where.id), requestParams); } - async deleteOrder(id: string | number): Promise { - return await this.shopyyService.deleteOrder(this.site, id); + async deleteOrder(where: {id: string | number}): Promise { + return await this.shopyyService.deleteOrder(this.site, where.id); } async getOrderNotes(orderId: string | number): Promise { @@ -858,10 +861,18 @@ export class ShopyyAdapter implements ISiteAdapter { return params; } - async getProduct(id: string | number): Promise { - // 使用ShopyyService获取单个产品 - const product = await this.shopyyService.getProduct(this.site, id); - return this.mapPlatformToUnifiedProduct(product); + async getProduct(where: {id?: string | number, sku?: string}): Promise { + if(!where.id && !where.sku){ + throw new Error('必须传入 id 或 sku') + } + if (where.id) { + // 使用ShopyyService获取单个产品 + const product = await this.shopyyService.getProduct(this.site, where.id); + return this.mapPlatformToUnifiedProduct(product); + } else if (where.sku) { + // 通过sku获取产品 + return this.getProductBySku(where.sku); + } } async getProducts( @@ -900,24 +911,50 @@ export class ShopyyAdapter implements ISiteAdapter { return this.mapPlatformToUnifiedProduct(res); } - async updateProduct(id: string | number, data: Partial): Promise { - // Shopyy update returns boolean? - // shopyyService.updateProduct returns boolean. - // So I can't return the updated product. - // I have to fetch it again or return empty/input. - // Since getProduct is missing, I'll return input data as UnifiedProductDTO (mock). + async updateProduct(where: {id?: string | number, sku?: string}, data: Partial): Promise { + let productId: string; + if (where.id) { + productId = String(where.id); + } else if (where.sku) { + // 通过sku获取产品ID + const product = await this.getProductBySku(where.sku); + productId = String(product.id); + } else { + throw new Error('必须提供id或sku参数'); + } // 使用映射方法转换参数 const requestParams = this.mapUpdateProductParams(data); - await this.shopyyService.updateProduct(this.site, String(id), requestParams); + await this.shopyyService.updateProduct(this.site, productId, requestParams); return true; } - async deleteProduct(id: string | number): Promise { + async deleteProduct(where: {id?: string | number, sku?: string}): Promise { + let productId: string | number; + if (where.id) { + productId = where.id; + } else if (where.sku) { + // 通过sku获取产品ID + const product = await this.getProductBySku(where.sku); + productId = product.id; + } else { + throw new Error('必须提供id或sku参数'); + } // Use batch delete - await this.shopyyService.batchProcessProducts(this.site, { delete: [id] }); + await this.shopyyService.batchProcessProducts(this.site, { delete: [productId] }); return true; } + // 通过sku获取产品详情的私有方法 + private async getProductBySku(sku: string): Promise { + // 使用Shopyy API的搜索功能通过sku查询产品 + const response = await this.shopyyService.getProducts(this.site, 1, 100); + const product = response.items.find((item: any) => item.sku === sku); + if (!product) { + throw new Error(`未找到sku为${sku}的产品`); + } + return this.mapPlatformToUnifiedProduct(product); + } + async batchProcessProducts( data: { create?: any[]; update?: any[]; delete?: Array } ): Promise { @@ -929,9 +966,6 @@ export class ShopyyAdapter implements ISiteAdapter { } // ========== 评论映射方法 ========== - mapPlatformToUnifiedReview(data: any): UnifiedReviewDTO { - return data - } mapUnifiedToPlatformReview(data: Partial) { return data @@ -954,7 +988,7 @@ export class ShopyyAdapter implements ISiteAdapter { requestParams ); return { - items: items.map(this.mapReview), + items: items.map(this.mapPlatformToUnifiedReview), total, totalPages, page, @@ -969,19 +1003,19 @@ export class ShopyyAdapter implements ISiteAdapter { async createReview(data: any): Promise { const createdReview = await this.shopyyService.createReview(this.site, data); - return this.mapReview(createdReview); + return this.mapPlatformToUnifiedReview(createdReview); } - async updateReview(id: string | number, data: any): Promise { - const updatedReview = await this.shopyyService.updateReview(this.site, id, data); - return this.mapReview(updatedReview); + async updateReview(where: {id: string | number}, data: any): Promise { + const updatedReview = await this.shopyyService.updateReview(this.site, where.id, data); + return this.mapPlatformToUnifiedReview(updatedReview); } - async deleteReview(id: string | number): Promise { - return await this.shopyyService.deleteReview(this.site, id); + async deleteReview(where: {id: string | number}): Promise { + return await this.shopyyService.deleteReview(this.site, where.id); } - mapReview(review: any): UnifiedReviewDTO { + mapPlatformToUnifiedReview(review: any): UnifiedReviewDTO { // 将ShopYY评论数据映射到统一评论DTO格式 return { id: review.id || review.review_id, @@ -1120,9 +1154,7 @@ export class ShopyyAdapter implements ISiteAdapter { } // ========== Webhook映射方法 ========== - mapPlatformToUnifiedWebhook(data: any): UnifiedWebhookDTO { - return data - } + mapUnifiedToPlatformWebhook(data: Partial) { return data @@ -1136,15 +1168,15 @@ export class ShopyyAdapter implements ISiteAdapter { return data } - async getWebhook(id: string | number): Promise { - const webhook = await this.shopyyService.getWebhook(this.site, id); - return this.mapWebhook(webhook); + async getWebhook(where: {id: string | number}): Promise { + const webhook = await this.shopyyService.getWebhook(this.site, where.id); + return this.mapPlatformToUnifiedWebhook(webhook); } async getWebhooks(params: UnifiedSearchParamsDTO): Promise { const { items, total, totalPages, page, per_page } = await this.shopyyService.getWebhooks(this.site, params); return { - items: items.map(this.mapWebhook), + items: items.map(this.mapPlatformToUnifiedWebhook), total, totalPages, page, @@ -1159,19 +1191,19 @@ export class ShopyyAdapter implements ISiteAdapter { async createWebhook(data: CreateWebhookDTO): Promise { const createdWebhook = await this.shopyyService.createWebhook(this.site, data); - return this.mapWebhook(createdWebhook); + return this.mapPlatformToUnifiedWebhook(createdWebhook); } - async updateWebhook(id: string | number, data: UpdateWebhookDTO): Promise { - const updatedWebhook = await this.shopyyService.updateWebhook(this.site, id, data); - return this.mapWebhook(updatedWebhook); + async updateWebhook(where: {id: string | number}, data: UpdateWebhookDTO): Promise { + const updatedWebhook = await this.shopyyService.updateWebhook(this.site, where.id, data); + return this.mapPlatformToUnifiedWebhook(updatedWebhook); } - async deleteWebhook(id: string | number): Promise { - return await this.shopyyService.deleteWebhook(this.site, id); + async deleteWebhook(where: {id: string | number}): Promise { + return await this.shopyyService.deleteWebhook(this.site, where.id); } - mapWebhook(item: ShopyyWebhook): UnifiedWebhookDTO { + mapPlatformToUnifiedWebhook(item: ShopyyWebhook): UnifiedWebhookDTO { return { id: item.id, name: item.webhook_name || `Webhook-${item.id}`, diff --git a/src/adapter/woocommerce.adapter.ts b/src/adapter/woocommerce.adapter.ts index 1e1ade7..95e8567 100644 --- a/src/adapter/woocommerce.adapter.ts +++ b/src/adapter/woocommerce.adapter.ts @@ -36,12 +36,15 @@ import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto'; export class WooCommerceAdapter implements ISiteAdapter { // 构造函数接收站点配置与服务实例 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); - this.mapMedia = this.mapMedia.bind(this); - this.mapOrder = this.mapOrder.bind(this); - this.mapWebhook = this.mapWebhook.bind(this); + this.mapPlatformToUnifiedProduct = this.mapPlatformToUnifiedProduct.bind(this); + this.mapPlatformToUnifiedReview = this.mapPlatformToUnifiedReview.bind(this); + this.mapPlatformToUnifiedCustomer = this.mapPlatformToUnifiedCustomer.bind(this); + this.mapPlatformToUnifiedMedia = this.mapPlatformToUnifiedMedia.bind(this); + this.mapPlatformToUnifiedOrder = this.mapPlatformToUnifiedOrder.bind(this); + this.mapPlatformToUnifiedWebhook = this.mapPlatformToUnifiedWebhook.bind(this); + } + mapUnifiedToPlatformCustomer(data: Partial) { + return data } batchProcessProducts?(data: BatchOperationDTO): Promise { throw new Error('Method not implemented.'); @@ -54,14 +57,8 @@ export class WooCommerceAdapter implements ISiteAdapter { } // ========== 客户映射方法 ========== - mapPlatformToUnifiedCustomer(data: any): UnifiedCustomerDTO { - return data; - } - mapUnifiedToPlatformCustomer(data: Partial) { - return data; - } - mapCustomer(item: WooCustomer): UnifiedCustomerDTO { + mapPlatformToUnifiedCustomer(item: WooCustomer): UnifiedCustomerDTO { // 将 WooCommerce 客户数据映射为统一客户DTO // 包含基础信息地址信息与时间信息 return { @@ -136,10 +133,10 @@ export class WooCommerceAdapter implements ISiteAdapter { } // 客户操作方法 - async getCustomer(id: string | number): Promise { + async getCustomer(where: {id: string | number}): Promise { const api = (this.wpService as any).createApi(this.site, 'wc/v3'); - const res = await api.get(`customers/${id}`); - return this.mapCustomer(res.data); + const res = await api.get(`customers/${where.id}`); + return this.mapPlatformToUnifiedCustomer(res.data); } async getCustomers(params: UnifiedSearchParamsDTO): Promise> { @@ -150,7 +147,7 @@ export class WooCommerceAdapter implements ISiteAdapter { requestParams ); return { - items: items.map((i: any) => this.mapCustomer(i)), + items: items.map((i: any) => this.mapPlatformToUnifiedCustomer(i)), total, totalPages, page, @@ -167,36 +164,33 @@ export class WooCommerceAdapter implements ISiteAdapter { const requestParams = this.mapCustomerSearchParams(params || {}); const customers = await this.wpService.sdkGetAll(api, 'customers', requestParams); - return customers.map((customer: any) => this.mapCustomer(customer)); + return customers.map((customer: any) => this.mapPlatformToUnifiedCustomer(customer)); } async createCustomer(data: Partial): Promise { const api = (this.wpService as any).createApi(this.site, 'wc/v3'); const res = await api.post('customers', data); - return this.mapCustomer(res.data); + return this.mapPlatformToUnifiedCustomer(res.data); } - async updateCustomer(id: string | number, data: Partial): Promise { + async updateCustomer(where: {id: string | number}, data: Partial): Promise { const api = (this.wpService as any).createApi(this.site, 'wc/v3'); - const res = await api.put(`customers/${id}`, data); - return this.mapCustomer(res.data); + const res = await api.put(`customers/${where.id}`, data); + return this.mapPlatformToUnifiedCustomer(res.data); } - async deleteCustomer(id: string | number): Promise { + async deleteCustomer(where: {id: string | number}): Promise { const api = (this.wpService as any).createApi(this.site, 'wc/v3'); - await api.delete(`customers/${id}`, { force: true }); + await api.delete(`customers/${where.id}`, { force: true }); return true; } // ========== 媒体映射方法 ========== - mapPlatformToUnifiedMedia(data: any): UnifiedMediaDTO { - return data; - } mapUnifiedToPlatformMedia(data: Partial) { return data; } - mapMedia(item: WpMedia): UnifiedMediaDTO { + mapPlatformToUnifiedMedia(item: WpMedia): UnifiedMediaDTO { // 将 WordPress 媒体数据映射为统一媒体DTO // 兼容不同字段命名的时间信息 return { @@ -221,7 +215,7 @@ export class WooCommerceAdapter implements ISiteAdapter { params ); return { - items: items.map(this.mapMedia.bind(this)), + items: items.map(this.mapPlatformToUnifiedMedia.bind(this)), total, totalPages, page, @@ -233,21 +227,21 @@ export class WooCommerceAdapter implements ISiteAdapter { // 使用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)); + return media.map((mediaItem: any) => this.mapPlatformToUnifiedMedia(mediaItem)); } createMedia(file: any): Promise { throw new Error('Method not implemented.'); } - async updateMedia(id: string | number, data: any): Promise { + async updateMedia(where: {id: string | number}, data: any): Promise { // 更新媒体信息 - return await this.wpService.updateMedia(Number(this.site.id), Number(id), data); + return await this.wpService.updateMedia(Number(this.site.id), Number(where.id), data); } - async deleteMedia(id: string | number): Promise { + async deleteMedia(where: {id: string | number}): Promise { // 删除媒体资源 - await this.wpService.deleteMedia(Number(this.site.id), Number(id), true); + await this.wpService.deleteMedia(Number(this.site.id), Number(where.id), true); return true; } @@ -258,9 +252,6 @@ export class WooCommerceAdapter implements ISiteAdapter { } // ========== 订单映射方法 ========== - mapPlatformToUnifiedOrder(data: any): UnifiedOrderDTO { - return data; - } mapUnifiedToPlatformOrder(data: Partial) { return data; } @@ -357,7 +348,7 @@ export class WooCommerceAdapter implements ISiteAdapter { ].filter(Boolean).join(', '); } - mapOrder(item: WooOrder): UnifiedOrderDTO { + mapPlatformToUnifiedOrder(item: WooOrder): UnifiedOrderDTO { // 将 WooCommerce 订单数据映射为统一订单DTO // 包含账单地址与收货地址以及创建与更新时间 @@ -411,11 +402,11 @@ export class WooCommerceAdapter implements ISiteAdapter { } // 订单操作方法 - async getOrder(id: string | number): Promise { + async getOrder(where: {id: string | number}): Promise { // 获取单个订单详情 const api = (this.wpService as any).createApi(this.site, 'wc/v3'); - const res = await api.get(`orders/${id}`); - return this.mapOrder(res.data); + const res = await api.get(`orders/${where.id}`); + return this.mapPlatformToUnifiedOrder(res.data); } async getOrders(params: UnifiedSearchParamsDTO): Promise> { @@ -445,7 +436,7 @@ export class WooCommerceAdapter implements ISiteAdapter { ); return { - items: ordersWithFulfillments.map(this.mapOrder), + items: ordersWithFulfillments.map(this.mapPlatformToUnifiedOrder), total, totalPages, page, @@ -457,7 +448,7 @@ export class WooCommerceAdapter implements ISiteAdapter { // 使用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)); + return orders.map((order: any) => this.mapPlatformToUnifiedOrder(order)); } async countOrders(where: Record): Promise { @@ -476,18 +467,18 @@ export class WooCommerceAdapter implements ISiteAdapter { // 创建订单并返回统一订单DTO const api = (this.wpService as any).createApi(this.site, 'wc/v3'); const res = await api.post('orders', data); - return this.mapOrder(res.data); + return this.mapPlatformToUnifiedOrder(res.data); } - async updateOrder(id: string | number, data: Partial): Promise { + async updateOrder(where: {id: string | number}, data: Partial): Promise { // 更新订单并返回布尔结果 - return await this.wpService.updateOrder(this.site, String(id), data as any); + return await this.wpService.updateOrder(this.site, String(where.id), data as any); } - async deleteOrder(id: string | number): Promise { + async deleteOrder(where: {id: string | number}): Promise { // 删除订单 const api = (this.wpService as any).createApi(this.site, 'wc/v3'); - await api.delete(`orders/${id}`, { force: true }); + await api.delete(`orders/${where.id}`, { force: true }); return true; } @@ -592,9 +583,6 @@ export class WooCommerceAdapter implements ISiteAdapter { } // ========== 产品映射方法 ========== - mapPlatformToUnifiedProduct(data: any): UnifiedProductDTO { - return data; - } mapUnifiedToPlatformProduct(data: Partial) { return data; } @@ -662,8 +650,7 @@ export class WooCommerceAdapter implements ISiteAdapter { return mapped; } - mapProduct(item: WooProduct): UnifiedProductDTO { - mapProduct(item: WooProduct): UnifiedProductDTO { + mapPlatformToUnifiedProduct(item: WooProduct): UnifiedProductDTO { // 将 WooCommerce 产品数据映射为统一产品DTO // 保留常用字段与时间信息以便前端统一展示 // https://woocommerce.github.io/woocommerce-rest-api-docs/?javascript#product-properties @@ -751,11 +738,22 @@ export class WooCommerceAdapter implements ISiteAdapter { raw: item, }; } - + async getProduct({id, sku}: {id?: string, sku?:string}){ + if(id) return this.getProductById(id); + if(sku) return this.getProductBySku(sku) + return this.getProductById(id || sku || ''); + } + async getProductBySku(sku: string){ + const api = (this.wpService as any).createApi(this.site, 'wc/v3'); + const res = await api.get(`products?sku=${sku}`); + const product = res.data[0]; + return this.mapPlatformToUnifiedProduct(product); + } // 产品操作方法 - async getProduct(id: string | number): Promise { + async getProductById(id: string | number): Promise { // 获取单个产品详情并映射为统一产品DTO const api = (this.wpService as any).createApi(this.site, 'wc/v3'); + const res = await api.get(`products/${id}`); const product = res.data; @@ -775,7 +773,7 @@ export class WooCommerceAdapter implements ISiteAdapter { } } - return this.mapProduct(product); + return this.mapPlatformToUnifiedProduct(product); } async getProducts(params: UnifiedSearchParamsDTO): Promise> { @@ -810,7 +808,7 @@ export class WooCommerceAdapter implements ISiteAdapter { ); return { - items: productsWithVariations.map(this.mapProduct), + items: productsWithVariations.map(this.mapPlatformToUnifiedProduct), total, totalPages, page, @@ -846,26 +844,46 @@ export class WooCommerceAdapter implements ISiteAdapter { }) ); - return productsWithVariations.map((product: any) => this.mapProduct(product)); + return productsWithVariations.map((product: any) => this.mapPlatformToUnifiedProduct(product)); } async createProduct(data: Partial): Promise { // 创建产品并返回统一产品DTO const res = await this.wpService.createProduct(this.site, data); - return this.mapProduct(res); + return this.mapPlatformToUnifiedProduct(res); } - async updateProduct(id: string | number, data: Partial): Promise { + async updateProduct(where: {id?: string | number, sku?: string}, data: Partial): Promise { // 更新产品并返回统一产品DTO - const res = await this.wpService.updateProduct(this.site, String(id), data as any); + let productId: string; + if (where.id) { + productId = String(where.id); + } else if (where.sku) { + // 通过sku获取产品ID + const product = await this.getProductBySku(where.sku); + productId = String(product.id); + } else { + throw new Error('必须提供id或sku参数'); + } + const res = await this.wpService.updateProduct(this.site, productId, data as any); return res; } - async deleteProduct(id: string | number): Promise { + async deleteProduct(where: {id?: string | number, sku?: string}): Promise { // 删除产品 + let productId: string; + if (where.id) { + productId = String(where.id); + } else if (where.sku) { + // 通过sku获取产品ID + const product = await this.getProductBySku(where.sku); + productId = String(product.id); + } else { + throw new Error('必须提供id或sku参数'); + } const api = (this.wpService as any).createApi(this.site, 'wc/v3'); try { - await api.delete(`products/${id}`, { force: true }); + await api.delete(`products/${productId}`, { force: true }); return true; } catch (e) { return false; @@ -873,9 +891,7 @@ export class WooCommerceAdapter implements ISiteAdapter { } // ========== 评论映射方法 ========== - mapPlatformToUnifiedReview(data: any): UnifiedReviewDTO { - return data; - } + mapUnifiedToPlatformReview(data: Partial) { return data; } @@ -887,8 +903,7 @@ export class WooCommerceAdapter implements ISiteAdapter { return data; } - mapReview(item: any): UnifiedReviewDTO & { raw: any } { - mapReview(item: any): UnifiedReviewDTO & { raw: any } { + mapPlatformToUnifiedReview(item: any): UnifiedReviewDTO & { raw: any } { // 将 WooCommerce 评论数据映射为统一评论DTO return { id: item.id, @@ -913,7 +928,7 @@ export class WooCommerceAdapter implements ISiteAdapter { requestParams ); return { - items: items.map(this.mapReview.bind(this)), + items: items.map(this.mapPlatformToUnifiedReview.bind(this)), total, totalPages, page, @@ -925,32 +940,29 @@ export class WooCommerceAdapter implements ISiteAdapter { // 使用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)); + return reviews.map((review: any) => this.mapPlatformToUnifiedReview(review)); } async createReview(data: any): Promise { const res = await this.wpService.createReview(this.site, data); - return this.mapReview(res); + return this.mapPlatformToUnifiedReview(res); } - async updateReview(id: number, data: any): Promise { - const res = await this.wpService.updateReview(this.site, id, data); - return this.mapReview(res); + async updateReview(where: {id: number}, data: any): Promise { + const res = await this.wpService.updateReview(this.site, where.id, data); + return this.mapPlatformToUnifiedReview(res); } - async deleteReview(id: number): Promise { - return await this.wpService.deleteReview(this.site, id); + async deleteReview(where: {id: number}): Promise { + return await this.wpService.deleteReview(this.site, where.id); } // ========== 订阅映射方法 ========== - mapPlatformToUnifiedSubscription(data: any): UnifiedSubscriptionDTO { - return data; - } mapUnifiedToPlatformSubscription(data: Partial) { return data; } - mapSubscription(item: WooSubscription): UnifiedSubscriptionDTO { + mapPlatformToUnifiedSubscription(item: WooSubscription): UnifiedSubscriptionDTO { // 将 WooCommerce 订阅数据映射为统一订阅DTO // 若缺少创建时间则回退为开始时间 return { @@ -977,7 +989,7 @@ export class WooCommerceAdapter implements ISiteAdapter { params ); return { - items: items.map(this.mapSubscription), + items: items.map(this.mapPlatformToUnifiedSubscription), total, totalPages, page, @@ -990,7 +1002,7 @@ export class WooCommerceAdapter implements ISiteAdapter { // 使用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)); + return subscriptions.map((subscription: any) => this.mapPlatformToUnifiedSubscription(subscription)); } // ========== 变体映射方法 ========== @@ -1229,9 +1241,6 @@ export class WooCommerceAdapter implements ISiteAdapter { } // ========== 网络钩子映射方法 ========== - mapPlatformToUnifiedWebhook(data: any): UnifiedWebhookDTO { - return data; - } mapUnifiedToPlatformWebhook(data: Partial) { return data; } @@ -1244,7 +1253,7 @@ export class WooCommerceAdapter implements ISiteAdapter { } // 映射 WooCommerce webhook 到统一格式 - mapWebhook(webhook: WooWebhook): UnifiedWebhookDTO { + mapPlatformToUnifiedWebhook(webhook: WooWebhook): UnifiedWebhookDTO { return { id: webhook.id.toString(), name: webhook.name, @@ -1266,12 +1275,12 @@ export class WooCommerceAdapter implements ISiteAdapter { const result = await this.wpService.getWebhooks(this.site, params); return { - items: (result.items as WooWebhook[]).map(this.mapWebhook), - total: result.total, - page: Number(params.page || 1), - per_page: Number(params.per_page || 20), - totalPages: result.totalPages, - }; + items: (result.items as WooWebhook[]).map(this.mapPlatformToUnifiedWebhook), + total: result.total, + page: Number(params.page || 1), + per_page: Number(params.per_page || 20), + totalPages: result.totalPages, + }; } catch (error) { throw new Error(`Failed to get webhooks: ${error instanceof Error ? error.message : String(error)}`); } @@ -1282,17 +1291,17 @@ export class WooCommerceAdapter implements ISiteAdapter { 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)); + return webhooks.map((webhook: any) => this.mapPlatformToUnifiedWebhook(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 { + async getWebhook(where: {id: string | number}): Promise { try { - const result = await this.wpService.getWebhook(this.site, id); - return this.mapWebhook(result as WooWebhook); + const result = await this.wpService.getWebhook(this.site, where.id); + return this.mapPlatformToUnifiedWebhook(result as WooWebhook); } catch (error) { throw new Error(`Failed to get webhook: ${error instanceof Error ? error.message : String(error)}`); } @@ -1310,14 +1319,14 @@ export class WooCommerceAdapter implements ISiteAdapter { api_version: data.api_version || 'wp/v2', }; const result = await this.wpService.createWebhook(this.site, params); - return this.mapWebhook(result as WooWebhook); + return this.mapPlatformToUnifiedWebhook(result as WooWebhook); } catch (error) { throw new Error(`Failed to create webhook: ${error instanceof Error ? error.message : String(error)}`); } } // 更新现有的 webhook - async updateWebhook(id: string | number, data: UpdateWebhookDTO): Promise { + async updateWebhook(where: Partial>, data: UpdateWebhookDTO): Promise { try { const params = { ...(data.name ? { name: data.name } : {}), @@ -1327,17 +1336,17 @@ export class WooCommerceAdapter implements ISiteAdapter { ...(data.secret ? { secret: data.secret } : {}), ...(data.api_version ? { api_version: data.api_version } : {}), }; - const result = await this.wpService.updateWebhook(this.site, id, params); - return this.mapWebhook(result as WooWebhook); + const result = await this.wpService.updateWebhook(this.site, where.id, params); + return this.mapPlatformToUnifiedWebhook(result as WooWebhook); } catch (error) { throw new Error(`Failed to update webhook: ${error instanceof Error ? error.message : String(error)}`); } } // 删除指定的 webhook - async deleteWebhook(id: string | number): Promise { + async deleteWebhook(where: Partial>): Promise { try { - await this.wpService.deleteWebhook(this.site, id); + await this.wpService.deleteWebhook(this.site, where.id); return true; } catch (error) { throw new Error(`Failed to delete webhook: ${error instanceof Error ? error.message : String(error)}`); diff --git a/src/controller/site-api.controller.ts b/src/controller/site-api.controller.ts index f4b1c83..00d8285 100644 --- a/src/controller/site-api.controller.ts +++ b/src/controller/site-api.controller.ts @@ -105,7 +105,7 @@ export class SiteApiController { this.logger.debug(`[Site API] 更新评论开始, siteId: ${siteId}, id: ${id}, body: ${JSON.stringify(body)}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.updateReview(id, body); + const data = await adapter.updateReview({ id }, body); this.logger.debug(`[Site API] 更新评论成功, siteId: ${siteId}, id: ${id}`); return successResponse(data); } catch (error) { @@ -123,7 +123,7 @@ export class SiteApiController { this.logger.debug(`[Site API] 删除评论开始, siteId: ${siteId}, id: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.deleteReview(id); + const data = await adapter.deleteReview({ id }); this.logger.debug(`[Site API] 删除评论成功, siteId: ${siteId}, id: ${id}`); return successResponse(data); } catch (error) { @@ -159,7 +159,7 @@ export class SiteApiController { this.logger.debug(`[Site API] 获取单个webhook开始, siteId: ${siteId}, id: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.getWebhook(id); + const data = await adapter.getWebhook({ id }); this.logger.debug(`[Site API] 获取单个webhook成功, siteId: ${siteId}, id: ${id}`); return successResponse(data); } catch (error) { @@ -198,7 +198,7 @@ export class SiteApiController { this.logger.debug(`[Site API] 更新webhook开始, siteId: ${siteId}, id: ${id}, body: ${JSON.stringify(body)}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.updateWebhook(id, body); + const data = await adapter.updateWebhook({ id }, body); this.logger.debug(`[Site API] 更新webhook成功, siteId: ${siteId}, id: ${id}`); return successResponse(data); } catch (error) { @@ -216,7 +216,7 @@ export class SiteApiController { this.logger.debug(`[Site API] 删除webhook开始, siteId: ${siteId}, id: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.deleteWebhook(id); + const data = await adapter.deleteWebhook({ id }); this.logger.debug(`[Site API] 删除webhook成功, siteId: ${siteId}, id: ${id}`); return successResponse(data); } catch (error) { @@ -326,7 +326,7 @@ export class SiteApiController { if (site.type === 'woocommerce') { const page = query.page || 1; const perPage = (query.per_page) || 100; - const res = await this.siteApiService.wpService.getProducts(site, page, perPage); + const res = await this.siteApiService.wpService.getProducts(site, { page, per_page: perPage }); const header = ['id', 'name', 'type', 'status', 'sku', 'regular_price', 'sale_price', 'stock_status', 'stock_quantity']; const rows = (res.items || []).map((p: any) => [p.id, p.name, p.type, p.status, p.sku, p.regular_price, p.sale_price, p.stock_status, p.stock_quantity]); const toCsvValue = (val: any) => { @@ -359,7 +359,7 @@ export class SiteApiController { this.logger.info(`[Site API] 获取单个产品开始, siteId: ${siteId}, productId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.getProduct(id); + const data = await adapter.getProduct({ id }); // 如果获取到商品数据,则增强ERP产品信息 if (data) { @@ -484,7 +484,7 @@ export class SiteApiController { this.logger.info(`[Site API] 更新产品开始, siteId: ${siteId}, productId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.updateProduct(id, body); + const data = await adapter.updateProduct({ id }, body); this.logger.info(`[Site API] 更新产品成功, siteId: ${siteId}, productId: ${id}`); return successResponse(data); } catch (error) { @@ -539,7 +539,7 @@ export class SiteApiController { this.logger.info(`[Site API] 删除产品开始, siteId: ${siteId}, productId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const success = await adapter.deleteProduct(id); + const success = await adapter.deleteProduct({ id }); this.logger.info(`[Site API] 删除产品成功, siteId: ${siteId}, productId: ${id}`); return successResponse(success); } catch (error) { @@ -584,7 +584,7 @@ export class SiteApiController { for (const item of body.update) { try { const id = item.id; - const data = await adapter.updateProduct(id, item); + const data = await adapter.updateProduct({ id }, item); updated.push(data); } catch (e) { errors.push({ @@ -597,7 +597,7 @@ export class SiteApiController { if (body.delete?.length) { for (const id of body.delete) { try { - const ok = await adapter.deleteProduct(id); + const ok = await adapter.deleteProduct({ id }); if (ok) deleted.push(id); else errors.push({ identifier: String(id), @@ -771,7 +771,7 @@ export class SiteApiController { this.logger.info(`[Site API] 获取单个订单开始, siteId: ${siteId}, orderId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.getOrder(id); + const data = await adapter.getOrder({ id }); this.logger.info(`[Site API] 获取单个订单成功, siteId: ${siteId}, orderId: ${id}`); return successResponse(data); } catch (error) { @@ -843,7 +843,7 @@ export class SiteApiController { this.logger.info(`[Site API] 更新订单开始, siteId: ${siteId}, orderId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const ok = await adapter.updateOrder(id, body); + const ok = await adapter.updateOrder({ id }, body); this.logger.info(`[Site API] 更新订单成功, siteId: ${siteId}, orderId: ${id}`); return successResponse(ok); } catch (error) { @@ -861,7 +861,7 @@ export class SiteApiController { this.logger.info(`[Site API] 删除订单开始, siteId: ${siteId}, orderId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const ok = await adapter.deleteOrder(id); + const ok = await adapter.deleteOrder({ id }); this.logger.info(`[Site API] 删除订单成功, siteId: ${siteId}, orderId: ${id}`); return successResponse(ok); } catch (error) { @@ -901,7 +901,7 @@ export class SiteApiController { for (const item of body.update) { try { const id = item.id; - const ok = await adapter.updateOrder(id, item); + const ok = await adapter.updateOrder({ id }, item); if (ok) updated.push(item); else errors.push({ identifier: String(item.id || 'unknown'), @@ -918,7 +918,7 @@ export class SiteApiController { if (body.delete?.length) { for (const id of body.delete) { try { - const ok = await adapter.deleteOrder(id); + const ok = await adapter.deleteOrder({ id }); if (ok) deleted.push(id); else errors.push({ identifier: String(id), @@ -1435,7 +1435,7 @@ export class SiteApiController { this.logger.info(`[Site API] 获取单个客户开始, siteId: ${siteId}, customerId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.getCustomer(id); + const data = await adapter.getCustomer({ id }); this.logger.info(`[Site API] 获取单个客户成功, siteId: ${siteId}, customerId: ${id}`); return successResponse(data); } catch (error) { @@ -1507,7 +1507,7 @@ export class SiteApiController { this.logger.info(`[Site API] 更新客户开始, siteId: ${siteId}, customerId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const data = await adapter.updateCustomer(id, body); + const data = await adapter.updateCustomer({ id }, body); this.logger.info(`[Site API] 更新客户成功, siteId: ${siteId}, customerId: ${id}`); return successResponse(data); } catch (error) { @@ -1525,7 +1525,7 @@ export class SiteApiController { this.logger.info(`[Site API] 删除客户开始, siteId: ${siteId}, customerId: ${id}`); try { const adapter = await this.siteApiService.getAdapter(siteId); - const success = await adapter.deleteCustomer(id); + const success = await adapter.deleteCustomer({ id }); this.logger.info(`[Site API] 删除客户成功, siteId: ${siteId}, customerId: ${id}`); return successResponse(success); } catch (error) { @@ -1561,7 +1561,7 @@ export class SiteApiController { for (const item of body.update) { try { const id = item.id; - const data = await adapter.updateCustomer(id, item); + const data = await adapter.updateCustomer({ id }, item); updated.push(data); } catch (e) { failed.push({ action: 'update', item, error: (e as any).message }); @@ -1571,7 +1571,7 @@ export class SiteApiController { if (body.delete?.length) { for (const id of body.delete) { try { - const ok = await adapter.deleteCustomer(id); + const ok = await adapter.deleteCustomer({ id }); if (ok) deleted.push(id); else failed.push({ action: 'delete', id, error: 'delete failed' }); } catch (e) { diff --git a/src/interface/site-adapter.interface.ts b/src/interface/site-adapter.interface.ts index 630e5ed..f290517 100644 --- a/src/interface/site-adapter.interface.ts +++ b/src/interface/site-adapter.interface.ts @@ -19,7 +19,7 @@ import { import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto'; import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto'; -export interface ISiteAdapter { +export interface ISiteAdapter { // ========== 客户映射方法 ========== /** * 将平台客户数据转换为统一客户数据格式 @@ -38,7 +38,7 @@ export interface ISiteAdapter { /** * 获取单个客户 */ - getCustomer(id: string | number): Promise; + getCustomer(where: Partial>): Promise; /** * 获取客户列表 @@ -58,12 +58,12 @@ export interface ISiteAdapter { /** * 更新客户 */ - updateCustomer(id: string | number, data: Partial): Promise; + updateCustomer(where: Partial>, data: Partial): Promise; /** * 删除客户 */ - deleteCustomer(id: string | number): Promise; + deleteCustomer(where: Partial>): Promise; /** * 批量处理客户 @@ -132,7 +132,7 @@ export interface ISiteAdapter { /** * 获取单个订单 */ - getOrder(id: string | number): Promise; + getOrder(where: Partial>): Promise; /** * 获取订单列表 @@ -147,7 +147,7 @@ export interface ISiteAdapter { /** * 获取订单总数 */ - countOrders(params: Record): Promise; + countOrders(params: Record): Promise; /** * 创建订单 @@ -157,12 +157,12 @@ export interface ISiteAdapter { /** * 更新订单 */ - updateOrder(id: string | number, data: Partial): Promise; + updateOrder(where: Partial>, data: Partial): Promise; /** * 删除订单 */ - deleteOrder(id: string | number): Promise; + deleteOrder(where: Partial>): Promise; /** * 获取订单备注 @@ -259,7 +259,7 @@ export interface ISiteAdapter { /** * 获取单个产品 */ - getProduct(id: string | number): Promise; + getProduct(where: Partial>): Promise; /** * 获取产品列表 @@ -279,12 +279,12 @@ export interface ISiteAdapter { /** * 更新产品 */ - updateProduct(id: string | number, data: Partial): Promise; + updateProduct(where: Partial>, data: Partial): Promise; /** * 删除产品 */ - deleteProduct(id: string | number): Promise; + deleteProduct(where: Partial>): Promise; /** * 批量处理产品 @@ -338,12 +338,12 @@ export interface ISiteAdapter { /** * 更新评论 */ - updateReview(id: number, data: UpdateReviewDTO): Promise; + updateReview(where: Partial>, data: UpdateReviewDTO): Promise; /** * 删除评论 */ - deleteReview(id: number): Promise; + deleteReview(where: Partial>): Promise; // ========== 订阅映射方法 ========== /** @@ -461,7 +461,7 @@ export interface ISiteAdapter { /** * 获取单个webhook */ - getWebhook(id: string | number): Promise; + getWebhook(where: Partial>): Promise; /** * 获取webhooks列表 @@ -481,16 +481,16 @@ export interface ISiteAdapter { /** * 更新webhook */ - updateWebhook(id: string | number, data: UpdateWebhookDTO): Promise; + updateWebhook(where: Partial>, data: UpdateWebhookDTO): Promise; /** * 删除webhook */ - deleteWebhook(id: string | number): Promise; + deleteWebhook(where: Partial>): Promise; // ========== 站点/其他方法 ========== /** * 获取站点链接列表 */ - getLinks(): Promise>; + getLinks(): Promise>; } diff --git a/src/service/order.service.ts b/src/service/order.service.ts index 5c5e47f..1aa19bd 100644 --- a/src/service/order.service.ts +++ b/src/service/order.service.ts @@ -202,7 +202,7 @@ export class OrderService { try { // 调用 WooCommerce API 获取订单 const adapter = await this.siteApiService.getAdapter(siteId); - const order = await adapter.getOrder(orderId); + const order = await adapter.getOrder({ id: orderId }); // 检查订单是否已存在,以区分创建和更新 const existingOrder = await this.orderModel.findOne({ diff --git a/src/service/site-api.service.ts b/src/service/site-api.service.ts index c57a899..3aab4ac 100644 --- a/src/service/site-api.service.ts +++ b/src/service/site-api.service.ts @@ -110,36 +110,22 @@ export class SiteApiService { const adapter = await this.getAdapter(siteId); // 首先尝试查找产品 - if (product.id) { - try { - // 尝试获取产品以确认它是否存在 - const existingProduct = await adapter.getProduct(product.id); - if (existingProduct) { - // 产品存在,执行更新 - return await adapter.updateProduct(product.id, product); - } - } catch (error) { - // 如果获取产品失败,可能是因为产品不存在,继续执行创建逻辑 - console.log(`产品 ${product.id} 不存在,将创建新产品:`, error.message); - } - } else if (product.sku) { + if (product.sku) { // 如果没有提供ID但提供了SKU,尝试通过SKU查找产品 try { // 尝试搜索具有相同SKU的产品 - const searchResult = await adapter.getProducts({ where: { sku: product.sku } }); - if (searchResult.items && searchResult.items.length > 0) { - const existingProduct = searchResult.items[0]; + const existingProduct = await adapter.getProduct( { sku: product.sku }); + if (existingProduct) { // 找到现有产品,更新它 - return await adapter.updateProduct(existingProduct.id, product); + return await adapter.updateProduct({ id: existingProduct.id }, product); } + // 产品不存在,执行创建 + return await adapter.createProduct(product); } catch (error) { // 搜索失败,继续执行创建逻辑 console.log(`通过SKU搜索产品失败:`, error.message); } } - - // 产品不存在,执行创建 - return await adapter.createProduct(product); } /** @@ -197,7 +183,7 @@ export class SiteApiService { */ async getProductFromSite(siteId: number, productId: string | number): Promise { const adapter = await this.getAdapter(siteId); - return await adapter.getProduct(productId); + return await adapter.getProduct({ id: productId }); } /** diff --git a/src/service/wp.service.ts b/src/service/wp.service.ts index c7faa02..8c8bc89 100644 --- a/src/service/wp.service.ts +++ b/src/service/wp.service.ts @@ -240,9 +240,11 @@ export class WPService implements IPlatformService { return allData; } - async getProducts(site: any, page: number = 1, pageSize: number = 100): Promise { + async getProducts(site: any, params: Record = {}): Promise { const api = this.createApi(site, 'wc/v3'); - return await this.sdkGetPage(api, 'products', { page, per_page: pageSize }); + const page = params.page ?? 1; + const per_page = params.per_page ?? params.pageSize ?? 100; + return await this.sdkGetPage(api, 'products', { ...params, page, per_page }); } async getProduct(site: any, id: number): Promise { @@ -254,7 +256,7 @@ export class WPService implements IPlatformService { // 导出 WooCommerce 产品为特殊CSV(平台特性) async exportProductsCsvSpecial(site: any, page: number = 1, pageSize: number = 100): Promise { - const list = await this.getProducts(site, page, pageSize); + const list = await this.getProducts(site, { page, per_page: pageSize }); const header = ['id','name','type','status','sku','regular_price','sale_price','stock_status','stock_quantity']; const rows = (list.items || []).map((p: any) => [p.id,p.name,p.type,p.status,p.sku,p.regular_price,p.sale_price,p.stock_status,p.stock_quantity]); const csv = [header.join(','), ...rows.map(r => r.map(v => String(v ?? '')).join(','))].join('\n');