import { BaseResponsiveProps } from "../../responsive/type.js"; import { WeighingValue } from "./components/weighing/types.js"; import { ResolveSelectionFlowSteps, ResolveSelectionFlowStepsContext, SelectionFlowBookingPriceQuote, SelectionFlowBookingPriceRequest, SelectionFlowBookingPriceService, SelectionFlowBookingPriceSnapshot, SelectionFlowBookingPriceState, SelectionFlowDraft, SelectionFlowModuleConfig, SelectionFlowModuleInput, SelectionFlowServices, SelectionFlowStepConfig, SelectionModuleType } from "./flow/types.js"; import { Dayjs } from "dayjs"; import { WeightUnitName } from "@pisell/utils"; //#region src/pro/skuDetailModal/types.d.ts type ChannelApplication = 'online-store' | 'pos' | 'wholesalebusiness' | 'kiosk'; type ProductType = 'physical' | 'virtual'; type DurationType = 'minutes' | 'hours' | 'days' | 'flexible'; type ResourceType = 'single' | 'multiple'; type RelationType = 'form'; type EventType = 'schedule_event'; type MaxParticipantsType = 'custom-limit' | 'unlimited'; interface TimeSlice { label: string; value: string; } interface DurationSlice { label: string; value: number; } interface MultiLanguageName { en?: string; 'zh-CN'?: string; 'zh-HK'?: string; original?: string; 'ja'?: string; 'pt'?: string; auto?: string; } interface MultiLanguageTitle { label: { type: 'i18n'; 'en-US': string; 'zh-CN': string; 'ja'?: string; 'pt'?: string; }; } interface SelectType { type: 'single' | 'multiple'; min: number; max: number; } interface Duration { type: DurationType; value: number; } interface CutOffTime { unit: number; unit_type: DurationType; future_day: number; type: 'advance'; ongoing: { type: 'before_end'; unit: number; }; } interface MachineCode { make_over: number; beforehand: number; limit_count: number; customer: number; send_action: string; hide_recharge: number; distributor_automatic: number; } interface Form { id: number; shop_id: number; title: string; navigation_display: number; button: string; describe: string; status: 'published' | 'draft'; resource_sort: number; code: string; type: 'manual' | 'auto'; version: number; setting: any; created_at: string; updated_at: string; } interface PartyroomPackage { type: 'product_all' | 'product_part'; } interface EventListItem { id: number; start_date?: string; start_time?: string; end_date?: string; end_time?: string; relation_id: number; number?: number; start_at?: string; end_at?: string; keys?: string; pax: number; type: EventType; pax_list: Record; } interface TimeConfig { keys: string; schedule_id: number; item_type: string; item_id: number; start_date: string; end_date: string; start_time: string; end_time: string; is_all: number; relation_type: RelationType; start_at: string; end_at: string; event_list: EventListItem[]; max_participants_type?: MaxParticipantsType; max_participants_limit?: number; is_blocked?: number; blocked_times?: any[]; order_event_count?: number; unique?: string; _extend?: { isMaxLimitRange: boolean; isDateRange: boolean; isCountRange: boolean; isUsable: boolean; }; } interface ResourceMetadata { combined_resource: any; } interface ResourceItem { id: number; main_field: string; sort: number; form_id: number; times: TimeConfig[]; capacity: number; combined_resource: any; resource_form_id: string | number; form_code: string; resourceType: ResourceType; children: any[]; metadata: ResourceMetadata; form_tag?: any; policy?: number; partyroom_package?: PartyroomPackage; status?: string; description?: string; media?: string; subtitle?: string; room_name?: string; labelText?: string; form_record_id?: number; item_type?: string; form_resource_sort?: number; form_title?: string; form?: Form; _extend?: { usableTime?: TimeConfig; }; usable?: boolean; label?: any; } interface ResourceTypeInfo { id: number; title: string; status: number; code: string; created_at: string; updated_at: string | null; type: ResourceType; optional_resource: number[]; default_resource: any[]; select_type: SelectType; resource_type_id: number; renderList?: ResourceItem[]; form_id?: number; renderListMaps?: Record; } interface ProductResource { resources: ResourceTypeInfo[]; } interface CapacityCustom { name: MultiLanguageName; min: number; max: number; id: string; } interface CapacityPackage {} interface Capacity { type: 'product' | 'package' | 'custom'; custom: CapacityCustom[]; package: CapacityPackage[]; } interface ProductDisplaySetting { kiosk: { use_display_mode: number; product_option_mode: any; product_option_mode_paging: any; product_bundle_mode: any; product_bundle_mode_paging: any; }; } interface ShelfProductData {} interface Category { id: number; name: string; icon: string; slug: string; sort: number; } interface Collection { id: number; title: string; cover: string; } interface ExtendData { duration: number | string; start_time: string; end_time?: string; start_date: string | Dayjs; end_date?: string | Dayjs; quantity: number; price: string; product_name: string; other: { bundle: any[]; key: number; option: any[]; product_id: number; product_variant_id: number; quantity: number; rowKey: number; session: any; unique: string; }; total: number; origin_total: number; startDate: string | Dayjs; endDate: string | Dayjs; capacity: Array<{ id: number; value: number; name: string; }>; resource: Record>; note?: string; holder_id?: Array; skuValue?: ExtendData['other']; weighing?: WeighingValue; metadata?: { product_add_schedule_time?: unknown; [key: string]: any; }; _skuValue?: { bundle: any[]; option: any[]; product_id: number; product_variant_id: number; }; priceOverride?: number; } interface TimeObj { timeSlices: TimeSlice[]; durationSlicesBasedOnTime: DurationSlice[]; } interface DataObj { timeObj: TimeObj; capacitys: Capacity; resourcesOrigin: ResourceTypeInfo[]; resources: ResourceTypeInfo[]; resourceMaps: Record; } interface DiscountItem { amount: number; type: 'discount_card' | 'discount_code' | 'discount_package'; discount: { resource_id: number; title: MultiLanguageTitle; original_amount: number; product_id: number; percent: string; }; num: number; } interface ProductData { id: number; extension_id: number; extension_type: string; shop_id: number; title: string; slug: string; status: 'published' | 'draft' | 'archived'; stock_quantity: number; sales_quantity: number; sum_stock: number; price: string; original_price: string; cost_price: string; cover: string; channel_application: ChannelApplication[]; is_track: number; over_sold: number; is_gst: number; code: string; production_code?: string; barcode: string; is_delivery: number; weight_unit: WeightUnitName; weight_value: string; type: ProductType; unit: string; sort: number; subtitle: string; minimum_markup_price: string; is_bundle: number; bundle_group_count: number; option_group_count: number; is_variant: number; variant_count: number; cut_off_time: CutOffTime; policy: number; machine_code: MachineCode; duration: Duration; product_resource: ProductResource; capacity: Capacity; product_display_setting: ProductDisplaySetting; shelf_product_datas: ShelfProductData[]; step_value: number; min_num_unit: number; schedules: any[]; is_charge_tax: number; base_price: string; variant: any[]; variant_group: any[]; category: Category[]; collection: Collection[]; product_id: number; _id: string; _key: number; _extend: ExtendData; new: number; currentDefaultTime: string; _data: DataObj; autoClose: boolean; _serviceKey: string; _holderKey: string; discount_list: DiscountItem[]; } type SkuDetailModalData = ProductData; interface SkuDetailModalProps { /** 确认回调;返回 false 或 Promise 时保留弹窗。 */ onConfirm?: (data: ProductData) => void | boolean | Promise; /** 删除回调 */ onRemove?: (productData: ProductData) => void; /** 关闭回调 */ onClose?: () => void; } interface SkuDetailModalRef { /** 打开弹窗 */ open: (data: ProductData | SkuDetailModalOpenParams) => Promise; /** 主动关闭弹窗,并终止尚未完成的详情加载。 */ close: () => void; } interface ExternalVariantProps { /** 是否开启自定义组合规格功能 */ isCustom?: boolean; /** 自定义组合规格函数 */ formatVariant?: (variant: any[]) => any[]; } interface ConfigProps { /** * POS 可完整初始化旧 BookingContext;Kiosk/H5 预约 Flow 默认关闭旧资源加载, * 避免与 UnifiedBookingSales 的 Availability/资源请求重复。 */ initializeFullBookingContext?: boolean; /** * POS 柜台允许员工选择容量已满(remaining=0)的日期/时间片。 * past / unavailable / conflict 仍禁用;Kiosk、H5 继续遵守全部限制。 */ allowUnavailableBookingSelection?: boolean; /** POS 柜台是否在真实资源旁展示并允许选择「无资源」。 */ allowNoResourceBookingSelection?: boolean; /** * 商品详情的展示平台,由页面模板显式传入。 * Kiosk 不能通过 phone variant 或屏幕宽度推断,因为真实手机也会使用同一种 Drawer。 */ presentationPlatform?: 'default' | 'kiosk' | 'pos'; /** * 提交前选择流程的自定义步骤。 * 只要传入数组就启用新流程;不传时保持现有 SkuDetailModal 行为。 * 空数组、空步骤、未知模块或不满足依赖顺序的配置由流程编译阶段阻断。 * 可用于加入购物车前和购物车预约行编辑;最终写入仍由 Host 负责。 */ steps?: readonly SelectionFlowStepConfig[]; /** * 根据完整商品详情为本次打开解析步骤。优先级高于同一配置中的 steps。 * 返回 null 时明确回到旧流程;每次打开只执行一次,不随日期水合重复执行。 */ resolveSteps?: ResolveSelectionFlowSteps; /** 页面是否将商品新建、action:add 强制选择和购物车编辑统一交给 Selection Flow。 */ enableProductSelectionFlowForCart?: boolean; /** @deprecated 使用 enableProductSelectionFlowForCart。 */ enableBookingSelectionFlowForCart?: boolean; /** * 显式解析预约智能报价的拆段粒度。它只用于“按 30/60 分钟累计报价”这类 * 商品;返回 undefined 时按完整 candidate 的开始时刻报价一次。 * 禁止把普通商品的 duration 直接当作报价粒度。 */ resolveBookingPriceDuration?: (context: { productData: ProductData; }) => { type: string; value: number | string; } | null | undefined; /** 固定弹窗展示形态;不传时继续按屏幕宽度响应 */ variant?: BaseResponsiveProps['variant']; /** * 规格选项每行最大列数;实际列数会根据选项容器宽度收缩。 * 不传时手机最多一列、其他设备最多两列。 */ selectorColumns?: number; /** 是否在规格选择区域上方展示商品封面、标题与副标题 */ isShowProductSummary?: boolean; /** * 是否启用 SKU Detail 的通用独立折叠区。 * 商品详情始终可使用;日期、时间等区域仅在对应 Flow module 存在时出现。 * 默认关闭,避免改变现有 SkuDetailModal 调用方的版式。 */ isShowCollapsibleSections?: boolean; /** 是否在手机版内容区展示称重模块;仅当前商品/规格需要称重时生效 */ isShowMobileWeighing?: boolean; /** 是否展示 Details / Select Bundle 步骤条与返回入口 */ isShowProcedureSteps?: boolean; /** 是否显示数量步进器 */ isShowStepper?: boolean; /** * 是否仅对预约/Session 门票商品隐藏数量步进器。 * KioskSale 的 H5 宿主使用该开关;普通零售商品仍保留数量选择。 */ hideQuantityForBookingProducts?: boolean; /** 是否显示备注 */ isShowNote?: boolean; /** 是否显示手动改价入口 */ isShowManualPriceChange?: boolean; /** 编辑态是否显示删除按钮;关闭时回退为取消按钮 */ isShowRemove?: boolean; /** 是否使用外部传递的 variant 数据,而不是组件内部从接口获取的数据。默认 false(使用接口数据) */ externalVariant?: ExternalVariantProps; /** 是否使用自定义数据覆盖接口字段 */ useCustomData?: boolean; /** 自定义数据,用于覆盖接口返回的特定字段,如 { price: 0, origin_price: 17 } */ customData?: Partial; /** 是否调用商品详情接口 */ isCallProductDetail?: boolean; /** 自定义取消按钮 */ onCancel?: () => void; /** 自定义确认按钮 */ onConfirm?: (data: ProductData) => void; /** 自定义移除按钮 */ onRemove?: (data: ProductData) => void; /** 自定义关闭按钮 */ onClose?: () => void; } interface SkuDetailModalOpenParams { id: number; date: string; is_eject?: 0 | 1; productData?: ProductData; /** create 模式的初始数量;未传时沿用商品/缓存默认值。 */ initialQuantity?: number; /** 加车前预约 Flow 的初始 cacheItem;选择态优先于详情接口默认值。 */ initialCacheItem?: ProductData; /** 仅作为 Holder 模块初始草稿,不预先写入 cacheItem。 */ initialHolderIds?: Array; /** 完整商品详情水合后、Selection Flow 编译前通知 Host 更新依赖数据。 */ onProductDataHydrated?: (context: { productData: ProductData; }) => void | Promise; /** Host 是否已准备好 time/resource/holder 所需的完整 BookingContext。 */ isBookingFlowContextPrepared?: boolean; /** Resolver 返回 null 或全部候选模块均不适用时,交还旧预约 Host。 */ onSelectionFlowNotApplicable?: (context: { productData: ProductData; reason: 'resolver_null' | 'booking_context_unavailable' | 'no_applicable_modules'; }) => boolean | void; /** Host 注入给 Selection Flow 的运行时服务,不参与商品详情接口参数。 */ selectionFlowServices?: SelectionFlowServices; skuDetailConfig?: ConfigProps; } //#endregion export { ConfigProps, ExtendData, ExternalVariantProps, ProductData, SkuDetailModalData, SkuDetailModalOpenParams, SkuDetailModalProps, SkuDetailModalRef };