UNPKG

@pisell/pisellos

Version:

一个可扩展的前端模块化SDK框架,支持插件系统

254 lines (253 loc) 8.96 kB
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[]; }