refactor(interface): 重构站点适配器接口,按功能模块组织方法
重构 ISiteAdapter 接口,将相关方法按功能模块(客户、媒体、订单、产品等)分组 移除废弃的 fulfillOrder 方法 新增多个数据映射方法以支持统一数据格式转换
This commit is contained in:
parent
acfee35e73
commit
d549227e03
|
|
@ -21,6 +21,10 @@ import {
|
||||||
CreateReviewDTO,
|
CreateReviewDTO,
|
||||||
CreateVariationDTO,
|
CreateVariationDTO,
|
||||||
UpdateReviewDTO
|
UpdateReviewDTO
|
||||||
|
FulfillmentDTO,
|
||||||
|
CreateReviewDTO,
|
||||||
|
CreateVariationDTO,
|
||||||
|
UpdateReviewDTO
|
||||||
} from '../dto/site-api.dto';
|
} from '../dto/site-api.dto';
|
||||||
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO, } from '../dto/api.dto';
|
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO, } from '../dto/api.dto';
|
||||||
import {
|
import {
|
||||||
|
|
@ -38,6 +42,7 @@ import {
|
||||||
OrderStatus,
|
OrderStatus,
|
||||||
} from '../enums/base.enum';
|
} from '../enums/base.enum';
|
||||||
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
||||||
|
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
||||||
export class ShopyyAdapter implements ISiteAdapter {
|
export class ShopyyAdapter implements ISiteAdapter {
|
||||||
shopyyFinancialStatusMap= {
|
shopyyFinancialStatusMap= {
|
||||||
'200': '待支付',
|
'200': '待支付',
|
||||||
|
|
@ -56,53 +61,53 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
this.mapPlatformToUnifiedOrder = this.mapPlatformToUnifiedOrder.bind(this);
|
this.mapPlatformToUnifiedOrder = this.mapPlatformToUnifiedOrder.bind(this);
|
||||||
this.mapPlatformToUnifiedMedia = this.mapPlatformToUnifiedMedia.bind(this);
|
this.mapPlatformToUnifiedMedia = this.mapPlatformToUnifiedMedia.bind(this);
|
||||||
// this.mapPlatformToUnifiedSubscription = this.mapPlatformToUnifiedSubscription.bind(this);
|
// this.mapPlatformToUnifiedSubscription = this.mapPlatformToUnifiedSubscription.bind(this);
|
||||||
|
this.mapPlatformToUnifiedCustomer = this.mapPlatformToUnifiedCustomer.bind(this);
|
||||||
|
this.mapPlatformToUnifiedProduct = this.mapPlatformToUnifiedProduct.bind(this);
|
||||||
|
this.mapPlatformToUnifiedVariation = this.mapPlatformToUnifiedVariation.bind(this);
|
||||||
|
this.mapPlatformToUnifiedOrder = this.mapPlatformToUnifiedOrder.bind(this);
|
||||||
|
this.mapPlatformToUnifiedMedia = this.mapPlatformToUnifiedMedia.bind(this);
|
||||||
|
// this.mapPlatformToUnifiedSubscription = this.mapPlatformToUnifiedSubscription.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapMedia(item: any): UnifiedMediaDTO {
|
// ========== 客户映射方法 ==========
|
||||||
// 映射媒体项目
|
mapPlatformToUnifiedCustomer(item: ShopyyCustomer): UnifiedCustomerDTO {
|
||||||
return {
|
// 处理多地址结构
|
||||||
id: item.id,
|
const addresses = item.addresses || [];
|
||||||
date_created: item.created_at,
|
const defaultAddress = item.default_address || (addresses.length > 0 ? addresses[0] : {});
|
||||||
date_modified: item.updated_at,
|
|
||||||
source_url: item.src,
|
// 尝试从地址列表中获取billing和shipping
|
||||||
title: item.alt || '',
|
// 如果没有明确区分,默认使用默认地址或第一个地址
|
||||||
media_type: '', // Shopyy API未提供,暂时留空
|
const billingAddress = defaultAddress;
|
||||||
mime_type: '', // Shopyy API未提供,暂时留空
|
const shippingAddress = defaultAddress;
|
||||||
|
|
||||||
|
const billing = {
|
||||||
|
first_name: billingAddress.first_name || item.first_name || '',
|
||||||
|
last_name: billingAddress.last_name || item.last_name || '',
|
||||||
|
fullname: billingAddress.name || `${billingAddress.first_name || item.first_name || ''} ${billingAddress.last_name || item.last_name || ''}`.trim(),
|
||||||
|
company: billingAddress.company || '',
|
||||||
|
email: item.email || '',
|
||||||
|
phone: billingAddress.phone || item.contact || '',
|
||||||
|
address_1: billingAddress.address1 || '',
|
||||||
|
address_2: billingAddress.address2 || '',
|
||||||
|
city: billingAddress.city || '',
|
||||||
|
state: billingAddress.province || '',
|
||||||
|
postcode: billingAddress.zip || '',
|
||||||
|
country: billingAddress.country_name || billingAddress.country_code || item.country?.country_name || ''
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
private mapMediaSearchParams(params: UnifiedSearchParamsDTO): any {
|
const shipping = {
|
||||||
return this.mapSearchParams(params)
|
first_name: shippingAddress.first_name || item.first_name || '',
|
||||||
}
|
last_name: shippingAddress.last_name || item.last_name || '',
|
||||||
|
fullname: shippingAddress.name || `${shippingAddress.first_name || item.first_name || ''} ${shippingAddress.last_name || item.last_name || ''}`.trim(),
|
||||||
|
company: shippingAddress.company || '',
|
||||||
|
address_1: shippingAddress.address1 || '',
|
||||||
|
address_2: shippingAddress.address2 || '',
|
||||||
|
city: shippingAddress.city || '',
|
||||||
|
state: shippingAddress.province || '',
|
||||||
|
postcode: shippingAddress.zip || '',
|
||||||
|
country: shippingAddress.country_name || shippingAddress.country_code || item.country?.country_name || ''
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用搜索参数转换方法,处理 where 和 orderBy 的转换
|
|
||||||
* 将统一的搜索参数转换为 ShopYY API 所需的参数格式
|
|
||||||
*/
|
|
||||||
private mapSearchParams(params: UnifiedSearchParamsDTO): any {
|
|
||||||
// 处理分页参数
|
|
||||||
const page = Number(params.page || 1);
|
|
||||||
const limit = Number(params.per_page ?? 20);
|
|
||||||
|
|
||||||
// 处理 where 条件
|
|
||||||
const query: any = {
|
|
||||||
...(params.where || {}),
|
|
||||||
page,
|
|
||||||
limit,
|
|
||||||
}
|
|
||||||
if(params.orderBy){
|
|
||||||
const [field, dir] = Object.entries(params.orderBy)[0];
|
|
||||||
query.order_by = dir === 'desc' ? 'desc' : 'asc';
|
|
||||||
query.order_field = field
|
|
||||||
}
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
private mapProduct(item: ShopyyProduct & { permalink?: string }): UnifiedProductDTO {
|
|
||||||
// 映射产品状态
|
|
||||||
function mapProductStatus(status: number) {
|
|
||||||
return status === 1 ? 'publish' : 'draft';
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
id: item.id || item.customer_id,
|
id: item.id || item.customer_id,
|
||||||
orders: Number(item.orders_count ?? item.order_count ?? item.orders ?? 0),
|
orders: Number(item.orders_count ?? item.order_count ?? item.orders ?? 0),
|
||||||
|
|
@ -130,11 +135,8 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCustomer(where: {id?: string | number,email?: string,phone?: string}): Promise<UnifiedCustomerDTO> {
|
async getCustomer(id: string | number): Promise<UnifiedCustomerDTO> {
|
||||||
if(!where.id && !where.email && !where.phone){
|
const customer = await this.shopyyService.getCustomer(this.site, id);
|
||||||
throw new Error('必须传入 id 或 email 或 phone')
|
|
||||||
}
|
|
||||||
const customer = await this.shopyyService.getCustomer(this.site, where.id);
|
|
||||||
return this.mapPlatformToUnifiedCustomer(customer);
|
return this.mapPlatformToUnifiedCustomer(customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,13 +162,13 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return this.mapPlatformToUnifiedCustomer(createdCustomer);
|
return this.mapPlatformToUnifiedCustomer(createdCustomer);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateCustomer(where: {id: string | number}, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
|
async updateCustomer(id: string | number, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
|
||||||
const updatedCustomer = await this.shopyyService.updateCustomer(this.site, where.id, data);
|
const updatedCustomer = await this.shopyyService.updateCustomer(this.site, id, data);
|
||||||
return this.mapPlatformToUnifiedCustomer(updatedCustomer);
|
return this.mapPlatformToUnifiedCustomer(updatedCustomer);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteCustomer(where: {id: string | number}): Promise<boolean> {
|
async deleteCustomer(id: string | number): Promise<boolean> {
|
||||||
return await this.shopyyService.deleteCustomer(this.site, where.id);
|
return await this.shopyyService.deleteCustomer(this.site, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
batchProcessCustomers?(data: BatchOperationDTO): Promise<BatchOperationResultDTO> {
|
batchProcessCustomers?(data: BatchOperationDTO): Promise<BatchOperationResultDTO> {
|
||||||
|
|
@ -219,13 +221,13 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return this.mapPlatformToUnifiedMedia(createdMedia);
|
return this.mapPlatformToUnifiedMedia(createdMedia);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateMedia(where: {id: string | number}, data: any): Promise<UnifiedMediaDTO> {
|
async updateMedia(id: string | number, data: any): Promise<UnifiedMediaDTO> {
|
||||||
const updatedMedia = await this.shopyyService.updateMedia(this.site, where.id, data);
|
const updatedMedia = await this.shopyyService.updateMedia(this.site, id, data);
|
||||||
return this.mapPlatformToUnifiedMedia(updatedMedia);
|
return this.mapPlatformToUnifiedMedia(updatedMedia);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteMedia(where: {id: string | number}): Promise<boolean> {
|
async deleteMedia(id: string | number): Promise<boolean> {
|
||||||
return await this.shopyyService.deleteMedia(this.site, where.id);
|
return await this.shopyyService.deleteMedia(this.site, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
mapMediaSearchParams(params: UnifiedSearchParamsDTO): any {
|
mapMediaSearchParams(params: UnifiedSearchParamsDTO): any {
|
||||||
|
|
@ -402,186 +404,148 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
raw: item,
|
raw: item,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
shopyyFulfillmentStatusMap = {
|
|
||||||
// 未发货
|
mapUnifiedToPlatformOrder(data: Partial<UnifiedOrderDTO>) {
|
||||||
'300': OrderFulfillmentStatus.PENDING,
|
return data
|
||||||
// 部分发货
|
|
||||||
'310': OrderFulfillmentStatus.PARTIALLY_FULFILLED,
|
|
||||||
// 已发货
|
|
||||||
'320': OrderFulfillmentStatus.FULFILLED,
|
|
||||||
// 已取消
|
|
||||||
'330': OrderFulfillmentStatus.CANCELLED,
|
|
||||||
// 确认发货
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private mapCustomer(item: ShopyyCustomer): UnifiedCustomerDTO {
|
mapCreateOrderParams(data: Partial<UnifiedOrderDTO>): any {
|
||||||
// 处理多地址结构
|
return data
|
||||||
const addresses = item.addresses || [];
|
|
||||||
const defaultAddress = item.default_address || (addresses.length > 0 ? addresses[0] : {});
|
|
||||||
|
|
||||||
// 尝试从地址列表中获取billing和shipping
|
|
||||||
// 如果没有明确区分,默认使用默认地址或第一个地址
|
|
||||||
const billingAddress = defaultAddress;
|
|
||||||
const shippingAddress = defaultAddress;
|
|
||||||
|
|
||||||
const billing = {
|
|
||||||
first_name: billingAddress.first_name || item.first_name || '',
|
|
||||||
last_name: billingAddress.last_name || item.last_name || '',
|
|
||||||
fullname: billingAddress.name || `${billingAddress.first_name || item.first_name || ''} ${billingAddress.last_name || item.last_name || ''}`.trim(),
|
|
||||||
company: billingAddress.company || '',
|
|
||||||
email: item.email || '',
|
|
||||||
phone: billingAddress.phone || item.contact || '',
|
|
||||||
address_1: billingAddress.address1 || '',
|
|
||||||
address_2: billingAddress.address2 || '',
|
|
||||||
city: billingAddress.city || '',
|
|
||||||
state: billingAddress.province || '',
|
|
||||||
postcode: billingAddress.zip || '',
|
|
||||||
country: billingAddress.country_name || billingAddress.country_code || item.country?.country_name || ''
|
|
||||||
};
|
|
||||||
|
|
||||||
const shipping = {
|
|
||||||
first_name: shippingAddress.first_name || item.first_name || '',
|
|
||||||
last_name: shippingAddress.last_name || item.last_name || '',
|
|
||||||
fullname: shippingAddress.name || `${shippingAddress.first_name || item.first_name || ''} ${shippingAddress.last_name || item.last_name || ''}`.trim(),
|
|
||||||
company: shippingAddress.company || '',
|
|
||||||
address_1: shippingAddress.address1 || '',
|
|
||||||
address_2: shippingAddress.address2 || '',
|
|
||||||
city: shippingAddress.city || '',
|
|
||||||
state: shippingAddress.province || '',
|
|
||||||
postcode: shippingAddress.zip || '',
|
|
||||||
country: shippingAddress.country_name || shippingAddress.country_code || item.country?.country_name || ''
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: item.id || item.customer_id,
|
|
||||||
orders: Number(item.orders_count ?? item.order_count ?? item.orders ?? 0),
|
|
||||||
total_spend: Number(item.total_spent ?? item.total_spend_amount ?? item.total_spend_money ?? 0),
|
|
||||||
first_name: item.first_name || item.firstname || '',
|
|
||||||
last_name: item.last_name || item.lastname || '',
|
|
||||||
fullname: item.fullname || item.customer_name || `${item.first_name || item.firstname || ''} ${item.last_name || item.lastname || ''}`.trim(),
|
|
||||||
email: item.email || item.customer_email || '',
|
|
||||||
phone: item.contact || billing.phone || item.phone || '',
|
|
||||||
billing,
|
|
||||||
shipping,
|
|
||||||
date_created:
|
|
||||||
typeof item.created_at === 'number'
|
|
||||||
? new Date(item.created_at * 1000).toISOString()
|
|
||||||
: (typeof item.created_at === 'string' ? item.created_at : item.date_added || ''),
|
|
||||||
date_modified:
|
|
||||||
typeof item.updated_at === 'number'
|
|
||||||
? new Date(item.updated_at * 1000).toISOString()
|
|
||||||
: (typeof item.updated_at === 'string' ? item.updated_at : item.date_updated || ''),
|
|
||||||
raw: item,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
mapProductQuery(query: UnifiedSearchParamsDTO): ShopyyProductQuery {
|
|
||||||
return this.mapSearchParams(query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProducts(
|
mapUpdateOrderParams(data: Partial<UnifiedOrderDTO>): any {
|
||||||
params: UnifiedSearchParamsDTO
|
// 构建 ShopYY 订单更新参数(仅包含传入的字段)
|
||||||
): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
|
const params: any = {};
|
||||||
// 转换搜索参数
|
|
||||||
const requestParams = this.mapProductQuery(params);
|
|
||||||
const response = await this.shopyyService.fetchResourcePaged<ShopyyProduct>(
|
|
||||||
this.site,
|
|
||||||
'products/list',
|
|
||||||
requestParams
|
|
||||||
);
|
|
||||||
const { items = [], total, totalPages, page, per_page } = response;
|
|
||||||
const finalItems = items.map((item) => ({
|
|
||||||
...item,
|
|
||||||
permalink: `${this.site.websiteUrl}/products/${item.handle}`,
|
|
||||||
})).map(this.mapProduct.bind(this))
|
|
||||||
return {
|
|
||||||
items: finalItems as UnifiedProductDTO[],
|
|
||||||
total,
|
|
||||||
totalPages,
|
|
||||||
page,
|
|
||||||
per_page,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]> {
|
// 仅当字段存在时才添加到更新参数中
|
||||||
// Shopyy getAllProducts 暂未实现
|
if (data.status !== undefined) {
|
||||||
throw new Error('Shopyy getAllProducts 暂未实现');
|
// 映射订单状态
|
||||||
}
|
const statusMap = {
|
||||||
|
[OrderStatus.PENDING]: 100, // pending -> 100 未完成
|
||||||
|
[OrderStatus.PROCESSING]: 110, // processing -> 110 待处理
|
||||||
|
[OrderStatus.COMPLETED]: 180, // completed -> 180 已完成
|
||||||
|
[OrderStatus.CANCEL]: 190 // cancel -> 190 取消
|
||||||
|
};
|
||||||
|
params.status = statusMap[data.status] || 100;
|
||||||
|
}
|
||||||
|
|
||||||
async getProduct(id: string | number): Promise<UnifiedProductDTO> {
|
if (data.payment_method !== undefined) {
|
||||||
// 使用ShopyyService获取单个产品
|
params.payment_method = data.payment_method;
|
||||||
const product = await this.shopyyService.getProduct(this.site, id);
|
}
|
||||||
return this.mapProduct(product);
|
|
||||||
}
|
|
||||||
|
|
||||||
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
|
if (data.billing) {
|
||||||
const res = await this.shopyyService.createProduct(this.site, data);
|
// 更新客户信息
|
||||||
return this.mapProduct(res);
|
if (data.billing.first_name !== undefined) {
|
||||||
}
|
params.firstname = data.billing.first_name;
|
||||||
async updateProduct(id: string | number, data: Partial<UnifiedProductDTO>): Promise<boolean> {
|
}
|
||||||
// Shopyy update returns boolean?
|
if (data.billing.last_name !== undefined) {
|
||||||
// shopyyService.updateProduct returns boolean.
|
params.lastname = data.billing.last_name;
|
||||||
// So I can't return the updated product.
|
}
|
||||||
// I have to fetch it again or return empty/input.
|
if (data.billing.email !== undefined) {
|
||||||
// Since getProduct is missing, I'll return input data as UnifiedProductDTO (mock).
|
params.email = data.billing.email;
|
||||||
await this.shopyyService.updateProduct(this.site, String(id), data);
|
}
|
||||||
return true;
|
if (data.billing.phone !== undefined) {
|
||||||
}
|
params.phone = data.billing.phone;
|
||||||
|
}
|
||||||
|
|
||||||
async updateVariation(productId: string | number, variationId: string | number, data: any): Promise<any> {
|
// 更新账单地址
|
||||||
await this.shopyyService.updateVariation(this.site, String(productId), String(variationId), data);
|
params.billing_address = params.billing_address || {};
|
||||||
return { ...data, id: variationId };
|
if (data.billing.first_name !== undefined) {
|
||||||
}
|
params.billing_address.first_name = data.billing.first_name;
|
||||||
|
}
|
||||||
async getOrderNotes(orderId: string | number): Promise<any[]> {
|
if (data.billing.last_name !== undefined) {
|
||||||
return await this.shopyyService.getOrderNotes(this.site, orderId);
|
params.billing_address.last_name = data.billing.last_name;
|
||||||
}
|
}
|
||||||
|
if (data.billing.company !== undefined) {
|
||||||
async createOrderNote(orderId: string | number, data: any): Promise<any> {
|
params.billing_address.company = data.billing.company;
|
||||||
return await this.shopyyService.createOrderNote(this.site, orderId, data);
|
}
|
||||||
}
|
if (data.billing.address_1 !== undefined) {
|
||||||
|
params.billing_address.address1 = data.billing.address_1;
|
||||||
async deleteProduct(id: string | number): Promise<boolean> {
|
}
|
||||||
// Use batch delete
|
if (data.billing.address_2 !== undefined) {
|
||||||
await this.shopyyService.batchProcessProducts(this.site, { delete: [id] });
|
params.billing_address.address2 = data.billing.address_2;
|
||||||
return true;
|
}
|
||||||
}
|
if (data.billing.city !== undefined) {
|
||||||
|
params.billing_address.city = data.billing.city;
|
||||||
async batchProcessProducts(
|
}
|
||||||
data: { create?: any[]; update?: any[]; delete?: Array<string | number> }
|
if (data.billing.state !== undefined) {
|
||||||
): Promise<any> {
|
params.billing_address.province = data.billing.state;
|
||||||
return await this.shopyyService.batchProcessProducts(this.site, data);
|
}
|
||||||
}
|
if (data.billing.postcode !== undefined) {
|
||||||
/**
|
params.billing_address.zip = data.billing.postcode;
|
||||||
* 将统一的订单查询参数转换为 ShopYY 订单查询参数
|
}
|
||||||
* 包含状态映射等特殊处理
|
if (data.billing.country !== undefined) {
|
||||||
*/
|
params.billing_address.country_code = data.billing.country;
|
||||||
private mapOrderSearchParams(params: UnifiedSearchParamsDTO): Partial<ShopyyOrderQuery> {
|
|
||||||
// 首先使用通用参数转换
|
|
||||||
const baseParams = this.mapSearchParams(params);
|
|
||||||
|
|
||||||
// 订单状态映射
|
|
||||||
const statusMap = {
|
|
||||||
'pending': '100', // 100 未完成
|
|
||||||
'processing': '110', // 110 待处理
|
|
||||||
'completed': "180", // 180 已完成(确认收货)
|
|
||||||
'cancelled': '190', // 190 取消
|
|
||||||
};
|
|
||||||
|
|
||||||
// 如果有状态参数,进行特殊映射
|
|
||||||
if (baseParams.status) {
|
|
||||||
const unifiedStatus = baseParams.status
|
|
||||||
if (statusMap[unifiedStatus]) {
|
|
||||||
baseParams.status = statusMap[unifiedStatus];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理ID参数
|
if (data.shipping) {
|
||||||
if (baseParams.id) {
|
// 更新送货地址
|
||||||
baseParams.ids = baseParams.id;
|
params.shipping_address = params.shipping_address || {};
|
||||||
delete baseParams.id;
|
if (data.shipping.first_name !== undefined) {
|
||||||
|
params.shipping_address.first_name = data.shipping.first_name;
|
||||||
|
}
|
||||||
|
if (data.shipping.last_name !== undefined) {
|
||||||
|
params.shipping_address.last_name = data.shipping.last_name;
|
||||||
|
}
|
||||||
|
if (data.shipping.company !== undefined) {
|
||||||
|
params.shipping_address.company = data.shipping.company;
|
||||||
|
}
|
||||||
|
if (data.shipping.address_1 !== undefined) {
|
||||||
|
params.shipping_address.address1 = data.shipping.address_1;
|
||||||
|
}
|
||||||
|
if (data.shipping.address_2 !== undefined) {
|
||||||
|
params.shipping_address.address2 = data.shipping.address_2;
|
||||||
|
}
|
||||||
|
if (data.shipping.city !== undefined) {
|
||||||
|
params.shipping_address.city = data.shipping.city;
|
||||||
|
}
|
||||||
|
if (data.shipping.state !== undefined) {
|
||||||
|
params.shipping_address.province = data.shipping.state;
|
||||||
|
}
|
||||||
|
if (data.shipping.postcode !== undefined) {
|
||||||
|
params.shipping_address.zip = data.shipping.postcode;
|
||||||
|
}
|
||||||
|
if (data.shipping.country !== undefined) {
|
||||||
|
params.shipping_address.country_code = data.shipping.country;
|
||||||
|
}
|
||||||
|
if (data.shipping.phone !== undefined) {
|
||||||
|
params.shipping_address.phone = data.shipping.phone;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return baseParams;
|
// 更新订单项
|
||||||
|
if (data.line_items && data.line_items.length > 0) {
|
||||||
|
params.products = data.line_items.map((item: UnifiedOrderLineItemDTO) => ({
|
||||||
|
product_id: item.product_id,
|
||||||
|
quantity: item.quantity,
|
||||||
|
// price: item.price || '0.00',
|
||||||
|
sku: item.sku || '',
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新物流信息
|
||||||
|
if (data.shipping_lines && data.shipping_lines.length > 0) {
|
||||||
|
const shippingLine = data.shipping_lines[0];
|
||||||
|
if (shippingLine.method_title !== undefined) {
|
||||||
|
params.shipping_method = shippingLine.method_title;
|
||||||
|
}
|
||||||
|
if (shippingLine.total !== undefined) {
|
||||||
|
params.shipping_price = shippingLine.total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 更新备注信息
|
||||||
|
// if (data.note !== undefined) {
|
||||||
|
// params.note = data.note;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getOrder(id: string | number): Promise<UnifiedOrderDTO> {
|
||||||
|
const data = await this.shopyyService.getOrder(this.site.id, String(id));
|
||||||
|
return this.mapPlatformToUnifiedOrder(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOrders(
|
async getOrders(
|
||||||
|
|
@ -602,6 +566,7 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
normalizedParams
|
normalizedParams
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
items: items.map(this.mapPlatformToUnifiedOrder.bind(this)),
|
||||||
items: items.map(this.mapPlatformToUnifiedOrder.bind(this)),
|
items: items.map(this.mapPlatformToUnifiedOrder.bind(this)),
|
||||||
total,
|
total,
|
||||||
totalPages,
|
totalPages,
|
||||||
|
|
@ -610,17 +575,6 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async countOrders(where: Record<string,any>): Promise<number> {
|
|
||||||
// 使用最小分页只获取总数
|
|
||||||
const searchParams = {
|
|
||||||
where,
|
|
||||||
page: 1,
|
|
||||||
per_page: 1,
|
|
||||||
}
|
|
||||||
const data = await this.getOrders(searchParams);
|
|
||||||
return data.total || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]> {
|
async getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]> {
|
||||||
const data = await this.shopyyService.getAllOrders(this.site.id, params);
|
const data = await this.shopyyService.getAllOrders(this.site.id, params);
|
||||||
return data.map(this.mapPlatformToUnifiedOrder.bind(this));
|
return data.map(this.mapPlatformToUnifiedOrder.bind(this));
|
||||||
|
|
@ -642,12 +596,16 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
const requestParams = this.mapCreateOrderParams(data);
|
const requestParams = this.mapCreateOrderParams(data);
|
||||||
const createdOrder = await this.shopyyService.createOrder(this.site, requestParams);
|
const createdOrder = await this.shopyyService.createOrder(this.site, requestParams);
|
||||||
return this.mapPlatformToUnifiedOrder(createdOrder);
|
return this.mapPlatformToUnifiedOrder(createdOrder);
|
||||||
|
// 使用映射方法转换参数
|
||||||
|
const requestParams = this.mapCreateOrderParams(data);
|
||||||
|
const createdOrder = await this.shopyyService.createOrder(this.site, requestParams);
|
||||||
|
return this.mapPlatformToUnifiedOrder(createdOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOrder(where: {id: string | number}, data: Partial<UnifiedOrderDTO>): Promise<boolean> {
|
async updateOrder(id: string | number, data: Partial<UnifiedOrderDTO>): Promise<boolean> {
|
||||||
// 使用映射方法转换参数
|
// 使用映射方法转换参数
|
||||||
const requestParams = this.mapUpdateOrderParams(data);
|
const requestParams = this.mapUpdateOrderParams(data);
|
||||||
return await this.shopyyService.updateOrder(this.site, String(where.id), requestParams);
|
return await this.shopyyService.updateOrder(this.site, String(id), requestParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteOrder(where: {id: string | number}): Promise<boolean> {
|
async deleteOrder(where: {id: string | number}): Promise<boolean> {
|
||||||
|
|
@ -658,6 +616,12 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return await this.shopyyService.getOrderNotes(this.site, orderId);
|
return await this.shopyyService.getOrderNotes(this.site, orderId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createOrderNote(orderId: string | number, data: any): Promise<any> {
|
||||||
|
return await this.shopyyService.createOrderNote(this.site, orderId, data);
|
||||||
|
async getOrderNotes(orderId: string | number): Promise<any[]> {
|
||||||
|
return await this.shopyyService.getOrderNotes(this.site, orderId);
|
||||||
|
}
|
||||||
|
|
||||||
async createOrderNote(orderId: string | number, data: any): Promise<any> {
|
async createOrderNote(orderId: string | number, data: any): Promise<any> {
|
||||||
return await this.shopyyService.createOrderNote(this.site, orderId, data);
|
return await this.shopyyService.createOrderNote(this.site, orderId, data);
|
||||||
}
|
}
|
||||||
|
|
@ -684,6 +648,7 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(`履行失败: ${error.message}`);
|
throw new Error(`履行失败: ${error.message}`);
|
||||||
|
throw new Error(`履行失败: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -925,36 +890,39 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getProduct(where: {id?: string | number, sku?: string}): Promise<UnifiedProductDTO> {
|
async getProduct(id: string | number): Promise<UnifiedProductDTO> {
|
||||||
if(!where.id && !where.sku){
|
// 使用ShopyyService获取单个产品
|
||||||
throw new Error('必须传入 id 或 sku')
|
const product = await this.shopyyService.getProduct(this.site, id);
|
||||||
}
|
return this.mapPlatformToUnifiedProduct(product);
|
||||||
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(
|
||||||
async getProducts(
|
async getProducts(
|
||||||
params: UnifiedSearchParamsDTO
|
params: UnifiedSearchParamsDTO
|
||||||
|
): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
|
||||||
|
// 转换搜索参数
|
||||||
|
const requestParams = this.mapProductQuery(params);
|
||||||
|
const response = await this.shopyyService.fetchResourcePaged<ShopyyProduct>(
|
||||||
): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
|
): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
|
||||||
// 转换搜索参数
|
// 转换搜索参数
|
||||||
const requestParams = this.mapProductQuery(params);
|
const requestParams = this.mapProductQuery(params);
|
||||||
const response = await this.shopyyService.fetchResourcePaged<ShopyyProduct>(
|
const response = await this.shopyyService.fetchResourcePaged<ShopyyProduct>(
|
||||||
this.site,
|
this.site,
|
||||||
'media', // Shopyy的媒体API端点可能需要调整
|
'products/list',
|
||||||
requestParams
|
requestParams
|
||||||
);
|
);
|
||||||
const { items = [], total, totalPages, page, per_page } = response;
|
const { items = [], total, totalPages, page, per_page } = response;
|
||||||
const finalItems = items.map((item) => ({
|
const finalItems = items.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
permalink: `${this.site.websiteUrl}/products/${item.handle}`,
|
permalink: `${this.site.websiteUrl}/products/${item.handle}`,
|
||||||
})).map(this.mapPlatformToUnifiedProduct.bind(this))
|
})).map(this.mapPlatformToUnifiedProduct.bind(this))
|
||||||
|
const { items = [], total, totalPages, page, per_page } = response;
|
||||||
|
const finalItems = items.map((item) => ({
|
||||||
|
...item,
|
||||||
|
permalink: `${this.site.websiteUrl}/products/${item.handle}`,
|
||||||
|
})).map(this.mapPlatformToUnifiedProduct.bind(this))
|
||||||
return {
|
return {
|
||||||
|
items: finalItems as UnifiedProductDTO[],
|
||||||
items: finalItems as UnifiedProductDTO[],
|
items: finalItems as UnifiedProductDTO[],
|
||||||
total,
|
total,
|
||||||
totalPages,
|
totalPages,
|
||||||
|
|
@ -963,11 +931,19 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]> {
|
||||||
|
// Shopyy getAllProducts 暂未实现
|
||||||
|
throw new Error('Shopyy getAllProducts 暂未实现');
|
||||||
async getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]> {
|
async getAllProducts(params?: UnifiedSearchParamsDTO): Promise<UnifiedProductDTO[]> {
|
||||||
// Shopyy getAllProducts 暂未实现
|
// Shopyy getAllProducts 暂未实现
|
||||||
throw new Error('Shopyy getAllProducts 暂未实现');
|
throw new Error('Shopyy getAllProducts 暂未实现');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
|
||||||
|
// 使用映射方法转换参数
|
||||||
|
const requestParams = this.mapCreateProductParams(data);
|
||||||
|
const res = await this.shopyyService.createProduct(this.site, requestParams);
|
||||||
|
return this.mapPlatformToUnifiedProduct(res);
|
||||||
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
|
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
|
||||||
// 使用映射方法转换参数
|
// 使用映射方法转换参数
|
||||||
const requestParams = this.mapCreateProductParams(data);
|
const requestParams = this.mapCreateProductParams(data);
|
||||||
|
|
@ -975,50 +951,24 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return this.mapPlatformToUnifiedProduct(res);
|
return this.mapPlatformToUnifiedProduct(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateProduct(where: {id?: string | number, sku?: string}, data: Partial<UnifiedProductDTO>): Promise<boolean> {
|
async updateProduct(id: string | number, data: Partial<UnifiedProductDTO>): Promise<boolean> {
|
||||||
let productId: string;
|
// Shopyy update returns boolean?
|
||||||
if (where.id) {
|
// shopyyService.updateProduct returns boolean.
|
||||||
productId = String(where.id);
|
// So I can't return the updated product.
|
||||||
} else if (where.sku) {
|
// I have to fetch it again or return empty/input.
|
||||||
// 通过sku获取产品ID
|
// Since getProduct is missing, I'll return input data as UnifiedProductDTO (mock).
|
||||||
const product = await this.getProductBySku(where.sku);
|
|
||||||
productId = String(product.id);
|
|
||||||
} else {
|
|
||||||
throw new Error('必须提供id或sku参数');
|
|
||||||
}
|
|
||||||
// 使用映射方法转换参数
|
// 使用映射方法转换参数
|
||||||
const requestParams = this.mapUpdateProductParams(data);
|
const requestParams = this.mapUpdateProductParams(data);
|
||||||
await this.shopyyService.updateProduct(this.site, productId, requestParams);
|
await this.shopyyService.updateProduct(this.site, String(id), requestParams);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteProduct(where: {id?: string | number, sku?: string}): Promise<boolean> {
|
async deleteProduct(id: string | number): Promise<boolean> {
|
||||||
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
|
// Use batch delete
|
||||||
await this.shopyyService.batchProcessProducts(this.site, { delete: [productId] });
|
await this.shopyyService.batchProcessProducts(this.site, { delete: [id] });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通过sku获取产品详情的私有方法
|
|
||||||
private async getProductBySku(sku: string): Promise<UnifiedProductDTO> {
|
|
||||||
// 使用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(
|
async batchProcessProducts(
|
||||||
data: { create?: any[]; update?: any[]; delete?: Array<string | number> }
|
data: { create?: any[]; update?: any[]; delete?: Array<string | number> }
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
|
|
@ -1030,6 +980,9 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 评论映射方法 ==========
|
// ========== 评论映射方法 ==========
|
||||||
|
mapPlatformToUnifiedReview(data: any): UnifiedReviewDTO {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
mapUnifiedToPlatformReview(data: Partial<UnifiedReviewDTO>) {
|
mapUnifiedToPlatformReview(data: Partial<UnifiedReviewDTO>) {
|
||||||
return data
|
return data
|
||||||
|
|
@ -1067,19 +1020,19 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
|
|
||||||
async createReview(data: any): Promise<UnifiedReviewDTO> {
|
async createReview(data: any): Promise<UnifiedReviewDTO> {
|
||||||
const createdReview = await this.shopyyService.createReview(this.site, data);
|
const createdReview = await this.shopyyService.createReview(this.site, data);
|
||||||
return this.mapPlatformToUnifiedReview(createdReview);
|
return this.mapReview(createdReview);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateReview(where: {id: string | number}, data: any): Promise<UnifiedReviewDTO> {
|
async updateReview(id: string | number, data: any): Promise<UnifiedReviewDTO> {
|
||||||
const updatedReview = await this.shopyyService.updateReview(this.site, where.id, data);
|
const updatedReview = await this.shopyyService.updateReview(this.site, id, data);
|
||||||
return this.mapPlatformToUnifiedReview(updatedReview);
|
return this.mapReview(updatedReview);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteReview(where: {id: string | number}): Promise<boolean> {
|
async deleteReview(id: string | number): Promise<boolean> {
|
||||||
return await this.shopyyService.deleteReview(this.site, where.id);
|
return await this.shopyyService.deleteReview(this.site, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedReview(review: any): UnifiedReviewDTO {
|
mapReview(review: any): UnifiedReviewDTO {
|
||||||
// 将ShopYY评论数据映射到统一评论DTO格式
|
// 将ShopYY评论数据映射到统一评论DTO格式
|
||||||
return {
|
return {
|
||||||
id: review.id || review.review_id,
|
id: review.id || review.review_id,
|
||||||
|
|
@ -1096,7 +1049,6 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mapReviewSearchParams(params: UnifiedSearchParamsDTO): any {
|
|
||||||
mapReviewSearchParams(params: UnifiedSearchParamsDTO): any {
|
mapReviewSearchParams(params: UnifiedSearchParamsDTO): any {
|
||||||
const { search, page, per_page, where } = params;
|
const { search, page, per_page, where } = params;
|
||||||
const shopyyParams: any = {
|
const shopyyParams: any = {
|
||||||
|
|
@ -1122,19 +1074,36 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
|
|
||||||
mapUnifiedToPlatformSubscription(data: Partial<UnifiedSubscriptionDTO>) {
|
mapUnifiedToPlatformSubscription(data: Partial<UnifiedSubscriptionDTO>) {
|
||||||
return data
|
return data
|
||||||
|
// ========== 订阅映射方法 ==========
|
||||||
|
mapPlatformToUnifiedSubscription(data: any): UnifiedSubscriptionDTO {
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mapUnifiedToPlatformSubscription(data: Partial<UnifiedSubscriptionDTO>) {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSubscriptions(
|
||||||
|
params: UnifiedSearchParamsDTO
|
||||||
|
): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
|
||||||
|
throw new Error('Shopyy does not support subscriptions.');
|
||||||
async getSubscriptions(
|
async getSubscriptions(
|
||||||
params: UnifiedSearchParamsDTO
|
params: UnifiedSearchParamsDTO
|
||||||
): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
|
): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
|
||||||
throw new Error('Shopyy does not support subscriptions.');
|
throw new Error('Shopyy does not support subscriptions.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
|
||||||
|
// Shopyy getAllSubscriptions 暂未实现
|
||||||
|
throw new Error('Shopyy getAllSubscriptions 暂未实现');
|
||||||
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
|
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
|
||||||
// Shopyy getAllSubscriptions 暂未实现
|
// Shopyy getAllSubscriptions 暂未实现
|
||||||
throw new Error('Shopyy getAllSubscriptions 暂未实现');
|
throw new Error('Shopyy getAllSubscriptions 暂未实现');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 产品变体映射方法 ==========
|
||||||
|
mapPlatformToUnifiedVariation(variant: ShopyyVariant): UnifiedProductVariationDTO {
|
||||||
|
// 映射变体
|
||||||
// ========== 产品变体映射方法 ==========
|
// ========== 产品变体映射方法 ==========
|
||||||
mapPlatformToUnifiedVariation(variant: ShopyyVariant): UnifiedProductVariationDTO {
|
mapPlatformToUnifiedVariation(variant: ShopyyVariant): UnifiedProductVariationDTO {
|
||||||
// 映射变体
|
// 映射变体
|
||||||
|
|
@ -1218,7 +1187,9 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== Webhook映射方法 ==========
|
// ========== Webhook映射方法 ==========
|
||||||
|
mapPlatformToUnifiedWebhook(data: any): UnifiedWebhookDTO {
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
mapUnifiedToPlatformWebhook(data: Partial<UnifiedWebhookDTO>) {
|
mapUnifiedToPlatformWebhook(data: Partial<UnifiedWebhookDTO>) {
|
||||||
return data
|
return data
|
||||||
|
|
@ -1232,9 +1203,9 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
async getWebhook(where: {id: string | number}): Promise<UnifiedWebhookDTO> {
|
async getWebhook(id: string | number): Promise<UnifiedWebhookDTO> {
|
||||||
const webhook = await this.shopyyService.getWebhook(this.site, where.id);
|
const webhook = await this.shopyyService.getWebhook(this.site, id);
|
||||||
return this.mapPlatformToUnifiedWebhook(webhook);
|
return this.mapWebhook(webhook);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getWebhooks(params: UnifiedSearchParamsDTO): Promise<UnifiedWebhookPaginationDTO> {
|
async getWebhooks(params: UnifiedSearchParamsDTO): Promise<UnifiedWebhookPaginationDTO> {
|
||||||
|
|
@ -1267,7 +1238,7 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return await this.shopyyService.deleteWebhook(this.site, where.id);
|
return await this.shopyyService.deleteWebhook(this.site, where.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedWebhook(item: ShopyyWebhook): UnifiedWebhookDTO {
|
mapWebhook(item: ShopyyWebhook): UnifiedWebhookDTO {
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.webhook_name || `Webhook-${item.id}`,
|
name: item.webhook_name || `Webhook-${item.id}`,
|
||||||
|
|
@ -1297,6 +1268,19 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
return links;
|
return links;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 辅助方法 ==========
|
||||||
|
/**
|
||||||
|
* 通用搜索参数转换方法,处理 where 和 orderBy 的转换
|
||||||
|
* 将统一的搜索参数转换为 ShopYY API 所需的参数格式
|
||||||
|
*/
|
||||||
|
mapSearchParams(params: UnifiedSearchParamsDTO): any {
|
||||||
|
// 处理分页参数
|
||||||
|
const page = Number(params.page || 1);
|
||||||
|
const limit = Number(params.per_page ?? 20);
|
||||||
|
|
||||||
|
// 处理 where 条件
|
||||||
|
const query: any = {
|
||||||
|
...(params.where || {}),
|
||||||
// ========== 辅助方法 ==========
|
// ========== 辅助方法 ==========
|
||||||
/**
|
/**
|
||||||
* 通用搜索参数转换方法,处理 where 和 orderBy 的转换
|
* 通用搜索参数转换方法,处理 where 和 orderBy 的转换
|
||||||
|
|
@ -1318,6 +1302,14 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
query.order_by = dir === 'desc' ? 'desc' : 'asc';
|
query.order_by = dir === 'desc' ? 'desc' : 'asc';
|
||||||
query.order_field = field
|
query.order_field = field
|
||||||
}
|
}
|
||||||
|
return query;
|
||||||
|
limit,
|
||||||
|
}
|
||||||
|
if(params.orderBy){
|
||||||
|
const [field, dir] = Object.entries(params.orderBy)[0];
|
||||||
|
query.order_by = dir === 'desc' ? 'desc' : 'asc';
|
||||||
|
query.order_field = field
|
||||||
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1340,6 +1332,35 @@ export class ShopyyAdapter implements ISiteAdapter {
|
||||||
[190]: OrderStatus.CANCEL // 190 取消 转为 cancelled
|
[190]: OrderStatus.CANCEL // 190 取消 转为 cancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shopyyFulfillmentStatusMap = {
|
||||||
|
// 未发货
|
||||||
|
'300': OrderFulfillmentStatus.PENDING,
|
||||||
|
// 部分发货
|
||||||
|
'310': OrderFulfillmentStatus.PARTIALLY_FULFILLED,
|
||||||
|
// 已发货
|
||||||
|
'320': OrderFulfillmentStatus.FULFILLED,
|
||||||
|
// 已取消
|
||||||
|
'330': OrderFulfillmentStatus.CANCELLED,
|
||||||
|
// 确认发货
|
||||||
|
// 映射产品状态: publish -> 1, draft -> 0
|
||||||
|
mapStatus = (status: string) => {
|
||||||
|
return status === 'publish' ? 1 : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 映射库存状态: instock -> 1, outofstock -> 0
|
||||||
|
mapStockStatus = (stockStatus: string) => {
|
||||||
|
return stockStatus === 'instock' ? 1 : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
shopyyOrderStatusMap = {//订单状态 100 未完成;110 待处理;180 已完成(确认收货); 190 取消;
|
||||||
|
[100]: OrderStatus.PENDING, // 100 未完成 转为 pending
|
||||||
|
[110]: OrderStatus.PROCESSING, // 110 待处理 转为 processing
|
||||||
|
// 已发货
|
||||||
|
|
||||||
|
[180]: OrderStatus.COMPLETED, // 180 已完成(确认收货) 转为 completed
|
||||||
|
[190]: OrderStatus.CANCEL // 190 取消 转为 cancelled
|
||||||
|
}
|
||||||
|
|
||||||
shopyyFulfillmentStatusMap = {
|
shopyyFulfillmentStatusMap = {
|
||||||
// 未发货
|
// 未发货
|
||||||
'300': OrderFulfillmentStatus.PENDING,
|
'300': OrderFulfillmentStatus.PENDING,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ import {
|
||||||
UnifiedVariationPaginationDTO,
|
UnifiedVariationPaginationDTO,
|
||||||
CreateReviewDTO,
|
CreateReviewDTO,
|
||||||
UpdateReviewDTO,
|
UpdateReviewDTO,
|
||||||
|
CreateReviewDTO,
|
||||||
|
UpdateReviewDTO,
|
||||||
} from '../dto/site-api.dto';
|
} from '../dto/site-api.dto';
|
||||||
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto';
|
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto';
|
||||||
import {
|
import {
|
||||||
|
|
@ -32,6 +34,7 @@ import {
|
||||||
import { Site } from '../entity/site.entity';
|
import { Site } from '../entity/site.entity';
|
||||||
import { WPService } from '../service/wp.service';
|
import { WPService } from '../service/wp.service';
|
||||||
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
||||||
|
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
||||||
|
|
||||||
export class WooCommerceAdapter implements ISiteAdapter {
|
export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
// 构造函数接收站点配置与服务实例
|
// 构造函数接收站点配置与服务实例
|
||||||
|
|
@ -43,9 +46,6 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
this.mapPlatformToUnifiedOrder = this.mapPlatformToUnifiedOrder.bind(this);
|
this.mapPlatformToUnifiedOrder = this.mapPlatformToUnifiedOrder.bind(this);
|
||||||
this.mapPlatformToUnifiedWebhook = this.mapPlatformToUnifiedWebhook.bind(this);
|
this.mapPlatformToUnifiedWebhook = this.mapPlatformToUnifiedWebhook.bind(this);
|
||||||
}
|
}
|
||||||
mapUnifiedToPlatformCustomer(data: Partial<UnifiedCustomerDTO>) {
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
batchProcessProducts?(data: BatchOperationDTO): Promise<BatchOperationResultDTO> {
|
batchProcessProducts?(data: BatchOperationDTO): Promise<BatchOperationResultDTO> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
@ -57,8 +57,14 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 客户映射方法 ==========
|
// ========== 客户映射方法 ==========
|
||||||
|
mapPlatformToUnifiedCustomer(data: any): UnifiedCustomerDTO {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
mapUnifiedToPlatformCustomer(data: Partial<UnifiedCustomerDTO>) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedCustomer(item: WooCustomer): UnifiedCustomerDTO {
|
mapCustomer(item: WooCustomer): UnifiedCustomerDTO {
|
||||||
// 将 WooCommerce 客户数据映射为统一客户DTO
|
// 将 WooCommerce 客户数据映射为统一客户DTO
|
||||||
// 包含基础信息地址信息与时间信息
|
// 包含基础信息地址信息与时间信息
|
||||||
return {
|
return {
|
||||||
|
|
@ -76,6 +82,20 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
date_created: item.date_created,
|
date_created: item.date_created,
|
||||||
date_modified: item.date_modified,
|
date_modified: item.date_modified,
|
||||||
raw: item,
|
raw: item,
|
||||||
|
id: item.id,
|
||||||
|
avatar: item.avatar_url,
|
||||||
|
email: item.email,
|
||||||
|
orders: Number(item.orders ?? 0),
|
||||||
|
total_spend: Number(item.total_spent ?? 0),
|
||||||
|
first_name: item.first_name,
|
||||||
|
last_name: item.last_name,
|
||||||
|
username: item.username,
|
||||||
|
phone: item.billing?.phone || item.shipping?.phone,
|
||||||
|
billing: item.billing,
|
||||||
|
shipping: item.shipping,
|
||||||
|
date_created: item.date_created,
|
||||||
|
date_modified: item.date_modified,
|
||||||
|
raw: item,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,10 +153,10 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 客户操作方法
|
// 客户操作方法
|
||||||
async getCustomer(where: {id: string | number}): Promise<UnifiedCustomerDTO> {
|
async getCustomer(id: string | number): Promise<UnifiedCustomerDTO> {
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const res = await api.get(`customers/${where.id}`);
|
const res = await api.get(`customers/${id}`);
|
||||||
return this.mapPlatformToUnifiedCustomer(res.data);
|
return this.mapCustomer(res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCustomers(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedCustomerDTO>> {
|
async getCustomers(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedCustomerDTO>> {
|
||||||
|
|
@ -147,7 +167,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
requestParams
|
requestParams
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
items: items.map((i: any) => this.mapPlatformToUnifiedCustomer(i)),
|
items: items.map((i: any) => this.mapCustomer(i)),
|
||||||
total,
|
total,
|
||||||
totalPages,
|
totalPages,
|
||||||
page,
|
page,
|
||||||
|
|
@ -164,33 +184,36 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
const requestParams = this.mapCustomerSearchParams(params || {});
|
const requestParams = this.mapCustomerSearchParams(params || {});
|
||||||
|
|
||||||
const customers = await this.wpService.sdkGetAll(api, 'customers', requestParams);
|
const customers = await this.wpService.sdkGetAll(api, 'customers', requestParams);
|
||||||
return customers.map((customer: any) => this.mapPlatformToUnifiedCustomer(customer));
|
return customers.map((customer: any) => this.mapCustomer(customer));
|
||||||
}
|
}
|
||||||
|
|
||||||
async createCustomer(data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
|
async createCustomer(data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const res = await api.post('customers', data);
|
const res = await api.post('customers', data);
|
||||||
return this.mapPlatformToUnifiedCustomer(res.data);
|
return this.mapCustomer(res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateCustomer(where: {id: string | number}, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
|
async updateCustomer(id: string | number, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO> {
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const res = await api.put(`customers/${where.id}`, data);
|
const res = await api.put(`customers/${id}`, data);
|
||||||
return this.mapPlatformToUnifiedCustomer(res.data);
|
return this.mapCustomer(res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteCustomer(where: {id: string | number}): Promise<boolean> {
|
async deleteCustomer(id: string | number): Promise<boolean> {
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
await api.delete(`customers/${where.id}`, { force: true });
|
await api.delete(`customers/${id}`, { force: true });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 媒体映射方法 ==========
|
// ========== 媒体映射方法 ==========
|
||||||
|
mapPlatformToUnifiedMedia(data: any): UnifiedMediaDTO {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
mapUnifiedToPlatformMedia(data: Partial<UnifiedMediaDTO>) {
|
mapUnifiedToPlatformMedia(data: Partial<UnifiedMediaDTO>) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedMedia(item: WpMedia): UnifiedMediaDTO {
|
mapMedia(item: WpMedia): UnifiedMediaDTO {
|
||||||
// 将 WordPress 媒体数据映射为统一媒体DTO
|
// 将 WordPress 媒体数据映射为统一媒体DTO
|
||||||
// 兼容不同字段命名的时间信息
|
// 兼容不同字段命名的时间信息
|
||||||
return {
|
return {
|
||||||
|
|
@ -215,7 +238,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
params
|
params
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
items: items.map(this.mapPlatformToUnifiedMedia.bind(this)),
|
items: items.map(this.mapMedia.bind(this)),
|
||||||
total,
|
total,
|
||||||
totalPages,
|
totalPages,
|
||||||
page,
|
page,
|
||||||
|
|
@ -227,21 +250,21 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
// 使用sdkGetAll获取所有媒体数据,不受分页限制
|
// 使用sdkGetAll获取所有媒体数据,不受分页限制
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const media = await this.wpService.sdkGetAll(api, 'media', params);
|
const media = await this.wpService.sdkGetAll(api, 'media', params);
|
||||||
return media.map((mediaItem: any) => this.mapPlatformToUnifiedMedia(mediaItem));
|
return media.map((mediaItem: any) => this.mapMedia(mediaItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
createMedia(file: any): Promise<UnifiedMediaDTO> {
|
createMedia(file: any): Promise<UnifiedMediaDTO> {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateMedia(where: {id: string | number}, data: any): Promise<any> {
|
async updateMedia(id: string | number, data: any): Promise<any> {
|
||||||
// 更新媒体信息
|
// 更新媒体信息
|
||||||
return await this.wpService.updateMedia(Number(this.site.id), Number(where.id), data);
|
return await this.wpService.updateMedia(Number(this.site.id), Number(id), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteMedia(where: {id: string | number}): Promise<boolean> {
|
async deleteMedia(id: string | number): Promise<boolean> {
|
||||||
// 删除媒体资源
|
// 删除媒体资源
|
||||||
await this.wpService.deleteMedia(Number(this.site.id), Number(where.id), true);
|
await this.wpService.deleteMedia(Number(this.site.id), Number(id), true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -252,6 +275,9 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 订单映射方法 ==========
|
// ========== 订单映射方法 ==========
|
||||||
|
mapPlatformToUnifiedOrder(data: any): UnifiedOrderDTO {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
mapUnifiedToPlatformOrder(data: Partial<UnifiedOrderDTO>) {
|
mapUnifiedToPlatformOrder(data: Partial<UnifiedOrderDTO>) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +289,6 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapOrderSearchParams(params: UnifiedSearchParamsDTO): Partial<WooOrderSearchParams> {
|
|
||||||
mapOrderSearchParams(params: UnifiedSearchParamsDTO): Partial<WooOrderSearchParams> {
|
mapOrderSearchParams(params: UnifiedSearchParamsDTO): Partial<WooOrderSearchParams> {
|
||||||
// 计算分页参数
|
// 计算分页参数
|
||||||
const page = Number(params.page ?? 1);
|
const page = Number(params.page ?? 1);
|
||||||
|
|
@ -348,7 +373,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
].filter(Boolean).join(', ');
|
].filter(Boolean).join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedOrder(item: WooOrder): UnifiedOrderDTO {
|
mapOrder(item: WooOrder): UnifiedOrderDTO {
|
||||||
// 将 WooCommerce 订单数据映射为统一订单DTO
|
// 将 WooCommerce 订单数据映射为统一订单DTO
|
||||||
// 包含账单地址与收货地址以及创建与更新时间
|
// 包含账单地址与收货地址以及创建与更新时间
|
||||||
|
|
||||||
|
|
@ -402,11 +427,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 订单操作方法
|
// 订单操作方法
|
||||||
async getOrder(where: {id: string | number}): Promise<UnifiedOrderDTO> {
|
async getOrder(id: string | number): Promise<UnifiedOrderDTO> {
|
||||||
// 获取单个订单详情
|
// 获取单个订单详情
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const res = await api.get(`orders/${where.id}`);
|
const res = await api.get(`orders/${id}`);
|
||||||
return this.mapPlatformToUnifiedOrder(res.data);
|
return this.mapOrder(res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>> {
|
async getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>> {
|
||||||
|
|
@ -436,7 +461,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: ordersWithFulfillments.map(this.mapPlatformToUnifiedOrder),
|
items: ordersWithFulfillments.map(this.mapOrder),
|
||||||
total,
|
total,
|
||||||
totalPages,
|
totalPages,
|
||||||
page,
|
page,
|
||||||
|
|
@ -448,7 +473,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
// 使用sdkGetAll获取所有订单数据,不受分页限制
|
// 使用sdkGetAll获取所有订单数据,不受分页限制
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const orders = await this.wpService.sdkGetAll(api, 'orders', params);
|
const orders = await this.wpService.sdkGetAll(api, 'orders', params);
|
||||||
return orders.map((order: any) => this.mapPlatformToUnifiedOrder(order));
|
return orders.map((order: any) => this.mapOrder(order));
|
||||||
}
|
}
|
||||||
|
|
||||||
async countOrders(where: Record<string, any>): Promise<number> {
|
async countOrders(where: Record<string, any>): Promise<number> {
|
||||||
|
|
@ -467,18 +492,18 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
// 创建订单并返回统一订单DTO
|
// 创建订单并返回统一订单DTO
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const res = await api.post('orders', data);
|
const res = await api.post('orders', data);
|
||||||
return this.mapPlatformToUnifiedOrder(res.data);
|
return this.mapOrder(res.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateOrder(where: {id: string | number}, data: Partial<UnifiedOrderDTO>): Promise<boolean> {
|
async updateOrder(id: string | number, data: Partial<UnifiedOrderDTO>): Promise<boolean> {
|
||||||
// 更新订单并返回布尔结果
|
// 更新订单并返回布尔结果
|
||||||
return await this.wpService.updateOrder(this.site, String(where.id), data as any);
|
return await this.wpService.updateOrder(this.site, String(id), data as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteOrder(where: {id: string | number}): Promise<boolean> {
|
async deleteOrder(id: string | number): Promise<boolean> {
|
||||||
// 删除订单
|
// 删除订单
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
await api.delete(`orders/${where.id}`, { force: true });
|
await api.delete(`orders/${id}`, { force: true });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -583,6 +608,9 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 产品映射方法 ==========
|
// ========== 产品映射方法 ==========
|
||||||
|
mapPlatformToUnifiedProduct(data: any): UnifiedProductDTO {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
mapUnifiedToPlatformProduct(data: Partial<UnifiedProductDTO>) {
|
mapUnifiedToPlatformProduct(data: Partial<UnifiedProductDTO>) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
@ -612,6 +640,40 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
return String(value).split(',').map(v => v.trim()).filter(Boolean);
|
return String(value).split(',').map(v => v.trim()).filter(Boolean);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (where.search_fields ?? where.searchFields) mapped.search_fields = toArray(where.search_fields ?? where.searchFields);
|
||||||
|
if (where.after ?? where.date_created_after ?? where.created_after) mapped.after = String(where.after ?? where.date_created_after ?? where.created_after);
|
||||||
|
if (where.before ?? where.date_created_before ?? where.created_before) mapped.before = String(where.before ?? where.date_created_before ?? where.created_before);
|
||||||
|
if (where.modified_after ?? where.date_modified_after) mapped.modified_after = String(where.modified_after ?? where.date_modified_after);
|
||||||
|
if (where.modified_before ?? where.date_modified_before) mapped.modified_before = String(where.modified_before ?? where.date_modified_before);
|
||||||
|
if (where.dates_are_gmt ?? where.datesAreGmt) mapped.dates_are_gmt = Boolean(where.dates_are_gmt ?? where.datesAreGmt);
|
||||||
|
if (where.exclude ?? where.exclude_ids ?? where.excludedIds) mapped.exclude = toArray(where.exclude ?? where.exclude_ids ?? where.excludedIds);
|
||||||
|
if (where.include ?? where.ids) mapped.include = toArray(where.include ?? where.ids);
|
||||||
|
if (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);
|
||||||
|
if (where.slug) mapped.slug = String(where.slug);
|
||||||
|
if (!mapped.status && (where.status || where.include_status || where.exclude_status || where.includeStatus || where.excludeStatus)) {
|
||||||
|
if (where.include_status ?? where.includeStatus) mapped.include_status = String(where.include_status ?? where.includeStatus);
|
||||||
|
if (where.exclude_status ?? where.excludeStatus) mapped.exclude_status = String(where.exclude_status ?? where.excludeStatus);
|
||||||
|
if (where.status) mapped.status = String(where.status);
|
||||||
|
}
|
||||||
|
if (where.type) mapped.type = String(where.type);
|
||||||
|
if (where.include_types ?? where.includeTypes) mapped.include_types = String(where.include_types ?? where.includeTypes);
|
||||||
|
if (where.exclude_types ?? where.excludeTypes) mapped.exclude_types = String(where.exclude_types ?? where.excludeTypes);
|
||||||
|
if (where.sku) mapped.sku = String(where.sku);
|
||||||
|
if (where.featured ?? where.isFeatured) mapped.featured = Boolean(where.featured ?? where.isFeatured);
|
||||||
|
if (where.category ?? where.categoryId) mapped.category = String(where.category ?? where.categoryId);
|
||||||
|
if (where.tag ?? where.tagId) mapped.tag = String(where.tag ?? where.tagId);
|
||||||
|
if (where.shipping_class ?? where.shippingClass) mapped.shipping_class = String(where.shipping_class ?? where.shippingClass);
|
||||||
|
if (where.attribute ?? where.attributeName) mapped.attribute = String(where.attribute ?? where.attributeName);
|
||||||
|
if (where.attribute_term ?? where.attributeTermId ?? where.attributeTerm) mapped.attribute_term = String(where.attribute_term ?? where.attributeTermId ?? where.attributeTerm);
|
||||||
|
if (where.tax_class ?? where.taxClass) mapped.tax_class = String(where.tax_class ?? where.taxClass);
|
||||||
|
if (where.on_sale ?? where.onSale) mapped.on_sale = Boolean(where.on_sale ?? where.onSale);
|
||||||
|
if (where.min_price ?? where.minPrice) mapped.min_price = String(where.min_price ?? where.minPrice);
|
||||||
|
if (where.max_price ?? where.maxPrice) mapped.max_price = String(where.max_price ?? where.maxPrice);
|
||||||
|
if (where.stock_status ?? where.stockStatus) mapped.stock_status = String(where.stock_status ?? where.stockStatus);
|
||||||
|
if (where.virtual !== undefined) mapped.virtual = Boolean(where.virtual);
|
||||||
|
if (where.downloadable !== undefined) mapped.downloadable = Boolean(where.downloadable);
|
||||||
if (where.search_fields ?? where.searchFields) mapped.search_fields = toArray(where.search_fields ?? where.searchFields);
|
if (where.search_fields ?? where.searchFields) mapped.search_fields = toArray(where.search_fields ?? where.searchFields);
|
||||||
if (where.after ?? where.date_created_after ?? where.created_after) mapped.after = String(where.after ?? where.date_created_after ?? where.created_after);
|
if (where.after ?? where.date_created_after ?? where.created_after) mapped.after = String(where.after ?? where.date_created_after ?? where.created_after);
|
||||||
if (where.before ?? where.date_created_before ?? where.created_before) mapped.before = String(where.before ?? where.date_created_before ?? where.created_before);
|
if (where.before ?? where.date_created_before ?? where.created_before) mapped.before = String(where.before ?? where.date_created_before ?? where.created_before);
|
||||||
|
|
@ -650,7 +712,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
return mapped;
|
return mapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedProduct(item: WooProduct): UnifiedProductDTO {
|
mapProduct(item: WooProduct): UnifiedProductDTO {
|
||||||
// 将 WooCommerce 产品数据映射为统一产品DTO
|
// 将 WooCommerce 产品数据映射为统一产品DTO
|
||||||
// 保留常用字段与时间信息以便前端统一展示
|
// 保留常用字段与时间信息以便前端统一展示
|
||||||
// https://woocommerce.github.io/woocommerce-rest-api-docs/?javascript#product-properties
|
// https://woocommerce.github.io/woocommerce-rest-api-docs/?javascript#product-properties
|
||||||
|
|
@ -738,22 +800,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
raw: item,
|
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 getProductById(id: string | number): Promise<UnifiedProductDTO> {
|
async getProduct(id: string | number): Promise<UnifiedProductDTO> {
|
||||||
// 获取单个产品详情并映射为统一产品DTO
|
// 获取单个产品详情并映射为统一产品DTO
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
|
|
||||||
const res = await api.get(`products/${id}`);
|
const res = await api.get(`products/${id}`);
|
||||||
const product = res.data;
|
const product = res.data;
|
||||||
|
|
||||||
|
|
@ -773,9 +824,10 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.mapPlatformToUnifiedProduct(product);
|
return this.mapProduct(product);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getProducts(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
|
||||||
async getProducts(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
|
async getProducts(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedProductDTO>> {
|
||||||
// 获取产品列表并使用统一分页结构返回
|
// 获取产品列表并使用统一分页结构返回
|
||||||
const requestParams = this.mapProductSearchParams(params);
|
const requestParams = this.mapProductSearchParams(params);
|
||||||
|
|
@ -784,6 +836,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
'products',
|
'products',
|
||||||
requestParams
|
requestParams
|
||||||
);
|
);
|
||||||
|
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
|
||||||
|
this.site,
|
||||||
|
'products',
|
||||||
|
requestParams
|
||||||
|
);
|
||||||
|
|
||||||
// 对于类型为 variable 的产品,需要加载完整的变体数据
|
// 对于类型为 variable 的产品,需要加载完整的变体数据
|
||||||
const productsWithVariations = await Promise.all(
|
const productsWithVariations = await Promise.all(
|
||||||
|
|
@ -844,7 +901,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return productsWithVariations.map((product: any) => this.mapPlatformToUnifiedProduct(product));
|
return productsWithVariations.map((product: any) => this.mapProduct(product));
|
||||||
}
|
}
|
||||||
|
|
||||||
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
|
async createProduct(data: Partial<UnifiedProductDTO>): Promise<UnifiedProductDTO> {
|
||||||
|
|
@ -855,17 +912,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
|
|
||||||
async updateProduct(where: {id?: string | number, sku?: string}, data: Partial<UnifiedProductDTO>): Promise<boolean> {
|
async updateProduct(where: {id?: string | number, sku?: string}, data: Partial<UnifiedProductDTO>): Promise<boolean> {
|
||||||
// 更新产品并返回统一产品DTO
|
// 更新产品并返回统一产品DTO
|
||||||
let productId: string;
|
const res = await this.wpService.updateProduct(this.site, String(id), data as any);
|
||||||
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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -890,87 +937,12 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async batchProcessProducts(
|
// ========== 评论映射方法 ==========
|
||||||
data: { create?: any[]; update?: any[]; delete?: Array<string | number> }
|
mapPlatformToUnifiedReview(data: any): UnifiedReviewDTO {
|
||||||
): Promise<any> {
|
return data;
|
||||||
// 批量处理产品增删改
|
|
||||||
return await this.wpService.batchProcessProducts(this.site, data);
|
|
||||||
}
|
}
|
||||||
|
mapUnifiedToPlatformReview(data: Partial<UnifiedReviewDTO>) {
|
||||||
async getOrders(
|
return data;
|
||||||
params: UnifiedSearchParamsDTO
|
|
||||||
): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>> {
|
|
||||||
const requestParams = this.mapOrderSearchParams(params);
|
|
||||||
const { items, total, totalPages, page, per_page } =
|
|
||||||
await this.wpService.fetchResourcePaged<any>(this.site, 'orders', requestParams);
|
|
||||||
|
|
||||||
// 并行获取所有订单的履行信息
|
|
||||||
const ordersWithFulfillments = await Promise.all(
|
|
||||||
items.map(async (order: any) => {
|
|
||||||
try {
|
|
||||||
// 获取订单的履行信息
|
|
||||||
const fulfillments = await this.getOrderFulfillments(order.id);
|
|
||||||
// 将履行信息添加到订单对象中
|
|
||||||
return {
|
|
||||||
...order,
|
|
||||||
fulfillments: fulfillments || []
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
// 如果获取履行信息失败,仍然返回订单,只是履行信息为空数组
|
|
||||||
console.error(`获取订单 ${order.id} 的履行信息失败:`, error);
|
|
||||||
return {
|
|
||||||
...order,
|
|
||||||
fulfillments: []
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
items: ordersWithFulfillments.map(this.mapOrder),
|
|
||||||
total,
|
|
||||||
totalPages,
|
|
||||||
page,
|
|
||||||
per_page,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async countOrders(where: Record<string,any>): Promise<number> {
|
|
||||||
// 使用最小分页只获取总数
|
|
||||||
const searchParams: UnifiedSearchParamsDTO = {
|
|
||||||
where,
|
|
||||||
page: 1,
|
|
||||||
per_page: 1,
|
|
||||||
};
|
|
||||||
const requestParams = this.mapOrderSearchParams(searchParams);
|
|
||||||
const { total } = await this.wpService.fetchResourcePaged<any>(this.site, 'orders', requestParams);
|
|
||||||
return total || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getOrder(id: string | number): Promise<UnifiedOrderDTO> {
|
|
||||||
// 获取单个订单详情
|
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
|
||||||
const res = await api.get(`orders/${id}`);
|
|
||||||
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');
|
|
||||||
const res = await api.post('orders', data);
|
|
||||||
return this.mapOrder(res.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateOrder(id: string | number, data: Partial<UnifiedOrderDTO>): Promise<boolean> {
|
|
||||||
// 更新订单并返回布尔结果
|
|
||||||
return await this.wpService.updateOrder(this.site, String(id), data as any);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mapCreateReviewParams(data: CreateReviewDTO) {
|
mapCreateReviewParams(data: CreateReviewDTO) {
|
||||||
|
|
@ -980,7 +952,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedReview(item: any): UnifiedReviewDTO & { raw: any } {
|
mapReview(item: any): UnifiedReviewDTO & { raw: any } {
|
||||||
// 将 WooCommerce 评论数据映射为统一评论DTO
|
// 将 WooCommerce 评论数据映射为统一评论DTO
|
||||||
return {
|
return {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
|
|
@ -995,6 +967,8 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 评论操作方法
|
||||||
|
async getReviews(params: UnifiedSearchParamsDTO): Promise<UnifiedReviewPaginationDTO> {
|
||||||
// 评论操作方法
|
// 评论操作方法
|
||||||
async getReviews(params: UnifiedSearchParamsDTO): Promise<UnifiedReviewPaginationDTO> {
|
async getReviews(params: UnifiedSearchParamsDTO): Promise<UnifiedReviewPaginationDTO> {
|
||||||
// 获取评论列表并使用统一分页结构返回
|
// 获取评论列表并使用统一分页结构返回
|
||||||
|
|
@ -1004,6 +978,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
'products/reviews',
|
'products/reviews',
|
||||||
requestParams
|
requestParams
|
||||||
);
|
);
|
||||||
|
const { items, total, totalPages, page, per_page } = await this.wpService.fetchResourcePaged<any>(
|
||||||
|
this.site,
|
||||||
|
'products/reviews',
|
||||||
|
requestParams
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
items: items.map(this.mapPlatformToUnifiedReview.bind(this)),
|
items: items.map(this.mapPlatformToUnifiedReview.bind(this)),
|
||||||
total,
|
total,
|
||||||
|
|
@ -1030,16 +1009,19 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
return this.mapPlatformToUnifiedReview(res);
|
return this.mapPlatformToUnifiedReview(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteReview(where: {id: number}): Promise<boolean> {
|
async deleteReview(id: number): Promise<boolean> {
|
||||||
return await this.wpService.deleteReview(this.site, where.id);
|
return await this.wpService.deleteReview(this.site, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 订阅映射方法 ==========
|
// ========== 订阅映射方法 ==========
|
||||||
|
mapPlatformToUnifiedSubscription(data: any): UnifiedSubscriptionDTO {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
mapUnifiedToPlatformSubscription(data: Partial<UnifiedSubscriptionDTO>) {
|
mapUnifiedToPlatformSubscription(data: Partial<UnifiedSubscriptionDTO>) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapPlatformToUnifiedSubscription(item: WooSubscription): UnifiedSubscriptionDTO {
|
mapSubscription(item: WooSubscription): UnifiedSubscriptionDTO {
|
||||||
// 将 WooCommerce 订阅数据映射为统一订阅DTO
|
// 将 WooCommerce 订阅数据映射为统一订阅DTO
|
||||||
// 若缺少创建时间则回退为开始时间
|
// 若缺少创建时间则回退为开始时间
|
||||||
return {
|
return {
|
||||||
|
|
@ -1049,14 +1031,26 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
billing_period: item.billing_period,
|
billing_period: item.billing_period,
|
||||||
billing_interval: item.billing_interval,
|
billing_interval: item.billing_interval,
|
||||||
date_created: item.date_created ?? item.start_date,
|
date_created: item.date_created ?? item.start_date,
|
||||||
|
status: item.status,
|
||||||
|
customer_id: item.customer_id,
|
||||||
|
billing_period: item.billing_period,
|
||||||
|
billing_interval: item.billing_interval,
|
||||||
|
date_created: item.date_created ?? item.start_date,
|
||||||
date_modified: item.date_modified,
|
date_modified: item.date_modified,
|
||||||
start_date: item.start_date,
|
start_date: item.start_date,
|
||||||
next_payment_date: item.next_payment_date,
|
next_payment_date: item.next_payment_date,
|
||||||
line_items: item.line_items,
|
line_items: item.line_items,
|
||||||
|
start_date: item.start_date,
|
||||||
|
next_payment_date: item.next_payment_date,
|
||||||
|
line_items: item.line_items,
|
||||||
raw: item,
|
raw: item,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 订阅操作方法
|
||||||
|
async getSubscriptions(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
|
||||||
|
// 获取订阅列表并映射为统一订阅DTO集合
|
||||||
|
|
||||||
// 订阅操作方法
|
// 订阅操作方法
|
||||||
async getSubscriptions(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
|
async getSubscriptions(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedSubscriptionDTO>> {
|
||||||
// 获取订阅列表并映射为统一订阅DTO集合
|
// 获取订阅列表并映射为统一订阅DTO集合
|
||||||
|
|
@ -1064,9 +1058,11 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
this.site,
|
this.site,
|
||||||
'subscriptions',
|
'subscriptions',
|
||||||
params
|
params
|
||||||
|
'subscriptions',
|
||||||
|
params
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
items: items.map(this.mapPlatformToUnifiedSubscription),
|
items: items.map(this.mapSubscription),
|
||||||
total,
|
total,
|
||||||
totalPages,
|
totalPages,
|
||||||
page,
|
page,
|
||||||
|
|
@ -1075,13 +1071,21 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
|
||||||
|
// 使用sdkGetAll获取所有订阅数据,不受分页限制
|
||||||
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
|
async getAllSubscriptions(params?: UnifiedSearchParamsDTO): Promise<UnifiedSubscriptionDTO[]> {
|
||||||
// 使用sdkGetAll获取所有订阅数据,不受分页限制
|
// 使用sdkGetAll获取所有订阅数据,不受分页限制
|
||||||
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
const api = (this.wpService as any).createApi(this.site, 'wc/v3');
|
||||||
const subscriptions = await this.wpService.sdkGetAll(api, 'subscriptions', params);
|
const subscriptions = await this.wpService.sdkGetAll(api, 'subscriptions', params);
|
||||||
return subscriptions.map((subscription: any) => this.mapPlatformToUnifiedSubscription(subscription));
|
return subscriptions.map((subscription: any) => this.mapSubscription(subscription));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 变体映射方法 ==========
|
||||||
|
mapPlatformToUnifiedVariation(data: any): UnifiedProductVariationDTO {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
mapUnifiedToPlatformVariation(data: Partial<UnifiedProductVariationDTO>) {
|
||||||
|
return data;
|
||||||
// ========== 变体映射方法 ==========
|
// ========== 变体映射方法 ==========
|
||||||
mapPlatformToUnifiedVariation(data: any): UnifiedProductVariationDTO {
|
mapPlatformToUnifiedVariation(data: any): UnifiedProductVariationDTO {
|
||||||
return data;
|
return data;
|
||||||
|
|
@ -1091,7 +1095,6 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 映射 WooCommerce 变体到统一格式
|
// 映射 WooCommerce 变体到统一格式
|
||||||
mapVariation(variation: any, productName?: string): UnifiedProductVariationDTO {
|
|
||||||
mapVariation(variation: any, productName?: string): UnifiedProductVariationDTO {
|
mapVariation(variation: any, productName?: string): UnifiedProductVariationDTO {
|
||||||
// 将变体属性转换为统一格式
|
// 将变体属性转换为统一格式
|
||||||
const mappedAttributes = variation.attributes && Array.isArray(variation.attributes)
|
const mappedAttributes = variation.attributes && Array.isArray(variation.attributes)
|
||||||
|
|
@ -1141,6 +1144,7 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 变体操作方法
|
||||||
// 变体操作方法
|
// 变体操作方法
|
||||||
// 获取产品变体列表
|
// 获取产品变体列表
|
||||||
async getVariations(productId: string | number, params: UnifiedSearchParamsDTO): Promise<UnifiedVariationPaginationDTO> {
|
async getVariations(productId: string | number, params: UnifiedSearchParamsDTO): Promise<UnifiedVariationPaginationDTO> {
|
||||||
|
|
@ -1316,4 +1320,145 @@ export class WooCommerceAdapter implements ISiteAdapter {
|
||||||
throw new Error(`删除产品变体失败: ${error instanceof Error ? error.message : String(error)}`);
|
throw new Error(`删除产品变体失败: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ========== 网络钩子映射方法 ==========
|
||||||
|
mapPlatformToUnifiedWebhook(data: any): UnifiedWebhookDTO {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
mapUnifiedToPlatformWebhook(data: Partial<UnifiedWebhookDTO>) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapCreateWebhookParams(data: CreateWebhookDTO) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
mapUpdateWebhookParams(data: UpdateWebhookDTO) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 映射 WooCommerce webhook 到统一格式
|
||||||
|
mapWebhook(webhook: WooWebhook): UnifiedWebhookDTO {
|
||||||
|
return {
|
||||||
|
id: webhook.id.toString(),
|
||||||
|
name: webhook.name,
|
||||||
|
status: webhook.status,
|
||||||
|
topic: webhook.topic,
|
||||||
|
delivery_url: webhook.delivery_url,
|
||||||
|
secret: webhook.secret,
|
||||||
|
api_version: webhook.api_version,
|
||||||
|
date_created: webhook.date_created,
|
||||||
|
date_modified: webhook.date_modified,
|
||||||
|
// metadata: webhook.meta_data || [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 网络钩子操作方法
|
||||||
|
// 获取站点的 webhooks 列表
|
||||||
|
async getWebhooks(params: UnifiedSearchParamsDTO): Promise<UnifiedWebhookPaginationDTO> {
|
||||||
|
try {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to get webhooks: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有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 {
|
||||||
|
const result = await this.wpService.getWebhook(this.site, id);
|
||||||
|
return this.mapWebhook(result as WooWebhook);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to get webhook: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的 webhook
|
||||||
|
async createWebhook(data: CreateWebhookDTO): Promise<UnifiedWebhookDTO> {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
name: data.name,
|
||||||
|
status: 'active', // 默认状态为活跃
|
||||||
|
topic: data.topic,
|
||||||
|
delivery_url: data.delivery_url,
|
||||||
|
secret: data.secret,
|
||||||
|
api_version: data.api_version || 'wp/v2',
|
||||||
|
};
|
||||||
|
const result = await this.wpService.createWebhook(this.site, params);
|
||||||
|
return this.mapWebhook(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<UnifiedWebhookDTO> {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
...(data.name ? { name: data.name } : {}),
|
||||||
|
...(data.status ? { status: data.status } : {}),
|
||||||
|
...(data.topic ? { topic: data.topic } : {}),
|
||||||
|
...(data.delivery_url ? { delivery_url: data.delivery_url } : {}),
|
||||||
|
...(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);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to update webhook: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除指定的 webhook
|
||||||
|
async deleteWebhook(id: string | number): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await this.wpService.deleteWebhook(this.site, id);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`Failed to delete webhook: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== 其他方法 ==========
|
||||||
|
async getLinks(): Promise<Array<{ title: string, url: string }>> {
|
||||||
|
const baseUrl = this.site.apiUrl;
|
||||||
|
const links = [
|
||||||
|
{ title: '访问网站', url: baseUrl },
|
||||||
|
{ title: '管理后台', url: `${baseUrl}/wp-admin/` },
|
||||||
|
{ title: '订单管理', url: `${baseUrl}/wp-admin/edit.php?post_type=shop_order` },
|
||||||
|
{ title: '产品管理', url: `${baseUrl}/wp-admin/edit.php?post_type=product` },
|
||||||
|
{ title: '客户管理', url: `${baseUrl}/wp-admin/users.php` },
|
||||||
|
{ title: '插件管理', url: `${baseUrl}/wp-admin/plugins.php` },
|
||||||
|
{ title: '主题管理', url: `${baseUrl}/wp-admin/themes.php` },
|
||||||
|
{ title: 'WooCommerce设置', url: `${baseUrl}/wp-admin/admin.php?page=wc-settings` },
|
||||||
|
{ title: 'WooCommerce报告', url: `${baseUrl}/wp-admin/admin.php?page=wc-reports` },
|
||||||
|
];
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
batchProcessOrders?(data: { create?: any[]; update?: any[]; delete?: Array<string | number>; }): Promise<any> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
|
|
||||||
|
batchProcessCustomers?(data: { create?: any[]; update?: any[]; delete?: Array<string | number>; }): Promise<any> {
|
||||||
|
throw new Error('Method not implemented.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import {
|
||||||
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto';
|
import { UnifiedPaginationDTO, UnifiedSearchParamsDTO } from '../dto/api.dto';
|
||||||
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
import { BatchOperationDTO, BatchOperationResultDTO } from '../dto/batch.dto';
|
||||||
|
|
||||||
export interface ISiteAdapter {
|
export interface ISiteAdapter {
|
||||||
// ========== 客户映射方法 ==========
|
// ========== 客户映射方法 ==========
|
||||||
/**
|
/**
|
||||||
* 将平台客户数据转换为统一客户数据格式
|
* 将平台客户数据转换为统一客户数据格式
|
||||||
|
|
@ -36,19 +36,16 @@ export interface ISiteAdapter {
|
||||||
mapUnifiedToPlatformCustomer(data: Partial<UnifiedCustomerDTO>): any;
|
mapUnifiedToPlatformCustomer(data: Partial<UnifiedCustomerDTO>): any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取单个客户
|
||||||
* 获取单个客户
|
* 获取单个客户
|
||||||
*/
|
*/
|
||||||
getCustomer(where: Partial<Pick<UnifiedCustomerDTO, 'id' | 'email' | 'phone'>>): Promise<UnifiedCustomerDTO>;
|
getCustomer(id: string | number): Promise<UnifiedCustomerDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取客户列表
|
||||||
* 获取客户列表
|
* 获取客户列表
|
||||||
*/
|
*/
|
||||||
getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>>;
|
getCustomers(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedCustomerDTO>>;
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取订单总数
|
|
||||||
*/
|
|
||||||
countOrders(params: Record<string,any>): Promise<number>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有客户
|
* 获取所有客户
|
||||||
|
|
@ -63,12 +60,12 @@ export interface ISiteAdapter {
|
||||||
/**
|
/**
|
||||||
* 更新客户
|
* 更新客户
|
||||||
*/
|
*/
|
||||||
updateCustomer(where: Partial<Pick<UnifiedCustomerDTO, 'id' | 'email' | 'phone'>>, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO>;
|
updateCustomer(id: string | number, data: Partial<UnifiedCustomerDTO>): Promise<UnifiedCustomerDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除客户
|
* 删除客户
|
||||||
*/
|
*/
|
||||||
deleteCustomer(where: Partial<Pick<UnifiedCustomerDTO, 'id' | 'email' | 'phone'>>): Promise<boolean>;
|
deleteCustomer(id: string | number): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量处理客户
|
* 批量处理客户
|
||||||
|
|
@ -105,69 +102,96 @@ export interface ISiteAdapter {
|
||||||
*/
|
*/
|
||||||
createMedia(file: any): Promise<UnifiedMediaDTO>;
|
createMedia(file: any): Promise<UnifiedMediaDTO>;
|
||||||
|
|
||||||
|
// ========== 订单映射方法 ==========
|
||||||
// ========== 订单映射方法 ==========
|
// ========== 订单映射方法 ==========
|
||||||
/**
|
/**
|
||||||
|
* 将平台订单数据转换为统一订单数据格式
|
||||||
|
* @param data 平台特定订单数据
|
||||||
|
* @returns 统一订单数据格式
|
||||||
* 将平台订单数据转换为统一订单数据格式
|
* 将平台订单数据转换为统一订单数据格式
|
||||||
* @param data 平台特定订单数据
|
* @param data 平台特定订单数据
|
||||||
* @returns 统一订单数据格式
|
* @returns 统一订单数据格式
|
||||||
*/
|
*/
|
||||||
mapPlatformToUnifiedOrder(data: any): UnifiedOrderDTO;
|
mapPlatformToUnifiedOrder(data: any): UnifiedOrderDTO;
|
||||||
|
mapPlatformToUnifiedOrder(data: any): UnifiedOrderDTO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 将统一订单数据格式转换为平台订单数据
|
||||||
|
* @param data 统一订单数据格式
|
||||||
|
* @returns 平台特定订单数据
|
||||||
* 将统一订单数据格式转换为平台订单数据
|
* 将统一订单数据格式转换为平台订单数据
|
||||||
* @param data 统一订单数据格式
|
* @param data 统一订单数据格式
|
||||||
* @returns 平台特定订单数据
|
* @returns 平台特定订单数据
|
||||||
*/
|
*/
|
||||||
mapUnifiedToPlatformOrder(data: Partial<UnifiedOrderDTO>): any;
|
mapUnifiedToPlatformOrder(data: Partial<UnifiedOrderDTO>): any;
|
||||||
|
mapUnifiedToPlatformOrder(data: Partial<UnifiedOrderDTO>): any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 将统一订单创建参数转换为平台订单创建参数
|
||||||
|
* @param data 统一订单创建参数
|
||||||
|
* @returns 平台订单创建参数
|
||||||
* 将统一订单创建参数转换为平台订单创建参数
|
* 将统一订单创建参数转换为平台订单创建参数
|
||||||
* @param data 统一订单创建参数
|
* @param data 统一订单创建参数
|
||||||
* @returns 平台订单创建参数
|
* @returns 平台订单创建参数
|
||||||
*/
|
*/
|
||||||
mapCreateOrderParams(data: Partial<UnifiedOrderDTO>): any;
|
mapCreateOrderParams(data: Partial<UnifiedOrderDTO>): any;
|
||||||
|
mapCreateOrderParams(data: Partial<UnifiedOrderDTO>): any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 将统一订单更新参数转换为平台订单更新参数
|
||||||
|
* @param data 统一订单更新参数
|
||||||
|
* @returns 平台订单更新参数
|
||||||
* 将统一订单更新参数转换为平台订单更新参数
|
* 将统一订单更新参数转换为平台订单更新参数
|
||||||
* @param data 统一订单更新参数
|
* @param data 统一订单更新参数
|
||||||
* @returns 平台订单更新参数
|
* @returns 平台订单更新参数
|
||||||
*/
|
*/
|
||||||
mapUpdateOrderParams(data: Partial<UnifiedOrderDTO>): any;
|
mapUpdateOrderParams(data: Partial<UnifiedOrderDTO>): any;
|
||||||
|
mapUpdateOrderParams(data: Partial<UnifiedOrderDTO>): any;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取单个订单
|
||||||
* 获取单个订单
|
* 获取单个订单
|
||||||
*/
|
*/
|
||||||
getOrder(where: Partial<Pick<UnifiedOrderDTO, 'id'>>): Promise<UnifiedOrderDTO>;
|
getOrder(id: string | number): Promise<UnifiedOrderDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取订单列表
|
||||||
* 获取订单列表
|
* 获取订单列表
|
||||||
*/
|
*/
|
||||||
getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>>;
|
getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>>;
|
||||||
|
getOrders(params: UnifiedSearchParamsDTO): Promise<UnifiedPaginationDTO<UnifiedOrderDTO>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取所有订单
|
||||||
* 获取所有订单
|
* 获取所有订单
|
||||||
*/
|
*/
|
||||||
getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]>;
|
getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]>;
|
||||||
|
getAllOrders(params?: UnifiedSearchParamsDTO): Promise<UnifiedOrderDTO[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 获取订单总数
|
||||||
* 获取订单总数
|
* 获取订单总数
|
||||||
*/
|
*/
|
||||||
countOrders(params: Record<string, any>): Promise<number>;
|
countOrders(params: Record<string,any>): Promise<number>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 创建订单
|
||||||
* 创建订单
|
* 创建订单
|
||||||
*/
|
*/
|
||||||
createOrder(data: Partial<UnifiedOrderDTO>): Promise<UnifiedOrderDTO>;
|
createOrder(data: Partial<UnifiedOrderDTO>): Promise<UnifiedOrderDTO>;
|
||||||
|
createOrder(data: Partial<UnifiedOrderDTO>): Promise<UnifiedOrderDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 更新订单
|
||||||
* 更新订单
|
* 更新订单
|
||||||
*/
|
*/
|
||||||
updateOrder(where: Partial<Pick<UnifiedOrderDTO, 'id'>>, data: Partial<UnifiedOrderDTO>): Promise<boolean>;
|
updateOrder(id: string | number, data: Partial<UnifiedOrderDTO>): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 删除订单
|
||||||
* 删除订单
|
* 删除订单
|
||||||
*/
|
*/
|
||||||
deleteOrder(where: Partial<Pick<UnifiedOrderDTO, 'id'>>): Promise<boolean>;
|
deleteOrder(id: string | number): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取订单备注
|
* 获取订单备注
|
||||||
|
|
@ -264,7 +288,7 @@ export interface ISiteAdapter {
|
||||||
/**
|
/**
|
||||||
* 获取单个产品
|
* 获取单个产品
|
||||||
*/
|
*/
|
||||||
getProduct(where: Partial<Pick<UnifiedProductDTO, 'id' | 'sku'>>): Promise<UnifiedProductDTO>;
|
getProduct(id: string | number): Promise<UnifiedProductDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取产品列表
|
* 获取产品列表
|
||||||
|
|
@ -284,12 +308,12 @@ export interface ISiteAdapter {
|
||||||
/**
|
/**
|
||||||
* 更新产品
|
* 更新产品
|
||||||
*/
|
*/
|
||||||
updateProduct(where: Partial<Pick<UnifiedProductDTO, 'id' | 'sku'>>, data: Partial<UnifiedProductDTO>): Promise<boolean>;
|
updateProduct(id: string | number, data: Partial<UnifiedProductDTO>): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除产品
|
* 删除产品
|
||||||
*/
|
*/
|
||||||
deleteProduct(where: Partial<Pick<UnifiedProductDTO, 'id' | 'sku'>>): Promise<boolean>;
|
deleteProduct(id: string | number): Promise<boolean>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量处理产品
|
* 批量处理产品
|
||||||
|
|
@ -343,12 +367,12 @@ export interface ISiteAdapter {
|
||||||
/**
|
/**
|
||||||
* 更新评论
|
* 更新评论
|
||||||
*/
|
*/
|
||||||
updateReview(where: Partial<Pick<UnifiedReviewDTO, 'id'>>, data: UpdateReviewDTO): Promise<UnifiedReviewDTO>;
|
updateReview(id: number, data: UpdateReviewDTO): Promise<UnifiedReviewDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除评论
|
* 删除评论
|
||||||
*/
|
*/
|
||||||
deleteReview(where: Partial<Pick<UnifiedReviewDTO, 'id'>>): Promise<boolean>;
|
deleteReview(id: number): Promise<boolean>;
|
||||||
|
|
||||||
// ========== 订阅映射方法 ==========
|
// ========== 订阅映射方法 ==========
|
||||||
/**
|
/**
|
||||||
|
|
@ -466,7 +490,7 @@ export interface ISiteAdapter {
|
||||||
/**
|
/**
|
||||||
* 获取单个webhook
|
* 获取单个webhook
|
||||||
*/
|
*/
|
||||||
getWebhook(where: Partial<Pick<UnifiedWebhookDTO, 'id'>>): Promise<UnifiedWebhookDTO>;
|
getWebhook(id: string | number): Promise<UnifiedWebhookDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取webhooks列表
|
* 获取webhooks列表
|
||||||
|
|
@ -486,16 +510,16 @@ export interface ISiteAdapter {
|
||||||
/**
|
/**
|
||||||
* 更新webhook
|
* 更新webhook
|
||||||
*/
|
*/
|
||||||
updateWebhook(where: Partial<Pick<UnifiedWebhookDTO, 'id'>>, data: UpdateWebhookDTO): Promise<UnifiedWebhookDTO>;
|
updateWebhook(id: string | number, data: UpdateWebhookDTO): Promise<UnifiedWebhookDTO>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除webhook
|
* 删除webhook
|
||||||
*/
|
*/
|
||||||
deleteWebhook(where: Partial<Pick<UnifiedWebhookDTO, 'id'>>): Promise<boolean>;
|
deleteWebhook(id: string | number): Promise<boolean>;
|
||||||
|
|
||||||
// ========== 站点/其他方法 ==========
|
// ========== 站点/其他方法 ==========
|
||||||
/**
|
/**
|
||||||
* 获取站点链接列表
|
* 获取站点链接列表
|
||||||
*/
|
*/
|
||||||
getLinks(): Promise<Array<{ title: string, url: string }>>;
|
getLinks(): Promise<Array<{title: string, url: string}>>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue