@pisell/pisellos
Version:
一个可扩展的前端模块化SDK框架,支持插件系统
254 lines (253 loc) • 8.96 kB
TypeScript
import { Module, PisellCore } from '../../../types';
import { BaseModule } from '../../../modules/BaseModule';
import { ProductData } from '../../../modules/Product/types';
import type { RouteDefinition } from '../../types';
import { ProductFormatter, ProductFormatterContext } from './types';
/**
* Products 模块 - 用于获取和管理完整的商品详细数据
* 相比 ProductList 模块,Products 会获取所有详细信息并缓存
*/
export declare class ProductsModule extends BaseModule implements Module {
protected defaultName: string;
protected defaultVersion: string;
private store;
private request;
private dbManager;
private logger;
private otherParams;
private productsPriceCache;
private readonly CACHE_MAX_DAYS;
private formatters;
private isPriceFormatterRegistered;
private productDataSource;
private pendingSyncMessages;
private syncTimer?;
constructor(name?: string, version?: string);
initialize(core: PisellCore, options: any): Promise<void>;
/**
* 记录信息日志
* @param title 日志标题
* @param metadata 日志元数据
*/
private logInfo;
/**
* 记录警告日志
* @param title 日志标题
* @param metadata 日志元数据
*/
private logWarning;
/**
* 记录错误日志
* @param title 日志标题
* @param metadata 日志元数据
*/
private logError;
/**
* 加载商品价格(原始方法,不带缓存)
* @private
*/
private loadProductsPrice;
/**
* 获取应用了价格的商品列表(带缓存)
* 使用日期作为缓存 key,同一天的商品价格会被缓存
* 缓存的是已经应用了价格的完整商品列表,避免重复转换
* @param schedule_date 日期
* @param extraContext 额外的上下文数据(可选,由 Server 层传入)
* @param options 可选参数
* @param options.changedIds 变更的商品 IDs,非空时仅对这些商品增量执行 prepare 并更新缓存
* @returns 应用了价格的商品列表
*/
getProductsWithPrice(schedule_date: string, extraContext?: Partial<ProductFormatterContext>, options?: {
changedIds?: number[];
}): Promise<ProductData[]>;
/**
* 准备带价格的商品数据(通过格式化器流程处理)
* @param schedule_date 日期
* @param extraContext 额外的上下文数据(可选)
* @param options 可选参数
* @param options.productIds 指定商品 IDs,仅处理这些商品;不传则处理全量
* @returns 处理后的商品列表
* @private
*/
private prepareProductsWithPrice;
/**
* 应用所有已注册的格式化器
* @param products 商品列表
* @param context 上下文信息
* @returns 格式化后的商品列表
* @private
*/
private applyFormatters;
/**
* 注册内置的价格格式化器
* 这个格式化器负责将价格数据应用到商品上
* @private
*/
private registerBuiltinPriceFormatter;
/**
* 注册商品格式化器
* 格式化器会按注册顺序依次执行(内置价格格式化器始终是第一个)
* @param formatter 格式化函数
* @param prepend 是否插入到队列开头(默认 false,追加到末尾)
* @example
* ```ts
* productsModule.registerFormatter((products, context) => {
* return products.map(p => ({
* ...p,
* custom_field: 'custom_value'
* }));
* });
* ```
*/
registerFormatter(formatter: ProductFormatter, prepend?: boolean): void;
/**
* 清空所有格式化器(包括内置价格格式化器)
* @param keepBuiltin 是否保留内置价格格式化器(默认 true)
*/
clearFormatters(keepBuiltin?: boolean): void;
/**
* 清理过期的价格缓存
* 当缓存数量超过限制时,删除最老的缓存
* @private
*/
private cleanExpiredPriceCache;
/**
* 清空商品价格缓存
* 可用于手动刷新价格数据
*/
clearPriceCache(): void;
/**
* 通过 ProductDataSource SSE 加载完整商品列表
*/
loadProductsByServer(): Promise<any>;
/**
* 纯请求方法:通过 HTTP 接口获取商品列表(无副作用,不触发事件、不写 IndexDB)
* @param params 查询参数
* @returns 商品列表
*/
private fetchProductsByHttp;
/**
* 加载完整商品列表通过接口(包含所有详细数据)
* 包含副作用:保存到 IndexDB + 触发 onProductsLoaded 事件
* @param params 查询参数
*/
loadProductsByServerHttp(params?: {
category_ids?: number[];
product_ids?: number[];
collection?: number | string[];
customer_id?: number;
cacheId?: string;
}): Promise<ProductData[]>;
/**
* 获取商品列表(深拷贝,供外部安全使用)
*/
getProducts(): Promise<ProductData[]>;
/**
* 内部获取商品列表的直接引用(无拷贝)
* 仅供内部 formatter 流程使用,因为 formatter 会创建新对象
*/
private getProductsRef;
/**
* 根据ID获取单个商品(从内存缓存)
* 使用 Map 快速查询,时间复杂度 O(1)
*/
getProductById(id: number): Promise<ProductData | undefined>;
/**
* 根据 ID 列表删除商品(用于 pubsub 同步删除场景)
* 同时更新 store.list、store.map、IndexDB 和价格缓存
*/
removeProductsByIds(ids: number[]): Promise<void>;
/**
* 重新从服务器加载全量商品列表并更新本地 store
* 用于 pubsub 同步 create / update / batch_update 场景
*/
refreshProducts(): Promise<ProductData[]>;
/**
* 清空缓存
*/
clear(): Promise<void>;
/**
* 从 IndexDB 加载商品数据
* @private
*/
private loadProductsFromIndexDB;
/**
* 保存商品数据到 IndexDB(平铺存储)
* @private
*/
private saveProductsToIndexDB;
/**
* 同步更新商品 Map 缓存
* 将 list 中的商品同步到 map,以 id 为 key
* @private
*/
private syncProductsMap;
/**
* 预加载模块数据(统一接口)
* 在模块注册后自动调用
*/
preload(): Promise<void>;
/**
* 初始化 ProductDataSource 实例
* 与 pubsub 订阅和数据获取分开,仅负责创建实例
*/
private initProductDataSource;
/**
* 初始化 pubsub 订阅,监听管理后台商品变更
* 仅负责订阅 product / product_quotation 频道,消息通过防抖合并后批量处理
* 数据获取由 loadProductsByServer 单独负责
*/
private setupProductSync;
/**
* 处理防抖后的同步消息批次
*
* product 模块:
* - operation === 'delete' → 本地删除
* - change_types 包含 price → 仅收集变更 IDs(不拉商品数据)
* - 有 body → body 完整数据直接覆盖本地
* - 其他 → SSE 增量拉取
*
* product_collection / product_category:
* - 按 relation_product_ids SSE 拉取受影响商品
*
* product_quotation:
* - 报价单变更影响范围大,直接清除价格缓存走全量重建
*
* 处理完成后 emit onProductsSyncCompleted(携带 changedIds),
* Server 层监听该事件后对变更商品增量执行 prepareProductsWithPrice 并更新缓存
*/
private processProductSyncMessages;
/**
* 通过 SSE 按 ids 增量拉取商品数据
* 请求 GET /shop/core/stream?type=product&ids={ids}
*/
private fetchProductsBySSE;
/**
* 将 body 完整数据直接覆盖到本地 store(不调用报价单接口)
* 已存在的 → 直接替换;不存在的 → 追加
* 同时更新 Map 缓存、IndexDB,触发 onProductsChanged
* 价格缓存由 processProductSyncMessages 末尾统一清除
*/
private applyBodyUpdatesToStore;
/**
* 将增量拉取的商品合并到 store
* 已存在的 → 替换;新的 → 追加
* 同时更新 store.map、IndexDB,触发 onProductsChanged
*/
private mergeProductsToStore;
/**
* 静默全量刷新:后台重新拉取全量 SSE 数据并更新本地
* 拿到完整数据后一次性替换 store,清除价格缓存,触发 onProductsSyncCompleted
* @returns 刷新后的商品列表
*/
silentRefresh(): Promise<ProductData[]>;
/**
* 销毁同步资源(取消 pubsub 订阅、清除定时器)
*/
destroyProductSync(): void;
/**
* 获取模块的路由定义
* Products 模块暂不提供路由,由 Server 层统一处理
*/
getRoutes(): RouteDefinition[];
}