@yorkjs/hive-biz 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hive-biz.esm.js +1 -1
- package/dist/hive-biz.esm.js.map +1 -1
- package/dist/hive-biz.esm.min.js +1 -1
- package/dist/hive-biz.esm.min.js.map +1 -1
- package/dist/hive-biz.js +1 -1
- package/dist/hive-biz.js.map +1 -1
- package/dist/hive-biz.min.js +1 -1
- package/dist/hive-biz.min.js.map +1 -1
- package/package.json +1 -1
- package/types/coupon/couponSelector.d.ts +1 -1
- package/types/coupon/couponUtil.d.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hive-biz.esm.min.js","sources":["../src/util/dataType.ts","../src/util/adjoinMartix.ts","../src/util/specAdjoinMartix.ts","../src/selector/specSelector.ts","../src/selector/constant.ts","../src/selector/productUtil.ts","../src/selector/customizationUtil.ts","../src/selector/comboUtil.ts","../src/selector/comboSpecSelector.ts","../src/selector/customSpecSelector.ts","../src/selector/childCustomSelector.ts","../src/coupon/constant.ts","../src/coupon/availableRepeat.ts","../src/coupon/couponUtil.ts","../src/coupon/couponSelector.ts"],"sourcesContent":["import {\n isNaN\n} from 'lodash-es'\n\n// 定义一个空字符串类型\ntype EmptyString = '' | ' '\n\n// 定义一个包含所有\"空\"值的联合类型\ntype EmptyValue = null | undefined | EmptyString | [] | Record<string, never> | typeof NaN\n\n// 空值: {}, [], '', ' ', null, undefined, NaN\nexport function isEmpty(value: any): value is EmptyValue {\n if (value == null\n || isNaN(value)\n ) {\n return true\n }\n let isEmptyValue = false\n const protoType = Object.prototype.toString.call(value)\n switch (protoType) {\n\n case '[object Object]':\n isEmptyValue = Object.keys(value).length === 0\n break\n\n case '[object Array]':\n isEmptyValue = value.length === 0\n break\n\n case '[object String]':\n if (value.trim().length === 0) {\n isEmptyValue = true\n }\n break\n\n default:\n break\n }\n\n return isEmptyValue\n}\n","import { fill } from 'lodash-es'\n\nexport default class AdjoinMatrix {\n vertex = [] // 顶点数组\n quantity = 0 // 矩阵长度\n adjoinArray = [] // 矩阵数组\n\n constructor(vertx) {\n this.vertex = vertx\n this.quantity = this.vertex.length\n this.adjoinArray = []\n this.init()\n }\n // 初始化数组\n init() {\n this.adjoinArray = fill(new Array(this.quantity * this.quantity), 0)\n }\n\n /*\n * @param id string\n * @param sides Array<string>\n * 传入一个顶点,和当前顶点可达的顶点数组,将对应位置设置权值\n */\n setAdjoinVertexs(id, sides, weight) {\n const pIndex = this.vertex.indexOf(id)\n sides.forEach((item, i) => {\n const index = this.vertex.indexOf(item)\n const cur = this.adjoinArray[pIndex * this.quantity + index]\n if (typeof cur !== 'number') { // specList.length > 3时,存在单边多权的情况\n this.adjoinArray[pIndex * this.quantity + index].push(weight)\n }\n else if (cur > 1) {\n this.adjoinArray[pIndex * this.quantity + index] = [cur, weight]\n }\n else {\n this.adjoinArray[pIndex * this.quantity + index] = weight\n }\n })\n }\n\n /*\n * @param id string\n * 传入顶点的值,获取该顶点的列\n */\n getVertexCol(id) {\n const index = this.vertex.indexOf(id)\n const col = []\n this.vertex.forEach((item, pIndex) => {\n col.push(this.adjoinArray[index + this.quantity * pIndex])\n })\n return col\n }\n\n /*\n * @param params Array<string>\n * 传入一个顶点数组,求出并集\n */\n getCollection(params) {\n const paramsVertex = params.map(id => this.getVertexCol(id))\n let collections = []\n paramsVertex.forEach((col, index) => {\n if (col.some(item => item !== 0)) {\n collections.push(params[index])\n }\n })\n return collections\n }\n\n /*\n * @param params Array<string>\n * 传入一个顶点数组,求出交集\n */\n getUnions(params) {\n const paramsVertex = params.map(id => this.getVertexCol(id))\n let unions = []\n this.vertex.forEach((type, index) => {\n const row = paramsVertex.map(col => col[index]).filter(t => t !== 1)\n if (this.isItemEqual(row)) {\n unions.push(type)\n }\n })\n return unions\n }\n\n /*\n * @param params\n * 传入一个交集行,判断内部是否互相相等\n */\n isItemEqual(params) {\n if (params.includes(0)) {\n return false\n }\n\n let weight = -1\n\n // 找出权值\n if (params.length) {\n params.some(t => {\n if (typeof t === 'number') {\n weight = t\n }\n return typeof t === 'number'\n })\n if (weight === -1) { // 都是多权边数组的情况\n return this.isArrayUnions(params)\n }\n }\n\n return params.every(t => {\n if (typeof t === 'number') {\n return t === weight\n } \n else {\n return t.includes(weight)\n }\n })\n }\n\n /*\n * @param params\n * 传入多个数组,判断是否有交集\n */\n isArrayUnions(params) {\n if (!params.length) {\n return false\n }\n return params[0].some(t => {\n return params.every(_t => _t.includes(t))\n })\n }\n}\n","import AdjoinMatrix from \"./adjoinMartix\"\n\nexport default class SpecAdjoinMatrix extends AdjoinMatrix {\n specList = []\n specCombinationList = []\n\n constructor(specList, specCombinationList) {\n // 使用 \"组索引_值\" 作为唯一顶点标识,避免不同组同名规格被当作同一顶点\n const vertices: string[] = []\n specList.forEach((group, gi) => {\n group.list.forEach(value => {\n vertices.push(`${gi}_${value}`)\n })\n })\n super(vertices)\n this.specList = specList\n\n this.specCombinationList = specCombinationList\n // 根据可选规格列表矩阵创建\n this.initSpec()\n // 同级顶点创建\n this.initSameLevel()\n }\n\n /**\n * 根据可选规格组合填写邻接矩阵的值\n */\n initSpec() {\n this.specCombinationList.forEach((item, index) => {\n // 将 SKU 规格按组索引映射为唯一标识\n const specs = item.specs.map((spec, gi) => `${gi}_${spec}`)\n this.fillInSpec(specs, index + 2) // 0用于互不相连,1用于同级,权级就从2开始\n })\n }\n // 填写同级点\n initSameLevel() {\n // 获得初始所有可选项\n const specsOption = this.getCollection(this.vertex)\n this.specList.forEach((group, gi) => {\n const params = []\n // 获取同级别顶点\n group.list.forEach(value => {\n const vertexId = `${gi}_${value}`\n if (specsOption.includes(vertexId)) {\n params.push(vertexId)\n }\n })\n // 同级点位创建\n this.fillInSpec(params, 1)\n })\n }\n /*\n * @params\n * 传入顶点数组(按组索引排列的已选规格值),查询出可选规格\n */\n getSpecsOptions(params) {\n let specOptionCanchoose: string[] = []\n if (params.some(Boolean)) {\n // 将 flat selectedSpecs 映射为 \"组索引_值\" 唯一标识再求交集\n const mappedParams = params.map((val, gi) => (val ? `${gi}_${val}` : '')).filter(Boolean)\n specOptionCanchoose = this.getUnions(mappedParams)\n }\n else {\n // 所有可选项\n specOptionCanchoose = this.getCollection(this.vertex)\n }\n return specOptionCanchoose\n }\n\n /*\n * @params\n * 填写邻接矩阵的值\n */\n fillInSpec(params, weight) {\n params.forEach(param => {\n this.setAdjoinVertexs(param, params, weight)\n })\n }\n}\n","import { find } from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\nimport SpecAdjoinMatrix from '../util/specAdjoinMartix'\n\nimport {\n ISpecList,\n ISkuCombination,\n IProductSpecItem,\n} from './type'\n\nexport interface ISpecSelectorOptions {\n /** 规格组列表,包含每组规格标题和可选值 */\n productSpecGroupList: ISpecList[]\n /** 格式化后的 sku 组合列表 */\n skuListAfter: ISkuCombination[]\n /** 活动规格列表,二维数组,与 productSpecGroupList 下标对应 */\n activitySpecList?: IProductSpecItem[][]\n}\n\nexport interface ISpecItemState {\n /** 规格值 */\n value: string\n /** 是否可选(未被禁用) */\n isEnabled: boolean\n /** 是否已选中 */\n isActive: boolean\n /** 是否是活动规格 */\n isActivitySpec: boolean\n}\n\nexport interface ISpecGroupState {\n /** 规格组标题 */\n title: string\n /** 该组下所有规格项的状态 */\n items: ISpecItemState[]\n}\n\nexport class SpecSelector {\n private productSpecGroupList: ISpecList[]\n private skuListAfter: ISkuCombination[]\n private activitySpecList: IProductSpecItem[][]\n private specAdjoinMatrix: InstanceType<typeof SpecAdjoinMatrix>\n\n constructor(options: ISpecSelectorOptions) {\n const { productSpecGroupList, skuListAfter, activitySpecList = [] } = options\n\n this.productSpecGroupList = productSpecGroupList\n this.skuListAfter = skuListAfter\n this.activitySpecList = activitySpecList\n this.specAdjoinMatrix = new SpecAdjoinMatrix(productSpecGroupList, skuListAfter)\n }\n\n /**\n * 判断某个规格值是否是活动规格\n * @param listIndex 规格组下标\n * @param value 规格值\n */\n isActivitySpec(listIndex: number, value: string): boolean {\n if (isEmpty(this.activitySpecList)) {\n return false\n }\n\n return !!find(this.activitySpecList[listIndex], item => item.name === value)\n }\n\n /**\n * 根据当前已选规格,获取所有规格组的渲染状态\n * @param selectedSpecs 当前已选规格值数组\n */\n getSpecGroupStateList(selectedSpecs: string[]): ISpecGroupState[] {\n const optionSpecs = this.specAdjoinMatrix.getSpecsOptions(selectedSpecs)\n\n return this.productSpecGroupList.map(({ title, list }, listIndex) => {\n const items: ISpecItemState[] = list.map(value => {\n // 使用 \"组索引_值\" 唯一标识检查可选性,避免跨组同名规格误匹配\n const isEnabled = optionSpecs.indexOf(`${listIndex}_${value}`) !== -1\n // 按组索引检查是否选中,避免跨组同名规格误匹配\n const isActive = selectedSpecs[listIndex] === value\n\n const isActivitySpec = this.isActivitySpec(listIndex, value)\n\n return {\n value,\n isEnabled,\n isActive,\n isActivitySpec,\n }\n })\n\n return { title, items }\n })\n }\n\n /**\n * 根据当前已选规格,获取可选规格值列表(扁平数组)\n * @param selectedSpecs 当前已选规格值数组\n */\n getOptionSpecs(selectedSpecs: string[]): string[] {\n return this.specAdjoinMatrix.getSpecsOptions(selectedSpecs)\n }\n\n /**\n * 处理规格选择/取消选择,返回新的已选规格数组\n * @param isEnabled 当前规格是否可选\n * @param value 被点击的规格值\n * @param groupIndex 规格组下标\n * @param selectedSpecs 当前已选规格值数组\n */\n toggleSpec(\n isEnabled: boolean,\n value: string,\n groupIndex: number,\n selectedSpecs: string[],\n ): string[] {\n if (!isEnabled) {\n return selectedSpecs\n }\n\n const newSelectedSpecs = [...selectedSpecs]\n const currentGroupList = this.productSpecGroupList[groupIndex]?.list ?? []\n\n if (newSelectedSpecs.indexOf(value) !== -1) {\n // 已选中 → 取消选中\n newSelectedSpecs[groupIndex] = ''\n }\n else {\n // 未选中 → 选中,同时清除同组内原来的选中项\n currentGroupList.forEach(item => {\n const idx = newSelectedSpecs.indexOf(item)\n if (idx !== -1) {\n newSelectedSpecs[idx] = ''\n }\n })\n newSelectedSpecs[groupIndex] = value\n }\n\n return newSelectedSpecs\n }\n\n /**\n * 根据当前已选规格找到匹配的 sku 组合\n * @param selectedSpecs 当前已选规格值数组\n */\n findMatchedSku(selectedSpecs: string[]): ISkuCombination | undefined {\n const validSelected = selectedSpecs.filter(Boolean)\n const groupCount = this.productSpecGroupList.length\n\n if (validSelected.length !== groupCount) {\n return undefined\n }\n\n return this.skuListAfter.find(sku =>\n validSelected.every(spec => sku.specs.includes(spec))\n )\n }\n\n /**\n * 判断规格是否已全部选完\n * @param selectedSpecs 当前已选规格值数组\n */\n isAllSpecSelected(selectedSpecs: string[]): boolean {\n const groupCount = this.productSpecGroupList.length\n return selectedSpecs.filter(spec => !isEmpty(spec)).length === groupCount\n }\n}\n","export const VALUE_UNDEFINED = -1\n\nexport const ENTITY_BOOL_YES = 1\nexport const ENTITY_BOOL_NO = 2\n\n// 无(第三方使用)\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_NONE = 1\n// 全部 sku\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_ALL = 2\n// 部分 sku\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_PART = 3\n// 某一个 sku\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_ONE = 4\n\n\nexport const SKU_STOCK_COUNT_UNLIMITED = 10000000\n\n// 商品规格\nexport const MALL_PRODUCT_SPEC_TYPE_SINGLE = 1\nexport const MALL_PRODUCT_SPEC_TYPE_MULTIPLE = 2\n\n// 商城商品 sku(原来企服系统里的商品sku),sku_id 传商城 sku ID\nexport const ORDER_EXTERNAL_SKU_TYPE_MALL = 0\n// 促销活动 sku,sku_id 传促销活动 sku ID\nexport const ORDER_EXTERNAL_SKU_TYPE_MARKETING_PROMOTION_ACTIVITY = 1\n\n// 商品组合\nexport const PRODUCT_COMBO_TYPE_SINGLE = 1\nexport const PRODUCT_COMBO_TYPE_MULTIPLE = 2\n\n// 添加购物车,是否要弹对话框\nexport const PRODUCT_SELECT_TYPE_DIRECT = 1\nexport const PRODUCT_SELECT_TYPE_DIALOG = 2\n\n// 店铺类型\nexport const SHOP_TYPE_DISTRIBUTOR = 1\nexport const SHOP_TYPE_PROMOTER = 2\nexport const SHOP_TYPE_MAHUA = 3\n\n// 做法计数类型\nexport const CUSTOMIZATION_COUNT_TYPE_KIND = 1\nexport const CUSTOMIZATION_COUNT_TYPE_QUANTITY = 2\n\n// 免费\nexport const CUSTOMIZATION_ITEM_INCREASE_TYPE_FREE = 1\n// 固定加价\nexport const CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED = 2\n\nexport const CHAGNE_TYPE_DECREASE = 'decrease'\nexport const CHAGNE_TYPE_INCREASE = 'increase'\nexport const CHAGNE_TYPE_EDIT = 'edit'\n\n// 商品类型\nexport const PRODUCT_STATUS_ALL = -1 // 全部\nexport const PRODUCT_STATUS_ONLINE = 1 // 上架\nexport const PRODUCT_STATUS_OFFLINE = 2 // 下架\n","import {\n find,\n findIndex,\n} from \"lodash-es\"\n\nimport {\n moneyToDisplay\n} from '@yorkjs/hive'\n\nimport {\n ENTITY_BOOL_NO,\n ENTITY_BOOL_YES,\n SHOP_TYPE_MAHUA,\n PRODUCT_STATUS_ONLINE,\n PRODUCT_COMBO_TYPE_MULTIPLE,\n PRODUCT_SELECT_TYPE_DIALOG,\n VALUE_UNDEFINED,\n PRODUCT_SELECT_TYPE_DIRECT,\n} from \"./constant\"\n\nimport {\n ISku,\n IFormatSku,\n IProductSpecGroup,\n IProductSpecItem,\n\n ICartListItem,\n IFindProductCart,\n\n ISpecList,\n ISkuCombination,\n ISpecObj,\n IImage,\n ISkuComboChildItem,\n ISimpleProduct,\n IProductPriceRange,\n IExternalSku,\n IProductPromotionActivitySaleInfoItem,\n} from \"./type\"\nimport { isEmpty } from \"../util/dataType\"\n\n// 合并 sku\nexport function formatSkuWithPromotionActivitySaleInfoItem(\n sku: ISku,\n promotionActivitySaleInfoItem: IProductPromotionActivitySaleInfoItem,\n): IFormatSku {\n const newSku: IFormatSku = {\n ...sku,\n id: promotionActivitySaleInfoItem.activity_sku_id,\n\n origin_sku_id: sku.id,\n is_promotion_activity: true,\n is_set_activity_price: false,\n }\n\n if (promotionActivitySaleInfoItem.sale_price !== VALUE_UNDEFINED\n && promotionActivitySaleInfoItem.sale_price !== sku.sale_price\n ) {\n // 新的原价则设置为老的 sku 的售价\n newSku.original_price = sku.sale_price\n newSku.sale_price = promotionActivitySaleInfoItem.sale_price\n newSku.is_set_activity_price = true\n }\n\n if (promotionActivitySaleInfoItem.stock_count !== VALUE_UNDEFINED) {\n newSku.stock_count = promotionActivitySaleInfoItem.stock_count\n }\n\n return newSku\n}\n\n// 格式化组合商品 children skuList 列表\nexport function formatProductComboChildrenSkuList(\n skuList: IFormatSku[],\n children: ISkuComboChildItem[]\n) {\n const newSkuList: IFormatSku[] = []\n\n children.forEach(function (childItem) {\n const {\n combo_sku,\n min_count,\n max_count,\n } = childItem\n\n const sku = find(skuList, skuItem => skuItem.id === combo_sku.id)\n if (!sku) {\n return\n }\n\n const newItem: IFormatSku = {\n ...sku,\n }\n\n if (min_count > 0) {\n newItem.per_order_min_limit = min_count\n }\n\n if (max_count > 0) {\n newItem.per_order_max_limit = max_count\n }\n\n newSkuList.push(newItem)\n })\n\n return newSkuList\n}\n\n// 格式化 sku\nexport function formatProductSku(\n sku: ISku,\n) {\n return {\n ...sku,\n origin_sku_id: sku.id,\n is_promotion_activity: false,\n is_set_activity_price: false,\n }\n}\n\n// 格式化商品 skuList 列表\nexport function formatProductSkuList(\n skuList: ISku[],\n promotionActivitySaleInfoList?: IProductPromotionActivitySaleInfoItem[],\n isSelfActivity?: boolean,\n): IFormatSku[] {\n if (promotionActivitySaleInfoList) {\n return formatProductActivitySkuList(skuList, promotionActivitySaleInfoList, isSelfActivity)\n }\n\n return skuList.map(sku => {\n return formatProductSku(sku)\n })\n}\n\n// 格式化活动商品 skuList 列表\nfunction formatProductActivitySkuList(\n skuList: ISku[],\n promotionActivitySaleInfoList: IProductPromotionActivitySaleInfoItem[],\n isSelfActivity?: boolean,\n): IFormatSku[] {\n\n // 1.1 活动为商家自建\n if (isSelfActivity) {\n return skuList.map(sku => {\n const promotionActivitySaleInfoItem: IProductPromotionActivitySaleInfoItem | undefined = find(promotionActivitySaleInfoList, item => item.mall_sku_id === sku.id)\n\n let newSku: IFormatSku = formatProductSku(sku)\n\n if (promotionActivitySaleInfoItem) {\n newSku = formatSkuWithPromotionActivitySaleInfoItem(sku, promotionActivitySaleInfoItem)\n }\n\n return newSku\n })\n }\n\n // 1.2 活动非商家自建\n return promotionActivitySaleInfoList.map(saleInfoItem => {\n const skuItem: ISku | undefined = find(skuList, item => item.id === saleInfoItem.mall_sku_id)\n\n return formatSkuWithPromotionActivitySaleInfoItem(skuItem!, saleInfoItem)\n })\n}\n\n// 格式化 productSpecGroupList 规格\nexport function formatProductSpecGroupList(\n skuList: IFormatSku[],\n productSpecGroupList: IProductSpecGroup[],\n useActivityFlag?: boolean,\n): IProductSpecGroup[] {\n const newProductSpecGroupList: IProductSpecGroup[] = []\n\n productSpecGroupList.forEach((groupItem, groupIndex) => {\n const {\n items,\n } = groupItem\n\n const newGroup: IProductSpecGroup = {\n ...groupItem,\n items: [],\n }\n\n skuList.forEach(item => {\n const itemIds = item.item_ids\n\n const findItemIndex = findIndex(items, function (value: IProductSpecItem) {\n return value.id === itemIds[groupIndex]\n })\n\n if (findItemIndex === -1) {\n return\n }\n\n // 判断规格值是否已经存在,不存在则添加\n const specValueItem = items[findItemIndex]\n const specValueIndex = findIndex(newGroup.items, function (value: IProductSpecItem) {\n return value.id === specValueItem.id\n })\n\n if (specValueIndex === -1) {\n if (item.is_promotion_activity && useActivityFlag) {\n specValueItem.is_promotion_activity = true\n }\n\n newGroup.items.push(specValueItem)\n }\n })\n\n newProductSpecGroupList.push(newGroup)\n })\n\n return newProductSpecGroupList\n}\n\n// 格式化 specList\nexport function formatSpecList(\n productSpecGroupList: IProductSpecGroup[],\n): ISpecList[] {\n return productSpecGroupList.map(groupItem => ({\n title: groupItem.spec.name,\n list: groupItem.items.map(item => item.name),\n }))\n}\n\n// 格式化 formatSkuListAfter\nexport function formatSkuListAfter(\n skuList: IFormatSku[],\n specObj: ISpecObj,\n negativeStockSaleEnabled?: boolean,\n): ISkuCombination[] {\n const skuListAfter: ISkuCombination[] = []\n\n skuList.map(item => {\n if (negativeStockSaleEnabled || item.stock_count > 0) {\n skuListAfter.push({\n ...item,\n specs: item.item_ids.map(id => specObj[id]),\n })\n }\n })\n\n return skuListAfter\n}\n\n// 格式化 specObj\nexport function formatSpecObj(\n productSpecGroupList: IProductSpecGroup[],\n): ISpecObj {\n const specObj = {}\n\n productSpecGroupList.forEach(groupItem => {\n groupItem.items.forEach(item => {\n specObj[item.id] = item.name\n })\n })\n\n return specObj\n}\n\n// 获取 specImage\nexport function getSpecImage(\n productSpecGroupList: IProductSpecGroup[],\n productCover: IImage,\n): IImage {\n let specImage = productCover\n\n if (productSpecGroupList.length !== 0) {\n if (productSpecGroupList[0].items[0]?.image !== undefined) {\n specImage = productSpecGroupList[0].items[0].image\n }\n }\n\n return specImage\n}\n\n// 获取活动规格列表\nexport function getActivitySpecList(\n productSpecGroupList: IProductSpecGroup[],\n): IProductSpecItem[][] {\n const activitySpecList: IProductSpecItem[][] = []\n\n productSpecGroupList.forEach(groupItem => {\n const activitySpecItemList: IProductSpecItem[] = []\n\n groupItem.items.forEach(item => {\n if (item.is_promotion_activity) {\n activitySpecItemList.push(item)\n }\n })\n\n activitySpecList.push(activitySpecItemList)\n })\n\n return activitySpecList\n}\n\n// 购买文字\nexport function formatProductBuyText(\n product: ISimpleProduct,\n): string {\n const {\n combo_type,\n select_type,\n } = product\n\n const isMultiComboType = combo_type === PRODUCT_COMBO_TYPE_MULTIPLE\n const isDialogSelect = select_type === PRODUCT_SELECT_TYPE_DIALOG\n\n if (isMultiComboType) {\n return '选套餐'\n }\n\n // 组合商品\n if (isDialogSelect) {\n return '选规格'\n }\n\n return '加入购物车'\n}\n\n// 商品是否在销售中\nexport function checkProductOnSale(productStatus: number, hasStock: number): boolean {\n return productStatus === PRODUCT_STATUS_ONLINE && hasStock === ENTITY_BOOL_YES\n}\n\n// 列表中商品是否使用加减按钮\nexport function checkUseReducePlusBtn(\n product: ISimpleProduct,\n) {\n const {\n combo_type,\n select_type,\n } = product\n\n const isMultiComboType = combo_type === PRODUCT_COMBO_TYPE_MULTIPLE\n const isDirectSelect = select_type === PRODUCT_SELECT_TYPE_DIRECT\n\n // 组合商品\n if (isMultiComboType) {\n return false\n }\n\n return isDirectSelect\n}\n\nexport function formatProductStatus(\n productStatus: number,\n hasStock: number,\n skuDeleted: number = ENTITY_BOOL_NO\n): string {\n if (productStatus === PRODUCT_STATUS_ONLINE && skuDeleted === ENTITY_BOOL_NO) {\n return hasStock === ENTITY_BOOL_YES ? '销售中' : '已售罄'\n }\n\n return '已下架'\n}\n\n\nexport function formatSkuPrice(skuList: ISku[]): string {\n const salePriceArr = skuList.map(item => item.sale_price)\n const minPrice = Math.min(...salePriceArr) || 0\n const maxPrice = Math.max(...salePriceArr) || 0\n\n if (minPrice === maxPrice) {\n return `¥${moneyToDisplay(minPrice)}`\n }\n\n return `¥${moneyToDisplay(minPrice)} ~ ¥${moneyToDisplay(maxPrice)}`\n}\n\n\nexport function formatPriceRange(priceRange: IProductPriceRange): string {\n const {\n end_price,\n start_price,\n } = priceRange\n\n if (start_price === end_price) {\n return `¥${moneyToDisplay(start_price)}`\n }\n\n return `¥${moneyToDisplay(start_price)}~${moneyToDisplay(end_price)}`\n}\n\nexport function formatSkuListStockCount(list: ISku[]): number {\n let sum = 0\n list.forEach(item => {\n sum += item.stock_count\n })\n return sum\n}\n\n// 注意有可能是活动商品\nexport function findProductCartList(\n cartList: ICartListItem[],\n product: ISimpleProduct,\n activityProductId?: number\n): IFindProductCart {\n const findCartList: IFindProductCart = {\n cartList: [],\n cartCount: 0,\n }\n\n const productId = product.id\n const productCode = product.code\n\n cartList.forEach(cartItem => {\n const cartItemProduct = cartItem.product\n const cartItemExternalProduct = cartItem.external_product\n\n // 过滤掉错误商品\n if (cartItem.error) {\n return\n }\n\n if (activityProductId) {\n if (cartItemExternalProduct?.id === activityProductId) {\n findCartList.cartList.push(cartItem)\n findCartList.cartCount += cartItem.cart.count\n }\n }\n else {\n if (productId) {\n if (cartItemProduct.id === productId) {\n findCartList.cartList.push(cartItem)\n findCartList.cartCount += cartItem.cart.count\n }\n }\n else if (cartItemProduct.code === productCode) {\n findCartList.cartList.push(cartItem)\n findCartList.cartCount += cartItem.cart.count\n }\n }\n })\n\n return findCartList\n}\n\n// 合并 sku\nexport function formatWithExternalSku(sku: ISku, externalSku?: IExternalSku): ISku {\n if (isEmpty(externalSku)) {\n return sku\n }\n\n const newSku = {\n ...sku,\n ...externalSku,\n }\n\n if (externalSku.sale_price === -1) {\n newSku.sale_price = sku.sale_price\n }\n else {\n // 新的原价则设置为老的 sku 的售价\n newSku.original_price = sku.sale_price\n }\n\n if (externalSku.stock_count === -1) {\n newSku.stock_count = sku.stock_count\n }\n\n return newSku\n}\n","import {\n pick,\n find,\n every,\n filter,\n cloneDeep,\n flattenDeep,\n} from 'lodash-es'\n\nimport { plusNumber, timesNumber } from '@yorkjs/hive'\n\nimport {\n ICartListItem,\n ICustomizationItem,\n IOrderSkuCustomizationItem,\n IProduct,\n IProductCustomizationGroupItem,\n IProductCustomizationGroupItemView,\n IProductCustomizationItemView,\n IProductSelectedCustomizationItem,\n IPromotionActivityProduct,\n ISubmitSelectedCustomizationItem\n} from './type'\n\nimport {\n ENTITY_BOOL_NO,\n ENTITY_BOOL_YES,\n CUSTOMIZATION_COUNT_TYPE_KIND,\n CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED,\n CUSTOMIZATION_COUNT_TYPE_QUANTITY,\n} from './constant'\nimport { isEmpty } from '../util/dataType'\n\ninterface ISelectedCustomizationItem {\n id: number\n count: number\n}\n\nfunction pickSubmitCustomizationItem(customizationItemList: ISelectedCustomizationItem): ISubmitSelectedCustomizationItem {\n return pick(customizationItemList, ['id', 'count'])\n}\n\nexport function getSubmitCustomizationItemList(customizationItemList: ISelectedCustomizationItem[]): ISubmitSelectedCustomizationItem[] {\n const submitItemList = customizationItemList.map(item => {\n return pickSubmitCustomizationItem(item)\n })\n\n return submitItemList\n}\n\n// 格式化二维选中的组合商品\nexport function getSubmitCustomizationItemListArr(customizationItemList: ISelectedCustomizationItem[][]): ISubmitSelectedCustomizationItem[] {\n return getSubmitCustomizationItemList(flattenDeep(customizationItemList))\n}\n\n// 计算做法选中的价格\nexport function calculateSelectedCustomizationPrice(\n customizationGroupList: IProductCustomizationGroupItemView[],\n customizationItemList: IProductSelectedCustomizationItem[][]\n): number {\n\n let price = 0\n const selectedCustomizationItemList = flattenDeep(customizationItemList)\n\n customizationGroupList.forEach((groupItem) => {\n const {\n items,\n } = groupItem\n\n items.forEach(item => {\n const {\n id,\n customization_item,\n } = item\n\n const {\n increase_type,\n increase_sale_price,\n } = customization_item\n\n const selectedItem = find(selectedCustomizationItemList, selectedItem => selectedItem.id === id)\n if (selectedItem && increase_type === CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED) {\n price += timesNumber(increase_sale_price, selectedItem.count)\n }\n })\n })\n\n return price\n}\n\nexport function formatCustomizationPrice(\n price: number,\n customizationGroupList: IProductCustomizationGroupItemView[],\n customizationItemList?: IProductSelectedCustomizationItem[][]\n): number {\n if (price === -1) {\n return price\n }\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(customizationGroupList, customizationItemList || [])\n\n return plusNumber(price, selectedCustomizationPrice)\n}\n\n// 比较做法值列表是否相等, 数组长度一致,且 id 和 count 一致\nexport function checkCustomizationItemListEqual(selectCustomizationItemList: IProductSelectedCustomizationItem[], cartCustomizationItemList: IOrderSkuCustomizationItem[]) {\n return selectCustomizationItemList.length === cartCustomizationItemList.length &&\n every(selectCustomizationItemList, item => {\n return find(cartCustomizationItemList, cartCustomizationItem => {\n // 做法值的 id 和 count 一致才是相等\n return cartCustomizationItem.id === item.id && cartCustomizationItem.count === item.count\n })\n })\n}\n\n // 格式化做法数据\nexport function formatCustomizationGroupList(\n customizationGroupList: IProductCustomizationGroupItem[]\n): IProductCustomizationGroupItemView[] {\n return customizationGroupList.map(group => {\n const newGroup: IProductCustomizationGroupItemView = {\n ...group,\n items: [],\n }\n\n newGroup.items = group.items.map(item => {\n const {\n count,\n selected,\n } = item\n\n // 初始化 selected_count 为 0\n const newItem: IProductCustomizationItemView = {\n ...item,\n selected_count: 0,\n }\n\n // 选中了,则设置 selected_count 为 count\n if (selected === ENTITY_BOOL_YES) {\n newItem.selected_count = count\n }\n\n return newItem\n })\n\n return newGroup\n })\n}\n\n// 初始化选中的做法值列表\nexport function formatInitCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[]\n): IProductSelectedCustomizationItem[][] {\n return formatSelectedCustomizationItemList(customizationGroupList)\n}\n\nexport function formatSelectedCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[]\n): IProductSelectedCustomizationItem[][] {\n const customizationItemList: IProductSelectedCustomizationItem[][] = []\n\n customizationGroupList.forEach(customizationGroupItem => {\n const customizationItems: IProductSelectedCustomizationItem[] = []\n\n const {\n items,\n customization,\n } = customizationGroupItem\n\n items.forEach(item => {\n const {\n id,\n count,\n selected,\n selected_count,\n customization_item,\n } = item\n\n if (selected === ENTITY_BOOL_YES) {\n customizationItems.push({\n id,\n name: customization_item.name,\n // NOTE: 初始可能没有 selected_count,设置为 count\n count: selected_count || count,\n count_type: customization.count_type,\n })\n }\n })\n\n customizationItemList.push(customizationItems)\n })\n\n return customizationItemList\n}\n\n// 回填做法值列表\nexport function reconstructCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[],\n selectedCustomizationItemList: IProductSelectedCustomizationItem[]\n): {\n isValid: boolean\n customizationGroupList: IProductCustomizationGroupItemView[],\n selectedCustomizationItemList: IProductSelectedCustomizationItem[][]\n} {\n const newSelectedCustomizationItemList: IProductSelectedCustomizationItem[][] = []\n\n // NOTE: 复制一份,避免修改原数据\n const copyCustomizationGroupList = cloneDeep(customizationGroupList)\n const newCustomizationGroupList: IProductCustomizationGroupItemView[] = copyCustomizationGroupList.map(group => {\n const groupItems = cloneDeep(group.items)\n const customization = group.customization\n\n const selectedItems: IProductSelectedCustomizationItem[] = []\n\n groupItems.forEach(item => {\n const {\n id,\n count,\n selected,\n selectable,\n customization_item,\n } = item\n\n const selectedItem = find(selectedCustomizationItemList, selectedItem => selectedItem.id === item.id)\n if (selectedItem) {\n selectedItems.push(selectedItem)\n\n item.selected_count = selectedItem.count\n item.selected = ENTITY_BOOL_YES\n }\n else {\n if (selectable === ENTITY_BOOL_NO) {\n // 固定选中的,加到选择列表中\n if (selected === ENTITY_BOOL_YES) {\n selectedItems.push({\n id,\n name: customization_item.name,\n count,\n count_type: customization.count_type,\n })\n }\n }\n else {\n // 不在选中列表中,强制设置为未选中\n item.selected_count = 0\n item.selected = ENTITY_BOOL_NO\n }\n }\n })\n\n newSelectedCustomizationItemList.push(selectedItems)\n\n return {\n ...group,\n items: groupItems,\n }\n })\n\n // 校验回填的是否正确\n const res = checkCustomizationItemList(newCustomizationGroupList, newSelectedCustomizationItemList)\n\n return {\n isValid: res.isValid,\n customizationGroupList: newCustomizationGroupList,\n selectedCustomizationItemList: newSelectedCustomizationItemList,\n }\n}\n\n// 校验选中的做法值列表\nexport function checkCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[],\n customizationItemList: IProductSelectedCustomizationItem[][]\n): {\n isValid: boolean\n errMsg: string\n} {\n let isValid = true\n let errMsg = ''\n\n customizationGroupList.forEach((customizationGroupItem, index) => {\n const {\n customization,\n min_count,\n max_count,\n } = customizationGroupItem\n\n const {\n count_type,\n } = customization\n\n const countTypeUnit = formatCountTypeUnit(count_type)\n\n // 有报错,直接返回\n if (!isValid) {\n return\n }\n\n let customizationCount = 0\n customizationItemList[index].forEach(item => {\n customizationCount += item.count\n })\n\n // 分组被选中商品个数不足\n if (customizationCount < min_count) {\n isValid = false\n errMsg = `【${customization.name}】:至少选择 ${min_count} ${countTypeUnit}`\n\n // 单选\n if (max_count === 1) {\n errMsg = `请选择【${customization.name}】`\n }\n\n return\n }\n\n if (customizationCount > max_count) {\n isValid = false\n errMsg = `【${customization.name}】:最多选择 ${max_count} ${countTypeUnit}`\n return\n }\n })\n\n return {\n isValid,\n errMsg,\n }\n}\n\nexport function formatCountTypeUnit(countType: number) {\n if (countType === CUSTOMIZATION_COUNT_TYPE_KIND) {\n return '种'\n }\n return '份'\n}\n\nexport const checkCustomizationItemIsUseSelectCount = (customizationItem: IProductCustomizationItemView) => {\n const {\n selectable,\n min_count,\n max_count,\n } = customizationItem\n\n // 是否需要选择份数\n return selectable === ENTITY_BOOL_YES &&\n min_count !== max_count &&\n max_count > 1\n}\n\nexport const checkCustomizationItemCanPlusCount = (customizationGroupItem: IProductCustomizationGroupItemView) => {\n const {\n max_count,\n } = customizationGroupItem\n\n // 检测数量是否超过最大值\n let selectCount = 0\n customizationGroupItem.items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.selected_count\n }\n })\n\n return max_count === -1 || selectCount < max_count\n}\n\nexport const checkCustomizationItemIsFixedSelected = (customizationItem: IProductCustomizationItemView) => {\n const {\n selected,\n selectable,\n } = customizationItem\n\n // 是否固定选中\n return selectable === ENTITY_BOOL_NO &&\n selected === ENTITY_BOOL_YES\n}\n\n// 是否禁用选中\nexport const checkCustomizationItemIsDisabledSelected = (customizationItem: IProductCustomizationItemView) => {\n const {\n selected,\n selectable,\n } = customizationItem\n\n // 是否禁用选中\n return selectable === ENTITY_BOOL_NO &&\n selected === ENTITY_BOOL_NO\n}\n\n// 获取当前商品,对应 skuId 在购物车中的数据\nexport function findCustomizationSkuCartItem(\n item: {\n skuId?: number\n product: IProduct\n promotionActivityProduct?: IPromotionActivityProduct\n customizationItemList?: IProductSelectedCustomizationItem[][]\n },\n cartList: ICartListItem[]\n): ICartListItem | undefined {\n if (isEmpty(cartList)) {\n return\n }\n\n const {\n skuId,\n product,\n promotionActivityProduct,\n customizationItemList,\n } = item\n\n const findCartItem = find(cartList, (cartItem: ICartListItem) => {\n const productId = product.id\n const productCode = product.code\n\n const cartItemProduct = cartItem.product\n const cartItemExternalProduct = cartItem.external_product\n\n // 1. 判断购物车商品是否是当前商品\n let isProductFind = false\n // 优先使用活动商品 id 进行比较\n if (cartItemExternalProduct) {\n isProductFind = cartItemExternalProduct.id === promotionActivityProduct?.id\n }\n else {\n isProductFind = productId ?\n cartItemProduct.id === productId :\n cartItemProduct.code === productCode\n }\n\n if (!isProductFind) {\n return false\n }\n\n // 2. 如果没有 skuId,则匹配到商品即可\n if (!skuId) {\n return true\n }\n\n const cartItemSku = cartItem.sku\n const cartItemSkuExternal = cartItem.external_sku\n // 3. 判断 sku_id 是否一样,优先使用活动 sku_id\n const isSkuEqual = cartItemSkuExternal ?\n cartItemSkuExternal.id === skuId :\n cartItemSku.id === skuId\n\n if (!isSkuEqual) {\n return false\n }\n\n const cartItemCustomizationItemList = cartItem.product_customization_item_list || []\n // 4. 如果做法值列表为空,则匹配到商品 + sku_id 即可\n if (isEmpty(customizationItemList) && isEmpty(cartItemCustomizationItemList)) {\n return true\n }\n\n const flattenCustomizationItemList = flattenDeep(customizationItemList)\n\n // 5. 比较做法值列表是否相等, 数组长度一致,且 id 和 count 一致\n return checkCustomizationItemListEqual(flattenCustomizationItemList, cartItemCustomizationItemList)\n })\n\n return findCartItem ? cloneDeep(findCartItem) : undefined\n}\n\nexport function genereateCartProductCustomizationItemList(\n submitSelectedCustomizationItemList: ISubmitSelectedCustomizationItem[] | undefined,\n productCustomizationGroupList: IProductCustomizationGroupItem[] | undefined\n): {\n orderSkuCustomizationItemList: IOrderSkuCustomizationItem[]\n customizationSalePrice: number\n} {\n // 根据选中的做法,生成购物车中的商品做法\n const orderSkuCustomizationItemList: IOrderSkuCustomizationItem[] = []\n let customizationSalePrice = 0\n\n if (isEmpty(submitSelectedCustomizationItemList) || isEmpty(productCustomizationGroupList)) {\n return {\n orderSkuCustomizationItemList,\n customizationSalePrice,\n }\n }\n\n productCustomizationGroupList.forEach(group => {\n const groupItems = group.items\n const customization = group.customization\n\n groupItems.forEach((item: ICustomizationItem) => {\n const {\n id,\n customization_item,\n } = item\n\n const selectedItem: ISubmitSelectedCustomizationItem | undefined = find(submitSelectedCustomizationItemList,\n (selectedItem: ISubmitSelectedCustomizationItem) => selectedItem.id === id)\n\n if (selectedItem) {\n orderSkuCustomizationItemList.push({\n ...selectedItem,\n name: customization_item.name,\n count_type: customization.count_type,\n })\n\n if (customization_item.increase_type === CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED) {\n customizationSalePrice = plusNumber(customizationSalePrice, timesNumber(customization_item.increase_sale_price, selectedItem.count))\n }\n }\n })\n })\n\n return {\n orderSkuCustomizationItemList,\n customizationSalePrice,\n }\n}\n\nexport function formatCustomizationGroupItemSelectTips(customizationGroupItem: IProductCustomizationGroupItemView): string {\n const { items, min_count, max_count, customization } = customizationGroupItem\n const selectTips: string[] = []\n const countTypeUnit = formatCountTypeUnit(customization.count_type)\n\n if (min_count === max_count) {\n selectTips.push(`请选择${min_count}${countTypeUnit}`)\n } else {\n if (min_count > 0) {\n selectTips.push(`至少选择${min_count}${countTypeUnit}`)\n }\n if (max_count > 0) {\n selectTips.push(`最多可选${max_count}${countTypeUnit}`)\n }\n }\n\n let selectedCount = 0\n items.forEach(item => {\n selectedCount += item.selected_count\n })\n\n if (selectedCount > 0) {\n selectTips.push(`已选${selectedCount}${countTypeUnit}`)\n }\n\n return selectTips.join(',')\n}\n\nexport function handleCustomizationGroupItemSelectedChange(\n group: IProductCustomizationGroupItemView,\n itemSelected: number,\n itemIndex: number,\n onChange?: (item: IProductCustomizationGroupItemView) => void\n) {\n const newGroup: IProductCustomizationGroupItemView = cloneDeep(group)\n const customizationItem = newGroup.items[itemIndex]\n\n const {\n items: groupItems,\n max_count\n } = newGroup\n\n const isSingleSelect = max_count === 1\n\n // 统计已选中的个数\n let selectedCount = 0\n groupItems.forEach((item, index) => {\n const {\n count,\n selected,\n selected_count\n } = item\n\n if (index === itemIndex) {\n if (itemSelected === ENTITY_BOOL_YES) {\n selectedCount += count\n }\n return\n }\n if (selected === ENTITY_BOOL_YES) {\n selectedCount += selected_count\n }\n })\n\n if (!isSingleSelect && selectedCount > max_count) {\n return\n }\n\n if (isSingleSelect) {\n newGroup.items.forEach((item, index) => {\n if (index !== itemIndex) {\n item.selected = ENTITY_BOOL_NO\n item.selected_count = 0\n }\n })\n }\n\n customizationItem.selected = itemSelected\n customizationItem.selected_count = itemSelected === ENTITY_BOOL_YES\n ? customizationItem.count\n : 0\n\n onChange?.(newGroup)\n}\n\nexport function handleCustomizationGroupItemCountChange(\n group: IProductCustomizationGroupItemView,\n count: number,\n index: number,\n onChange?: (item: IProductCustomizationGroupItemView) => void\n) {\n const newGroup: IProductCustomizationGroupItemView = cloneDeep(group)\n const customizationItem = newGroup.items[index]\n\n customizationItem.selected_count = count\n customizationItem.selected = count === 0\n ? ENTITY_BOOL_NO\n : ENTITY_BOOL_YES\n\n onChange?.(newGroup)\n}\n\nexport function handleCustomizationItemCountChange(\n customizationItem: IProductCustomizationItemView,\n customizationGroupItem: IProductCustomizationGroupItemView,\n newCount: number,\n onCountChange?: (count: number) => void\n) {\n const { items } = customizationGroupItem\n\n const {\n min_count,\n max_count,\n customization_item,\n } = customizationItem\n\n const itemMinCount = min_count\n const itemMaxCount = max_count\n const groupMaxCount = customizationGroupItem.max_count\n\n // 计算已选数量\n let selectCount = 0\n items.forEach(item => {\n if (item.customization_item.id === customization_item.id) {\n selectCount += newCount\n }\n else {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.selected_count\n }\n }\n })\n\n if (groupMaxCount !== -1 && selectCount > groupMaxCount) {\n return\n }\n if (itemMaxCount !== -1 && newCount > itemMaxCount) {\n return\n }\n\n if (newCount < itemMinCount) {\n onCountChange?.(0)\n return\n }\n\n onCountChange?.(newCount)\n}\n\nexport function handleCustomizationItemToggleSelected(\n customizationItem: IProductCustomizationItemView,\n onSelectedChange?: (selected: number) => void\n) {\n const {\n selected,\n selectable\n } = customizationItem\n\n if (selectable !== ENTITY_BOOL_YES) {\n return\n }\n\n const newSelected = selected === ENTITY_BOOL_YES\n ? ENTITY_BOOL_NO\n : ENTITY_BOOL_YES\n\n onSelectedChange?.(newSelected)\n}\n\nexport function formatSkuNameWithCustomization(\n skuName?: string,\n customizationItemList?: IOrderSkuCustomizationItem[]\n): string {\n const kindItemList = filter(customizationItemList || [], item => item.count_type === CUSTOMIZATION_COUNT_TYPE_KIND)\n\n if (isEmpty(kindItemList)) {\n return skuName || ''\n }\n\n const kindItemName = kindItemList.map(item => item.name).join('、')\n\n return skuName ? `${skuName}、${kindItemName}` : kindItemName\n}\n\n// 格式化做法中数量类型的做法\nexport function formatCustomizationCountType(\n customizationItemList?: IOrderSkuCustomizationItem[]\n): string {\n const itemList = filter(customizationItemList || [], item => item.count_type !== CUSTOMIZATION_COUNT_TYPE_KIND)\n if (isEmpty(itemList)) {\n return ''\n }\n\n return itemList.map(item => `${item.name}x${item.count}`).join('、')\n}\n\nexport function formatCustomizationInfo(\n customizationItemList?: IOrderSkuCustomizationItem[]\n): string {\n\n let customizationInfos: string[] = []\n\n if (isEmpty(customizationItemList)) {\n return ''\n }\n\n customizationItemList.map(item => {\n const {\n name,\n count,\n count_type,\n } = item\n\n const isCountTypeQuantity = count_type === CUSTOMIZATION_COUNT_TYPE_QUANTITY\n\n customizationInfos.push(`${name}${isCountTypeQuantity ? ` x${count}` : ''}`)\n })\n\n return customizationInfos.join('、')\n}\n","import {\n pick,\n find,\n every,\n cloneDeep,\n flattenDeep,\n} from 'lodash-es'\n\nimport * as hive from '@yorkjs/hive'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n ISkuComboChildItem,\n ICartSkuComboItem,\n ISelectSkuComboItem,\n ISkuComboGroupItem,\n ISkuComboGroupList,\n ISkuComboItem,\n ISubmitSelectSkuComboItem,\n ISkuPopupSbumitData,\n ISkuPopupSubmitData\n} from './type'\n\nimport {\n formatCustomizationCountType,\n formatSkuNameWithCustomization,\n checkCustomizationItemListEqual,\n getSubmitCustomizationItemList\n} from './customizationUtil'\n\nimport {\n ENTITY_BOOL_NO,\n ENTITY_BOOL_YES,\n SKU_COMBO_ITEM_COMBO_SKU_TYPE_NONE,\n SKU_STOCK_COUNT_UNLIMITED,\n PRODUCT_SELECT_TYPE_DIALOG,\n} from './constant'\n\nfunction pickSubmitComboItem(skuComboItemList: ISelectSkuComboItem): ISubmitSelectSkuComboItem {\n const item: ISubmitSelectSkuComboItem = pick(skuComboItemList, ['id', 'count', 'combo_sku_id', 'combo_product_customization_item_list'])\n\n const comboProductCustomizationItemList = item.combo_product_customization_item_list\n if (comboProductCustomizationItemList) {\n item.combo_product_customization_item_list = getSubmitCustomizationItemList(comboProductCustomizationItemList)\n }\n\n return item\n}\n\nexport function getSubmitComboItemList(skuComboItemList: ISelectSkuComboItem[]): ISubmitSelectSkuComboItem[] {\n const comboItemList = skuComboItemList.map(item => {\n return pickSubmitComboItem(item)\n })\n\n return comboItemList\n}\n\n// 格式化二维选中的组合商品\nexport function getSubmitComboItemListArr(skuComboItemList: ISelectSkuComboItem[][]): ISubmitSelectSkuComboItem[] {\n return getSubmitComboItemList(flattenDeep(skuComboItemList))\n}\n\n// 计算做法选中的价格\nexport function calculateSelectedComboPrice(\n skuComboGroupList: ISkuComboGroupItem[],\n skuComboItemList: ISelectSkuComboItem[][]\n): number {\n\n let price = 0\n const selectedComboItemList = flattenDeep(skuComboItemList)\n\n skuComboGroupList.forEach((groupItem) => {\n const {\n items,\n } = groupItem\n\n items.forEach(item => {\n const {\n id,\n increase_sale_price,\n } = item\n\n const selectedItem = find(selectedComboItemList, selectedItem => selectedItem.id === id)\n if (selectedItem && increase_sale_price > 0) {\n price += hive.timesNumber(increase_sale_price, selectedItem.count)\n }\n })\n })\n\n return price\n}\n\nexport function formatComboPrice(price: number, skuComboGroupList: ISkuComboGroupItem[], skuComboItemList?: ISelectSkuComboItem[][]): number {\n if (price === -1) {\n return price\n }\n\n const selectedCustomizationPrice = calculateSelectedComboPrice(skuComboGroupList, skuComboItemList || [])\n\n return hive.plusNumber(price, selectedCustomizationPrice)\n}\n\n// 5. 比较套餐值列表是否相等, 数组长度一致,且 id 和 count 一致\nexport function checkSkuComboItemListEqual(\n skuComboItemList: ISelectSkuComboItem[],\n cartItemSkuComboItemList: ICartSkuComboItem[]\n): boolean {\n return skuComboItemList.length === cartItemSkuComboItemList.length &&\n every(skuComboItemList, item => {\n return find(cartItemSkuComboItemList, cartItemComboItem => {\n // 做法值的 id 和 count 不一致,不匹配\n if (cartItemComboItem.id !== item.id || cartItemComboItem.count !== item.count) {\n return false\n }\n\n // 套餐值的 combo_sku_id 不一致,不匹配\n if (cartItemComboItem.combo_sku_id !== item.combo_sku_id) {\n return false\n }\n\n // 做法值的 combo_product_customization_item_list 不一致,不匹配\n const cartItemCustomizationItemList = cartItemComboItem.combo_product_customization_item_list || []\n const customizationItemList = item.combo_product_customization_item_list || []\n\n // 做法值列表都为空,匹配到商品 + sku_id 即可\n if (isEmpty(customizationItemList) && isEmpty(cartItemCustomizationItemList)) {\n return true\n }\n\n return checkCustomizationItemListEqual(customizationItemList, cartItemCustomizationItemList)\n })\n })\n}\n\n\nexport function formatSkuComboItemName(item: ICartSkuComboItem) {\n const {\n name,\n combo_sku_name,\n combo_product_customization_item_list\n } = item\n\n let skuName = name\n\n if (combo_product_customization_item_list) {\n const comboSkuName = formatSkuNameWithCustomization(combo_sku_name, combo_product_customization_item_list)\n skuName = comboSkuName ? `${name}(${comboSkuName})` : name\n\n const countTypeName = formatCustomizationCountType(combo_product_customization_item_list)\n if (countTypeName) {\n skuName = `${skuName}、${countTypeName}`\n }\n }\n\n return skuName\n}\n\nexport function formatSkuComboItemList(skuComboItemList: ICartSkuComboItem[]) {\n if (isEmpty(skuComboItemList)) {\n return ''\n }\n\n const skuNameList = skuComboItemList.map(item => formatSkuComboItemName(item))\n\n return skuNameList.join('+')\n}\n\n// 判断本组是否可以增加数量\nexport function checkComboGroupItemCanPlusCount(comboGroupItem: ISkuComboGroupItem): boolean {\n const {\n items,\n max_count,\n } = comboGroupItem\n\n // 检测数量是否超过最大值\n let selectCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n })\n\n return max_count === -1 || selectCount < max_count\n}\n\n// 判断是否可以改变选择框的状态\nexport function checkComboGroupItemIsCanChangeSelectCheckbox(comboGroupItem: ISkuComboGroupItem, selected: number): boolean {\n\n const {\n items,\n min_count,\n max_count\n } = comboGroupItem\n\n // 统计已选中的个数\n let selectedCount = 0\n items.forEach((item, _) => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectedCount++\n }\n })\n\n if (selected === ENTITY_BOOL_NO) {\n // 至少一个\n if (min_count === 1 && selectedCount <= 1) {\n return false\n }\n }\n else {\n // 如果是多选\n if (max_count > 1) {\n // 如果选中已达上限,则不能选中\n if (selectedCount >= max_count) {\n return false\n }\n }\n }\n\n return true\n}\n\nexport function checkComboItemIsFixedSelect(comboItem: ISkuComboItem): boolean {\n const {\n selected,\n selectable,\n } = comboItem\n\n return selected === ENTITY_BOOL_YES && selectable === ENTITY_BOOL_NO\n}\n\n// 判断是否使用选择框\nexport function checkComboItemIsUseSelectCheckbox(comboItem: ISkuComboItem): boolean {\n const {\n selectable,\n } = comboItem\n\n if (selectable === ENTITY_BOOL_NO) {\n return false\n }\n\n if (checkHasChildren(comboItem)) {\n return false\n }\n\n if (checkComboItemIsUseSelectCount(comboItem)) {\n return false\n }\n\n return true\n}\n\nexport function checkHasChildren(comboItem: ISkuComboItem): boolean {\n const {\n children,\n } = comboItem\n\n // 是否是定制\n return !isEmpty(children)\n}\n\n\nexport function checkComboItemIsUseSelectCount(comboItem: ISkuComboItem): boolean {\n const {\n min_count,\n max_count,\n } = comboItem\n\n // 是否需要选择份数\n return min_count !== max_count && max_count > 1\n}\n\n// 是否使用弹框选择商品\nexport function checkComboItemIsUseSelectSkuDialog(comboItem: ISkuComboItem) {\n const {\n combo_product,\n } = comboItem\n\n return combo_product?.select_type === PRODUCT_SELECT_TYPE_DIALOG\n}\n\n\nexport function formatComboSkuAndCustomizationName(comboItem: ISkuComboItem): string {\n const {\n combo_sku,\n combo_customization_item_list,\n } = comboItem\n\n if (isEmpty(combo_sku)) {\n return ''\n }\n\n let skuName = formatSkuNameWithCustomization(combo_sku.name, flattenDeep(combo_customization_item_list))\n\n const countTypeName = formatCustomizationCountType(flattenDeep(combo_customization_item_list))\n if (countTypeName) {\n skuName = `${skuName}、${countTypeName}`\n }\n\n return skuName\n}\n\n// 判断本组是否可以增加数量\nexport function checkItemCanPlusCount(comboGroupItem: ISkuComboGroupItem, comboItem: ISkuComboItem): boolean {\n const {\n selected,\n count,\n max_count,\n } = comboItem\n\n const canGroupPlus = checkComboGroupItemCanPlusCount(comboGroupItem)\n\n if (!canGroupPlus || selected === ENTITY_BOOL_NO) {\n return canGroupPlus\n }\n\n return count < max_count\n}\n\nexport function formatIncreaseSalePrice(comboItem: ISkuComboItem): string {\n const {\n increase_sale_price,\n } = comboItem\n\n return increase_sale_price > 0 ? `¥${hive.formatAmount(increase_sale_price, '')}` : ''\n}\n\n// 判断本项是否可以减少数量\nexport function checkItemCanMinusCount(comboGroupItem: ISkuComboGroupItem, comboItem: ISkuComboItem): boolean {\n const {\n count,\n min_count,\n } = comboItem\n\n const isFixedItem = checkComboItemIsFixedSelect(comboItem)\n const canGroupMinus = checkGroupCanMinusCount(comboGroupItem)\n\n if (!isFixedItem) {\n return canGroupMinus\n }\n\n return count > min_count\n}\n\n// 判断本组是否可以减少数量\nexport function checkGroupCanMinusCount(comboGroupItem: ISkuComboGroupItem): boolean {\n const {\n items,\n } = comboGroupItem\n\n // 检测数量是否超过最大值\n let selectCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n })\n\n return selectCount > 0\n}\n\n// 判断固定选中的是否需要选规格\nexport function checkIsFixedSelectNeedSelectSku(comboItem: ISkuComboItem): boolean {\n const {\n selected,\n selectable,\n } = comboItem\n\n if (selectable === ENTITY_BOOL_YES || selected === ENTITY_BOOL_NO) {\n return false\n }\n\n return checkComboItemIsUseSelectSkuDialog(comboItem)\n}\n\n// 判断是否使用选规格按钮\nexport function checkIsUseSelectSkuBtn(comboItem: ISkuComboItem) {\n const {\n combo_sku,\n combo_product,\n } = comboItem\n\n if (combo_product?.select_type !== PRODUCT_SELECT_TYPE_DIALOG) {\n return false\n }\n\n if (combo_sku) {\n return false\n }\n\n return true\n}\n\nexport function getSkuComboItemGroup(\n skuComboItemList: ICartSkuComboItem[]\n): ISkuComboGroupList[] {\n // 以 combo_group_name 分组\n const groupMap: Record<string, ICartSkuComboItem[]> = {}\n\n skuComboItemList.forEach((skuComboItem) => {\n const {\n combo_group_name\n } = skuComboItem\n\n const groupItem = groupMap[combo_group_name]\n if (groupItem) {\n groupItem.push(skuComboItem)\n }\n else {\n groupMap[combo_group_name] = [skuComboItem]\n }\n })\n\n return Object.keys(groupMap).map((comboGroupName) => {\n const list = groupMap[comboGroupName]\n\n return {\n comboGroupName,\n list\n }\n })\n}\n\n\n/** 将购物车数据回填到 comboGroupList */\nexport function reconstructComboGroupList(\n comboGroupList: ISkuComboGroupItem[],\n skuComboItemList?: ICartSkuComboItem[]\n): ISkuComboGroupItem[] {\n if (isEmpty(skuComboItemList)) {\n return comboGroupList\n }\n\n return comboGroupList.map(comboGroupItem => {\n const newItems = comboGroupItem.items.map(item => {\n const findComboItem = find(\n skuComboItemList,\n skuComboItem => skuComboItem.id === item.id\n )\n\n if (!findComboItem) {\n if (item.selectable === ENTITY_BOOL_YES) {\n item.selected = ENTITY_BOOL_NO\n }\n return item\n }\n\n const { children, combo_product } = item\n\n if (!isEmpty(children)) {\n children!.forEach((child: ISkuComboChildItem) => {\n if (child.combo_sku.id === findComboItem.combo_sku_id) {\n child.selected = ENTITY_BOOL_YES\n child.count = findComboItem.count\n }\n else {\n child.selected = ENTITY_BOOL_NO\n }\n })\n return item\n }\n\n if (combo_product) {\n if (findComboItem.combo_sku_id) {\n item.combo_sku = {\n id: findComboItem.combo_sku_id,\n name: findComboItem.combo_sku_name!,\n stock_count: item.combo_sku?.stock_count ?? SKU_STOCK_COUNT_UNLIMITED,\n }\n }\n\n if (findComboItem.combo_product_customization_item_list) {\n item.combo_customization_item_list = [\n findComboItem.combo_product_customization_item_list as any,\n ]\n }\n }\n\n item.count = findComboItem.count\n item.selected = ENTITY_BOOL_YES\n\n return item\n })\n\n return { ...comboGroupItem, items: newItems }\n })\n}\n\n/** 格式化当前选中的 skuComboItemList(二维数组) */\nexport function formatSelectSkuComboItemList(\n comboGroupList: ISkuComboGroupItem[]\n): ISelectSkuComboItem[][] {\n return comboGroupList.map(comboGroupItem => {\n const skuComboItems: ISelectSkuComboItem[] = []\n const comboGroupName = comboGroupItem.name\n\n comboGroupItem.items.forEach(item => {\n const {\n id,\n name,\n count,\n selected,\n children,\n combo_sku,\n combo_sku_type,\n combo_customization_item_list,\n } = item\n\n // 1. 有 children(定制商品),优先处理\n if (!isEmpty(children)) {\n const childItem: ISkuComboChildItem | undefined = find(\n children,\n (c: ISkuComboChildItem) => c.selected === ENTITY_BOOL_YES\n )\n\n if (childItem) {\n skuComboItems.push({\n id,\n name: `${name}(${childItem.name})`,\n combo_group_name: comboGroupName,\n combo_sku_id: childItem.combo_sku.id,\n count: childItem.count,\n })\n }\n return\n }\n\n // 未选中,跳过\n if (selected === ENTITY_BOOL_NO) {\n return\n }\n\n // 2. 无 SKU 类型的品牌店铺商品\n if (combo_sku_type === SKU_COMBO_ITEM_COMBO_SKU_TYPE_NONE) {\n skuComboItems.push({\n id,\n name,\n count,\n combo_group_name: comboGroupName,\n })\n return\n }\n\n // 3. 普通商品(有 combo_sku)\n if (combo_sku) {\n const selectItem: ISelectSkuComboItem = {\n id,\n name,\n count,\n combo_sku_id: combo_sku.id,\n combo_sku_name: combo_sku.name,\n combo_group_name: comboGroupName,\n }\n\n if (combo_customization_item_list) {\n selectItem.combo_product_customization_item_list = flattenDeep(\n combo_customization_item_list\n )\n }\n\n skuComboItems.push(selectItem)\n }\n })\n\n return skuComboItems\n })\n}\n\n/** 校验 comboGroupList 选中是否合法,合法返回 '',否则返回错误信息 */\nexport function validateComboGroupList(\n comboGroupList: ISkuComboGroupItem[],\n skuComboItemList?: ISelectSkuComboItem[][]\n): string {\n let isValid = true\n let errMsg = ''\n\n if (isEmpty(skuComboItemList)) {\n skuComboItemList = formatSelectSkuComboItemList(comboGroupList)\n }\n\n comboGroupList.forEach((comboGroupItem: ISkuComboGroupItem, groupIndex: number) => {\n if (!isValid) {\n return\n }\n\n const { items, min_count, max_count } = comboGroupItem\n const comboGroupName = comboGroupItem.name\n\n // 1. 逐个校验 item 选中状态\n items.forEach((item: ISkuComboItem, index: number) => {\n if (!isValid) {\n return\n }\n\n const { count, min_count: itemMinCount, selected, children, combo_sku, combo_product } = item\n\n if (selected === ENTITY_BOOL_NO) {\n return\n }\n\n // 有 children:必须选中一个定制子项\n if (!isEmpty(children)) {\n const childItem: ISkuComboChildItem | undefined = find(\n children,\n (c: ISkuComboChildItem) => c.selected === ENTITY_BOOL_YES\n )\n if (isEmpty(childItem)) {\n isValid = false\n errMsg = `【${comboGroupName}】:第${index + 1}个商品,请选择定制项`\n }\n return\n }\n\n // 有 combo_product 但未选规格\n if (combo_product && isEmpty(combo_sku)) {\n isValid = false\n errMsg = `【${comboGroupName}】:第${index + 1}个商品,请选择规格`\n return\n }\n\n // 数量不足本商品最小值\n if (count < itemMinCount) {\n isValid = false\n errMsg = `【${comboGroupName}】:第${index + 1}个商品,至少选择 ${itemMinCount} 件`\n }\n })\n\n if (!isValid) {\n return\n }\n\n // 2. 校验分组内总选中数量\n let skuComboCount = 0\n skuComboItemList[groupIndex]?.forEach(item => {\n skuComboCount += item.count\n })\n\n if (skuComboCount < min_count) {\n isValid = false\n errMsg = `【${comboGroupName}】:至少选择 ${min_count} 件商品`\n return\n }\n\n if (skuComboCount > max_count) {\n isValid = false\n errMsg = `【${comboGroupName}】:最多选择 ${max_count} 件商品`\n }\n })\n\n return errMsg\n}\n\nexport function formatComboGroupItemSelectTips(comboGroupItem: ISkuComboGroupItem) {\n const {\n items,\n repeatable,\n min_count,\n max_count,\n } = comboGroupItem\n\n const isAllSelectableNo = every(items, item => {\n return item.selectable === ENTITY_BOOL_NO\n })\n\n if (isAllSelectableNo) {\n return ''\n }\n\n const selectTips: string[] = []\n\n if (min_count === max_count) {\n selectTips.push(`请选择${min_count}项`)\n }\n else {\n if (min_count > 0) {\n selectTips.push(`至少选择${min_count}项`)\n }\n\n if (max_count > 0) {\n selectTips.push(`最多可选${max_count}项`)\n }\n }\n\n if (repeatable === ENTITY_BOOL_YES) {\n selectTips.push('可重复选')\n }\n\n // 当前已选数量\n let selectedCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectedCount += item.count\n }\n })\n\n if (selectedCount > 0) {\n selectTips.push(`已选${selectedCount}`)\n }\n\n return selectTips.join(',')\n}\n\nexport function generateCartSkuComboItemList(\n skuComboItemList: ISelectSkuComboItem[][] | undefined\n): ICartSkuComboItem[] {\n if (isEmpty(skuComboItemList)) {\n return []\n }\n\n // 将二维数组扁平化\n const flattenComboItemList = flattenDeep(skuComboItemList) as ISelectSkuComboItem[]\n\n // 直接转换为 ICartSkuComboItem[]\n const cartSkuComboItemList: ICartSkuComboItem[] = flattenComboItemList.map(item => {\n const cartItem: ICartSkuComboItem = {\n id: item.id,\n name: item.name,\n count: item.count,\n combo_group_name: item.combo_group_name,\n }\n\n // 如果有选中的规格,添加规格信息\n if (item.combo_sku_id) {\n cartItem.combo_sku_id = item.combo_sku_id\n }\n\n // 如果有规格名称\n if (item.combo_sku_name) {\n cartItem.combo_sku_name = item.combo_sku_name\n }\n\n // 如果有做法加料,添加做法信息\n if (!isEmpty(item.combo_product_customization_item_list)) {\n cartItem.combo_product_customization_item_list = item.combo_product_customization_item_list.map(customizationItem => ({\n id: customizationItem.id,\n name: customizationItem.name,\n count: customizationItem.count,\n count_type: customizationItem.count_type,\n }))\n }\n\n return cartItem\n })\n\n return cartSkuComboItemList\n}\n\nexport function handleSelectComboSkuSubmit(\n data: ISkuPopupSubmitData,\n isComboChild: boolean,\n onComboChildChange?: (data: ISkuPopupSubmitData) => void,\n onComboSkuChange?: (data: ISkuPopupSubmitData) => void\n) {\n if (isComboChild) {\n onComboChildChange?.(data)\n return\n }\n onComboSkuChange?.(data)\n}\n\nexport function setComboItemCountChange(\n comboGroupItem: ISkuComboGroupItem,\n comboItem: ISkuComboItem,\n count: number,\n onCountChange?: (count: number) => void\n) {\n const { items } = comboGroupItem\n const itemMinCount = comboItem.min_count\n const itemMaxCount = comboItem.max_count\n const groupMaxCount = comboGroupItem.max_count\n const isFixedItem = checkComboItemIsFixedSelect(comboItem)\n\n let selectCount = 0\n items.forEach(item => {\n if (item.id === comboItem.id) {\n selectCount += count\n }\n else {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n }\n })\n\n if (groupMaxCount !== -1 && selectCount > groupMaxCount) {\n return\n }\n if (itemMaxCount !== -1 && count > itemMaxCount) {\n return\n }\n if (count < 0 || selectCount < 0) {\n return\n }\n if (isFixedItem && count < itemMinCount) {\n return\n }\n\n onCountChange?.(count)\n}\n\nexport function handleComboItemCountChange(\n comboGroupItem: ISkuComboGroupItem,\n count: number,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem)\n const comboItem = newComboGroupItem.items[index]\n\n comboItem.count = count\n comboItem.selected = count === 0 ? ENTITY_BOOL_NO : ENTITY_BOOL_YES\n\n onChange?.(newComboGroupItem)\n}\n\nexport function handleComboGroupItemChildChange(\n comboGroupItem1: ISkuComboGroupItem,\n data: ISkuPopupSbumitData,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem1)\n\n const { sku, count } = data\n const skuId = sku.id\n const comboItem = newComboGroupItem.items[index]\n\n comboItem.children!.forEach(item => {\n if (item.combo_sku.id === skuId) {\n item.selected = ENTITY_BOOL_YES\n item.count = count\n }\n else {\n item.selected = ENTITY_BOOL_NO\n }\n })\n\n comboItem.selected = ENTITY_BOOL_YES\n\n onChange?.(newComboGroupItem)\n}\n\n\nexport function handleComboGroupItemSelected(\n comboGroupItem: ISkuComboGroupItem,\n selected: number,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem)\n\n const comboItem = newComboGroupItem.items[index]\n const { items, min_count, max_count } = newComboGroupItem\n\n let selectedCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectedCount++\n }\n })\n\n if (selected === ENTITY_BOOL_NO) {\n if (min_count === 1 && selectedCount <= 1) {\n onChange?.(newComboGroupItem)\n return\n }\n } else {\n if (max_count === 1) {\n newComboGroupItem.items.forEach((item, itemIndex) => {\n if (itemIndex !== index) {\n item.selected = ENTITY_BOOL_NO\n }\n })\n }\n else {\n if (selectedCount >= max_count) {\n onChange?.(newComboGroupItem)\n return\n }\n }\n }\n\n comboItem.selected = selected\n\n onChange?.(newComboGroupItem)\n}\n\nexport function handleComboGroupItemComboSkuChange(\n comboGroupItem: ISkuComboGroupItem,\n data: ISkuPopupSbumitData,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem)\n\n const { sku, customizationItemList } = data\n const comboItem = newComboGroupItem.items[index]\n const isUseSelectCount = checkComboItemIsUseSelectCount(comboItem)\n\n comboItem.combo_sku = {\n id: sku.id,\n name: sku.name,\n stock_count: comboItem.combo_sku?.stock_count ?? SKU_STOCK_COUNT_UNLIMITED,\n }\n\n if (customizationItemList) {\n comboItem.combo_customization_item_list = customizationItemList\n }\n\n if (isUseSelectCount && comboItem.count === 0) {\n comboItem.count = 1\n }\n\n handleComboGroupItemSelected(newComboGroupItem, ENTITY_BOOL_YES, index, onChange)\n}\n\n\nexport function setToggleComboItemSelecte(comboItem: ISkuComboItem, comboGroupItem: ISkuComboGroupItem, onSelectedChange?: (selected: number) => void) {\n const toggleSelected = comboItem.selected === ENTITY_BOOL_YES ? ENTITY_BOOL_NO : ENTITY_BOOL_YES\n\n if (!isEmpty(comboItem.children)) {\n return\n }\n\n const { items, max_count } = comboGroupItem\n\n if (toggleSelected === ENTITY_BOOL_YES) {\n if (max_count > 1) {\n let selectCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n })\n if (selectCount >= max_count) {\n return\n }\n }\n }\n\n onSelectedChange?.(toggleSelected)\n}\n","import { fill, find, isEqual, findIndex, flattenDeep, cloneDeep } from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n MALL_PRODUCT_SPEC_TYPE_SINGLE,\n MALL_PRODUCT_SPEC_TYPE_MULTIPLE,\n ORDER_EXTERNAL_SKU_TYPE_MALL,\n} from './constant'\n\nimport {\n IImage,\n IProduct,\n ISpecList,\n IFormatSku,\n ICartListItem,\n ISkuCombination,\n ISkuComboGroupItem,\n ISelectSkuComboItem,\n IProductSpecGroup,\n ISkuPopupData,\n} from './type'\n\nimport {\n formatSpecList,\n formatSpecObj,\n formatSkuListAfter,\n getSpecImage,\n checkProductOnSale,\n formatProductStatus,\n} from './productUtil'\n\nimport {\n reconstructComboGroupList,\n formatSelectSkuComboItemList,\n checkSkuComboItemListEqual,\n formatComboPrice,\n getSubmitComboItemListArr,\n} from './comboUtil'\n\nimport {\n ICountChangeResult,\n IAddToCartParamsResult,\n IComboSpecSelectorView,\n IComboSpecSelectorOptions,\n IFetchCartCountParams,\n IFetchMemberPriceParams,\n IMallSkuDetailDataForCombo,\n} from './type'\n\nimport { CHAGNE_TYPE_DECREASE } from './constant'\n\n/**\n * 套餐商品规格选择器\n *\n * 设计原则:类内部不发起任何接口请求,所有数据处理逻辑封装在此,\n * 网络请求由 UI 层发起,将结果通过公开方法回填。\n */\nexport class ComboSpecSelector {\n // ────────── 私有状态 ──────────\n private product: IProduct = {} as IProduct\n private specImage: IImage | undefined = undefined\n private skuId: number = 0\n private sku: IFormatSku | undefined = undefined\n private skuList: IFormatSku[] = []\n private skuListAfter: ISkuCombination[] = []\n private selectedSpecs: string[] = []\n private productSpecGroupList: ISpecList[] = []\n private specList: IProductSpecGroup[] = []\n\n private stockCount: number = 0\n private minCount: number = 1\n private maxCount: number = 1\n private perOrderMinLimit: number = -1\n private perOrderMaxLimit: number = -1\n\n private salePrice: number = 0\n private originalPrice: number = -1\n private memberPrice: number | undefined = undefined\n\n private skuComboGroupList: ISkuComboGroupItem[] = []\n private skuComboItemList: ISelectSkuComboItem[][] = []\n\n private cartCount: number = 0\n private cartItem: ICartListItem | undefined = undefined\n\n private visibleComboInfo: boolean = false\n private isComponentLoading: boolean = true\n\n // ────────── 初始化参数保存 ──────────\n private channel1Type: number\n private cartList: ICartListItem[]\n private negativeStockSaleEnabled?: boolean\n private onChange: () => void\n\n // 记录初始化时解析的 skuListAfter 与 specType,供 init 方法使用\n private _initSkuListAfter: ISkuCombination[] = []\n private _initSpecType: number = 0\n private _initSkuId: number = 0\n private _validateComboGroupList: () => string = () => ''\n\n constructor(options: IComboSpecSelectorOptions) {\n const { productData, cartList, channel1Type, negativeStockSaleEnabled, onChange, validateComboGroupList } = options\n this.cartList = cartList || []\n this.channel1Type = channel1Type\n this.negativeStockSaleEnabled = negativeStockSaleEnabled\n this.onChange = onChange\n this._validateComboGroupList = validateComboGroupList\n\n this._initProductData(productData as ISkuPopupData)\n }\n\n /** 获取初始 sku 列表(供 UI 在调用 fetchSkuDetail 前获取初始 skuId) */\n getInitialSkuId(): number {\n return this._initSkuId\n }\n // ────────── 初始化:接收 sku 详情数据 ──────────\n\n /**\n * 初始化,接收 UI 层拉取的 sku 详情数据\n * 调用后触发 onChange,UI 可通过 getView() 拿到渲染数据\n */\n init(skuDetailData: IMallSkuDetailDataForCombo): void {\n const specType = this._initSpecType\n const skuListAfter = this._initSkuListAfter\n\n // 找购物车中对应的初始化 cartItem\n const initCartItem = this._findSkuCartItem()\n\n let skuIndex = 0\n if (specType === MALL_PRODUCT_SPEC_TYPE_MULTIPLE) {\n if (!isEmpty(initCartItem)) {\n const { sku, external_sku } = initCartItem!\n const initSkuId = external_sku?.id || sku.id\n skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) {\n skuIndex = 0\n }\n }\n }\n\n this.cartItem = initCartItem\n this.cartCount = initCartItem?.cart?.count || 0\n\n const skuItem = skuListAfter[skuIndex]\n\n if (specType === MALL_PRODUCT_SPEC_TYPE_SINGLE) {\n this._initSkuDetail(skuDetailData)\n this._updateSkuData(skuItem || this.skuList[0])\n this.isComponentLoading = false\n this._notifyChange()\n return\n }\n\n // 多规格:先解析 sku 详情,再模拟选中规格\n this._initSkuDetail(skuDetailData)\n\n skuListAfter[skuIndex]?.specs.forEach((specValue, index) => {\n this._selectSpec(true, specValue, index)\n })\n\n this.isComponentLoading = false\n this._notifyChange()\n }\n\n /**\n * 同步最新的购物车列表\n * cartList 更新后调用此方法,会重新计算当前 skuId 在购物车中的数量\n */\n syncCartList(cartList: ICartListItem[]): void {\n this.cartList = cartList\n this._refreshCartItem()\n this._notifyChange()\n }\n\n // ────────── 获取渲染数据 ──────────\n\n getView(): IComboSpecSelectorView {\n return {\n product: this.product,\n skuId: this.skuId,\n salePrice: this.getSalePrice(),\n originalPrice: this.getOriginalPrice(),\n memberPrice: this.getMemberPrice(),\n specImage: this.specImage,\n skuListAfter: this.skuListAfter,\n selectedSpecs: this.selectedSpecs,\n productSpecGroupList: this.productSpecGroupList,\n skuComboGroupList: this.skuComboGroupList,\n skuComboItemList: this.skuComboItemList,\n cartCount: this.cartCount,\n maxCount: this.maxCount,\n isComponentLoading: this.isComponentLoading,\n visibleComboInfo: this.visibleComboInfo,\n }\n }\n\n // ────────── 规格选择 ──────────\n\n /**\n * 选择规格(纯数据处理)\n * @returns needFetchSkuDetail 是否需要重新拉取 sku 详情(为 true 时同样需要重新请求会员价);skuId 目标 skuId\n */\n handleSelectSpecs(\n isOption: boolean,\n value: string,\n index: number,\n ): { needFetchSkuDetail: boolean; skuId: number } {\n const changed = this._selectSpec(isOption, value, index)\n\n // 规格未全选,无需拉取详情\n if (!changed || this.selectedSpecs.indexOf('') >= 0) {\n this._notifyChange()\n return { needFetchSkuDetail: false, skuId: 0 }\n }\n\n // 全选后找到对应 sku\n const matchedSku = find(this.skuListAfter, item =>\n isEqual(item.specs, this.selectedSpecs),\n )\n\n if (!matchedSku) {\n this._notifyChange()\n return { needFetchSkuDetail: false, skuId: 0 }\n }\n\n // 更新规格图片\n if (this.specList[0]?.items[0]?.image !== undefined) {\n this.specList[0].items.forEach(item => {\n if (item.name === this.selectedSpecs[0]) {\n this.specImage = item.image\n }\n })\n }\n\n this._notifyChange()\n return { needFetchSkuDetail: true, skuId: matchedSku.id }\n }\n\n /**\n * 用新的 sku 详情数据更新内部状态\n * (规格切换后,UI 调用 fetchSkuDetail 接口拿到数据后传入此方法)\n */\n updateSkuDetailData(skuDetailData: IMallSkuDetailDataForCombo): void {\n this._initSkuDetail(skuDetailData)\n this._notifyChange()\n }\n\n /**\n * 用会员价查询结果更新内部状态,由 UI 层请求会员价接口后调用\n * @param price 会员价,请求失败或无会员价时传 undefined\n */\n updateMemberPrice(price: number | undefined): void {\n this.memberPrice = price\n this._notifyChange()\n }\n\n // ────────── 套餐选择 ──────────\n\n /**\n * 套餐选中变化(纯数据处理)\n */\n handleSelectComboData(skuComboItemList: ISelectSkuComboItem[][]) {\n this.skuComboItemList = skuComboItemList\n this._refreshCartItem()\n this._notifyChange()\n }\n\n // ────────── 数量变化 ──────────\n\n /**\n * 数量变化(纯逻辑,返回操作结果供 UI 决策)\n */\n handleProductCountChange(count: number, type: string): ICountChangeResult {\n const { perOrderMinLimit, cartItem, selectedSpecs } = this\n\n if (selectedSpecs.indexOf('') >= 0) {\n return { isValid: false, errMsg: '请选择规格' }\n }\n\n if (count > 0) {\n // 减少时,若低于最小购买量则直接置零\n if (type === CHAGNE_TYPE_DECREASE && perOrderMinLimit !== -1 && count < perOrderMinLimit) {\n return {\n isValid: true,\n cartItem: cartItem!,\n count: 0,\n }\n }\n\n // 校验套餐\n const comboErrMsg = this._validateCombo()\n if (comboErrMsg) {\n return { isValid: false, errMsg: comboErrMsg }\n }\n\n const countCheckResult = this._checkProductCount(count)\n if (!countCheckResult.isValid) {\n return countCheckResult\n }\n }\n\n return { isValid: true, cartItem: cartItem!, count }\n }\n\n // ────────── 加入购物车前校验 ──────────\n\n /**\n * 加入购物车前校验,返回提交所需参数\n * 由 UI 层使用参数调用 addToCart 接口\n */\n getAddToCartParams(productId: number, promotionActivityProductId?: number): IAddToCartParamsResult {\n const {\n sku,\n skuId,\n product,\n skuList,\n selectedSpecs,\n negativeStockSaleEnabled,\n productSpecGroupList,\n skuComboItemList,\n perOrderMinLimit,\n } = this\n\n const selectedSpecsIndex = selectedSpecs.indexOf('')\n const isProductOnSale = checkProductOnSale(product?.status, product?.has_stock)\n const productStatusDesc = formatProductStatus(product?.status, product?.has_stock)\n\n if (skuList[0].item_ids.length !== 0 && selectedSpecsIndex >= 0) {\n return {\n isValid: false,\n errMsg: `请选择${productSpecGroupList[selectedSpecsIndex].title}`,\n }\n }\n\n if (!isProductOnSale && !negativeStockSaleEnabled) {\n return { isValid: false, errMsg: productStatusDesc }\n }\n\n const comboErrMsg = this._validateCombo()\n if (comboErrMsg) {\n return { isValid: false, errMsg: comboErrMsg }\n }\n\n // 当前是活动 sku,则使用活动商品 id\n const finalPromotionActivityProductId = sku?.is_promotion_activity\n ? promotionActivityProductId\n : undefined\n\n return {\n isValid: true,\n params: {\n productId,\n promotionActivityProductId: finalPromotionActivityProductId,\n skuId,\n count: perOrderMinLimit !== -1 ? perOrderMinLimit : 1,\n skuComboItemList,\n },\n }\n }\n\n // ────────── 弹框显示 ──────────\n\n handleShowComboInfo(): void {\n const flattenList = flattenDeep(this.skuComboItemList)\n if (!isEmpty(flattenList)) {\n this.visibleComboInfo = true\n this._notifyChange()\n }\n }\n\n handleCloseComboInfo(): void {\n this.visibleComboInfo = false\n this._notifyChange()\n }\n\n // ────────── 价格计算 ──────────\n\n getSalePrice(): number {\n return formatComboPrice(this.salePrice, this.skuComboGroupList, this.skuComboItemList)\n }\n\n getOriginalPrice(): number {\n if (isEmpty(this.originalPrice) || this.originalPrice <= 0) {\n return 0\n }\n\n return formatComboPrice(this.originalPrice, this.skuComboGroupList, this.skuComboItemList)\n }\n\n // 会员价未加载或不存在时返回 undefined,否则叠加套餐加价\n getMemberPrice(): number | undefined {\n if (isEmpty(this.memberPrice) || this.memberPrice <= 0) {\n return undefined\n }\n\n return formatComboPrice(this.memberPrice, this.skuComboGroupList, this.skuComboItemList)\n }\n\n // ────────── 构造购物车查询参数(供 UI 层使用) ──────────\n\n buildCartCountParams(): IFetchCartCountParams {\n const submitSkuComboItemList = getSubmitComboItemListArr(this.skuComboItemList)\n return {\n channel1_type: this.channel1Type,\n checked: 1,\n sku_id: this.skuId,\n sku_type: ORDER_EXTERNAL_SKU_TYPE_MALL,\n sku_combo_item_list: JSON.stringify(submitSkuComboItemList),\n cart: 1,\n }\n }\n\n /**\n * 构造会员价查询参数(供 UI 层使用)\n * sku 未选中时返回 undefined\n */\n buildMemberPriceParams(): IFetchMemberPriceParams | undefined {\n if (!this.skuId) {\n return undefined\n }\n\n return {\n sku_id: this.skuId,\n sku_type: ORDER_EXTERNAL_SKU_TYPE_MALL,\n }\n }\n\n // ────────── 私有方法 ──────────\n\n private _initProductData(data: ISkuPopupData): void {\n const { product, skuList, productCover, productSpecGroupList } = data\n\n const specObj = formatSpecObj(productSpecGroupList)\n const newProductSpecGroupList = formatSpecList(productSpecGroupList)\n const skuListAfter = formatSkuListAfter(skuList, specObj, this.negativeStockSaleEnabled)\n const specImage = getSpecImage(productSpecGroupList, productCover)\n\n this.product = product\n this.specImage = specImage\n this.skuList = skuList\n this.skuListAfter = skuListAfter\n this.selectedSpecs = fill(new Array(newProductSpecGroupList.length), '')\n this.productSpecGroupList = newProductSpecGroupList\n this.specList = productSpecGroupList\n\n // 保存供 init 使用\n this._initSkuListAfter = skuListAfter\n this._initSpecType = product.spec_type\n\n // 计算初始 skuId\n const specType = product.spec_type\n if (specType === MALL_PRODUCT_SPEC_TYPE_MULTIPLE) {\n const initCartItem = this._findSkuCartItem()\n if (!isEmpty(initCartItem)) {\n const { sku, external_sku } = initCartItem!\n const initSkuId = external_sku?.id || sku.id\n let skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) skuIndex = 0\n this._initSkuId = skuListAfter[skuIndex]?.id ?? skuList[0]?.id ?? 0\n } else {\n this._initSkuId = skuListAfter[0]?.id ?? skuList[0]?.id ?? 0\n }\n } else {\n this._initSkuId = skuList[0]?.id ?? 0\n }\n }\n\n private _initSkuDetail(skuData: IMallSkuDetailDataForCombo): void {\n const { sku, sku_combo_group_list } = skuData\n\n this._updateSkuData(sku)\n\n const skuComboGroupList = reconstructComboGroupList(\n sku_combo_group_list || [],\n this.cartItem?.sku_combo_item_list,\n )\n\n this.skuComboGroupList = skuComboGroupList\n this.skuComboItemList = formatSelectSkuComboItemList(skuComboGroupList)\n }\n\n private _updateSkuData(sku: IFormatSku): void {\n const skuId = sku.id\n const stockCount = sku.stock_count\n const perOrderMinLimit = sku.per_order_min_limit\n const perOrderMaxLimit = sku.per_order_max_limit\n const minCount = perOrderMinLimit === -1 ? 1 : Math.min(perOrderMinLimit, stockCount)\n const maxCount = perOrderMaxLimit === -1 ? stockCount : Math.min(perOrderMaxLimit, stockCount)\n\n const skuCartItem = this._findSkuCartItem(skuId)\n\n this.sku = sku\n this.skuId = skuId\n this.stockCount = stockCount\n this.salePrice = sku.sale_price\n this.originalPrice = sku.original_price\n this.minCount = minCount\n this.maxCount = maxCount\n this.perOrderMinLimit = perOrderMinLimit\n this.perOrderMaxLimit = perOrderMaxLimit\n\n this.cartItem = skuCartItem\n this.cartCount = skuCartItem?.cart?.count || 0\n }\n\n private _checkProductCount(count: number): ICountChangeResult {\n const { minCount, maxCount, stockCount, perOrderMinLimit, negativeStockSaleEnabled } = this\n\n if (count < minCount || count < perOrderMinLimit) {\n const errMsg = perOrderMinLimit !== -1\n ? `该商品 ${perOrderMinLimit} 件起售哦`\n : `购买数量至少 ${minCount} 件`\n return { isValid: false, errMsg }\n }\n\n if (count > maxCount && !negativeStockSaleEnabled) {\n const errMsg = count > stockCount ? '库存不足' : `该商品最多购买 ${maxCount} 件哦`\n return { isValid: false, errMsg }\n }\n\n return { isValid: true }\n }\n\n /**\n * 内部规格选择逻辑(被 handleSelectSpecs 和 init 时复用)\n * @returns 是否发生了选中变化\n */\n private _selectSpec(isOption: boolean, value: string, index: number): boolean {\n const { selectedSpecs, productSpecGroupList } = this\n\n if (productSpecGroupList.length === 0) {\n return false\n }\n\n if (selectedSpecs[index] === value || !isOption) {\n return false\n }\n\n selectedSpecs[index] = value\n this.selectedSpecs = selectedSpecs.slice()\n return true\n }\n /**\n * 刷新当前 skuId 对应的购物车数据\n */\n private _refreshCartItem(): void {\n const skuCartItem = this._findSkuCartItem(this.skuId)\n this.cartItem = skuCartItem\n this.cartCount = skuCartItem?.cart?.count || 0\n }\n\n /**\n * 根据 skuId 和当前 skuComboItemList 从 cartList 中查找匹配的购物车项\n */\n private _findSkuCartItem(skuId?: number): ICartListItem | undefined {\n const { cartList, product, skuComboItemList } = this\n\n const findCartItem = find(cartList, (cartItem: ICartListItem) => {\n const productId = product.id\n const productCode = product.code\n const cartItemProduct = cartItem.product\n\n // 1. 判断是否是当前商品\n const isProductFind = productId\n ? cartItemProduct.id === productId\n : cartItemProduct.code === productCode\n\n if (!isProductFind) return false\n\n // 2. 没有 skuId,匹配到商品即可\n if (!skuId) return true\n\n const cartItemSku = cartItem.sku\n const cartItemSkuExternal = cartItem.external_sku\n // 3. 判断 sku_id 是否一致,优先使用活动 sku_id\n const isSkuEqual = cartItemSkuExternal\n ? cartItemSkuExternal.id === skuId\n : cartItemSku.id === skuId\n\n if (!isSkuEqual) return false\n\n const cartItemSkuComboItemList = cartItem.sku_combo_item_list || []\n // 4. 如果套餐列表为空,匹配到商品 + sku_id 即可\n if (isEmpty(skuComboItemList)) return true\n\n const flattenSkuComboItemList = flattenDeep(skuComboItemList)\n // 5. 比较套餐值列表是否相等\n return checkSkuComboItemListEqual(flattenSkuComboItemList, cartItemSkuComboItemList)\n })\n\n return findCartItem ? cloneDeep(findCartItem) : undefined\n }\n\n /**\n * 校验套餐分组是否满足要求,返回错误信息(空字符串表示校验通过)\n */\n private _validateCombo(): string {\n return this._validateComboGroupList()\n }\n\n private _notifyChange(): void {\n this.onChange()\n }\n}\n","import { fill, find, isEqual, findIndex, flattenDeep, cloneDeep } from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n CHAGNE_TYPE_DECREASE,\n MALL_PRODUCT_SPEC_TYPE_SINGLE,\n ORDER_EXTERNAL_SKU_TYPE_MALL,\n ORDER_EXTERNAL_SKU_TYPE_MARKETING_PROMOTION_ACTIVITY,\n} from './constant'\n\nimport {\n IImage,\n IProduct,\n ISpecList,\n IFormatSku,\n ICartListItem,\n ISkuCombination,\n IProductSpecGroup,\n IProductSpecItem,\n ISkuPopupData,\n IPromotionActivityProduct,\n IProductCustomizationGroupItemView,\n IProductSelectedCustomizationItem,\n} from './type'\n\nimport {\n formatSpecList,\n formatSpecObj,\n formatSkuListAfter,\n getSpecImage,\n getActivitySpecList,\n checkProductOnSale,\n formatProductStatus,\n} from './productUtil'\n\nimport {\n formatCustomizationGroupList,\n getSubmitCustomizationItemListArr,\n calculateSelectedCustomizationPrice,\n formatInitCustomizationItemList,\n reconstructCustomizationItemList,\n checkCustomizationItemList,\n checkCustomizationItemListEqual,\n formatSkuNameWithCustomization,\n formatCustomizationCountType,\n} from './customizationUtil'\n\nimport {\n IAddCartParams,\n ICountChangeResult,\n IAddToCartParamsResult,\n ICustomSpecSelectorView,\n ICustomSpecSelectorOptions,\n IFetchCustomCartCountParams,\n IFetchCartCountResult,\n IFetchMemberPriceParams,\n} from './type'\n\n/**\n * 做法加料商品规格选择器\n *\n * 设计原则:类内部不发起任何接口请求,所有数据处理逻辑封装在此,\n * 网络请求由 UI 层发起,将结果通过公开方法回填。\n *\n * 与 ComboSpecSelector 的差异:\n * - productData 已包含做法数据,初始化时无需额外接口\n * - 支持活动 sku(promotionActivityProduct)\n * - 购物车参数含 product_customization_item_list\n */\nexport class CustomSpecSelector {\n // ────────── 私有状态 ──────────\n private product: IProduct = {} as IProduct\n private promotionActivityProduct: IPromotionActivityProduct | undefined = undefined\n private specImage: IImage | undefined = undefined\n private skuId: number = 0\n private sku: IFormatSku | undefined = undefined\n private skuList: IFormatSku[] = []\n private skuListAfter: ISkuCombination[] = []\n private selectedSpecs: string[] = []\n private productSpecGroupList: ISpecList[] = []\n private specList: IProductSpecGroup[] = []\n private activitySpecList: IProductSpecItem[][] = []\n\n private stockCount: number = 0\n private minCount: number = 1\n private maxCount: number = 1\n private perOrderMinLimit: number = -1\n private perOrderMaxLimit: number = -1\n\n private salePrice: number = 0\n private originalPrice: number = -1\n private memberPrice: number | undefined = undefined\n\n private customizationGroupList: IProductCustomizationGroupItemView[] = []\n private customizationItemList: IProductSelectedCustomizationItem[][] = []\n\n private cartCount: number = 0\n private cartItem: ICartListItem | undefined = undefined\n\n // ────────── 初始化参数保存 ──────────\n private cartList: ICartListItem[] = []\n private channel1Type: number\n private negativeStockSaleEnabled?: boolean\n private onChange: () => void\n\n constructor(options: ICustomSpecSelectorOptions) {\n const { productData, cartList, channel1Type, negativeStockSaleEnabled, onChange } = options\n this.cartList = cartList || []\n this.channel1Type = channel1Type\n this.negativeStockSaleEnabled = negativeStockSaleEnabled\n this.onChange = onChange\n\n this._initProductData(productData as ISkuPopupData)\n }\n\n // ────────── 初始化 ──────────\n\n /**\n * 设置购物车列表,当购物车数据变化时调用\n * 会根据当前选中的规格和做法重新匹配购物车数据\n */\n setCartList(cartList: ICartListItem[]): void {\n this.cartList = cartList\n this._updateSkuCartItem()\n this._notifyChange()\n }\n\n /**\n * 初始化(做法加料商品无需额外接口请求,productData 已包含全部数据)\n * 调用后触发 onChange,UI 可通过 getView() 拿到渲染数据;\n * 但购物车数据需 UI 层调用 buildCartCountParams() 拿参数后自行请求。\n */\n init(): void {\n const skuListAfter = this.skuListAfter\n const specType = this.product.spec_type\n\n // 从购物车列表中找到匹配的初始商品\n const initCartItem = this._findSkuCartItem()\n\n let skuIndex = 0\n\n if (!isEmpty(initCartItem)) {\n const { sku, external_sku, product_customization_item_list } = initCartItem!\n const initSkuId = external_sku?.id || sku.id\n skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) {\n skuIndex = 0\n }\n\n // 购物车中有做法值,回填做法值列表\n if (!isEmpty(product_customization_item_list)) {\n const res = reconstructCustomizationItemList(\n this.customizationGroupList,\n product_customization_item_list!,\n )\n this.customizationGroupList = res.customizationGroupList\n this.customizationItemList = res.selectedCustomizationItemList\n }\n }\n\n this._updateSkuCartItem()\n\n if (specType === MALL_PRODUCT_SPEC_TYPE_SINGLE) {\n this._updateSkuData(this.skuList[0])\n this._notifyChange()\n return\n }\n\n // 多规格:模拟选中初始规格\n skuListAfter[skuIndex]?.specs.forEach((specValue, index) => {\n this._selectSpec(true, specValue, index)\n })\n\n // 找到对应 sku 并更新\n const matchedSku = find(skuListAfter, item =>\n isEqual(item.specs, this.selectedSpecs),\n )\n if (matchedSku) {\n this._updateSkuData(matchedSku)\n }\n\n this._notifyChange()\n }\n\n // ────────── 获取渲染数据 ──────────\n\n getView(): ICustomSpecSelectorView {\n return {\n product: this.product,\n promotionActivityProduct: this.promotionActivityProduct,\n skuId: this.skuId,\n sku: this.sku,\n salePrice: this.getSalePrice(),\n originalPrice: this.getOriginalPrice(),\n memberPrice: this.getMemberPrice(),\n specImage: this.specImage,\n skuListAfter: this.skuListAfter,\n selectedSpecs: this.selectedSpecs,\n productSpecGroupList: this.productSpecGroupList,\n activitySpecList: this.activitySpecList,\n customizationGroupList: this.customizationGroupList,\n customizationItemList: this.customizationItemList,\n cartCount: this.cartCount,\n maxCount: this.maxCount,\n cartItem: this.cartItem,\n }\n }\n\n // ────────── 规格选择 ──────────\n\n /**\n * 选择规格(纯数据处理)\n * @returns needFetchCart 是否需要刷新购物车数(为 true 时同样需要重新请求会员价);cartParams 购物车查询参数\n */\n handleSelectSpecs(\n isOption: boolean,\n value: string,\n index: number,\n ): { needFetchCart: boolean; cartParams: IFetchCustomCartCountParams } {\n const changed = this._selectSpec(isOption, value, index)\n\n const emptyCartParams = this.buildCartCountParams()\n\n if (!changed || this.selectedSpecs.indexOf('') >= 0) {\n // 规格未全选时,清空购物车匹配数据\n this._updateSkuCartItem()\n this._notifyChange()\n return { needFetchCart: false, cartParams: emptyCartParams }\n }\n\n // 全选后找到对应 sku\n const matchedSku = find(this.skuListAfter, item =>\n isEqual(item.specs, this.selectedSpecs),\n )\n\n if (!matchedSku) {\n this._updateSkuCartItem()\n this._notifyChange()\n return { needFetchCart: false, cartParams: emptyCartParams }\n }\n\n // 更新规格图片\n if (this.specList[0]?.items[0]?.image !== undefined) {\n this.specList[0].items.forEach(item => {\n if (item.name === this.selectedSpecs[0]) {\n this.specImage = item.image\n }\n })\n }\n\n this._updateSkuData(matchedSku)\n // 规格变化后,重新匹配购物车数据\n this._updateSkuCartItem()\n this._notifyChange()\n\n return { needFetchCart: true, cartParams: this.buildCartCountParams() }\n }\n\n /**\n * 用购物车查询结果更新内部状态\n */\n updateCartCountData(result: IFetchCartCountResult): void {\n if (result && result.cart !== undefined) {\n const cart = result.cart\n this.cartItem = result as any\n this.cartCount = cart?.count || 0\n } else {\n this.cartItem = undefined\n this.cartCount = 0\n }\n this._notifyChange()\n }\n\n /**\n * 用会员价查询结果更新内部状态,由 UI 层请求会员价接口后调用\n * @param price 会员价,请求失败或无会员价时传 undefined\n */\n updateMemberPrice(price: number | undefined): void {\n this.memberPrice = price\n this._notifyChange()\n }\n\n // ────────── 做法选择 ──────────\n\n /**\n * 做法选中变化(纯数据处理)\n * @returns isValid 校验是否通过;cartParams 若通过则返回购物车查询参数\n */\n handleCustomizationItemListSelect(\n customizationItemList: IProductSelectedCustomizationItem[][],\n ): { isValid: boolean; cartParams?: IFetchCustomCartCountParams } {\n this.customizationItemList = customizationItemList\n\n const res = checkCustomizationItemList(\n this.customizationGroupList,\n customizationItemList,\n )\n\n if (!res.isValid) {\n this.cartItem = undefined\n this.cartCount = 0\n this._notifyChange()\n return { isValid: false }\n }\n\n // 做法变化后,重新匹配购物车数据\n this._updateSkuCartItem()\n this._notifyChange()\n return { isValid: true, cartParams: this.buildCartCountParams() }\n }\n\n // ────────── 数量变化 ──────────\n\n /**\n * 数量变化(纯逻辑,返回操作结果供 UI 决策)\n */\n handleProductCountChange(count: number, type: string): ICountChangeResult {\n const { perOrderMinLimit, cartItem, selectedSpecs } = this\n\n if (selectedSpecs.indexOf('') >= 0) {\n return { isValid: false, errMsg: '请选择规格' }\n }\n\n if (count > 0) {\n // 减少时,若低于最小购买量则直接置零\n if (type === CHAGNE_TYPE_DECREASE && perOrderMinLimit !== -1 && count < perOrderMinLimit) {\n return { isValid: true, cartItem: cartItem!, count: 0 }\n }\n\n // 校验做法\n if (this.customizationGroupList.length > 0) {\n const res = checkCustomizationItemList(\n this.customizationGroupList,\n this.customizationItemList,\n )\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n }\n\n const countCheckResult = this._checkProductCount(count)\n if (!countCheckResult.isValid) {\n return countCheckResult\n }\n }\n\n return { isValid: true, cartItem: cartItem!, count }\n }\n\n // ────────── 加入购物车前校验 ──────────\n\n /**\n * 加入购物车前校验,返回提交所需参数\n * 由 UI 层使用参数调用 addToCart 接口\n */\n getAddToCartParams(productId: number, promotionActivityProductId?: number): IAddToCartParamsResult {\n const {\n sku,\n skuId,\n product,\n skuList,\n selectedSpecs,\n negativeStockSaleEnabled,\n productSpecGroupList,\n customizationItemList,\n customizationGroupList,\n perOrderMinLimit,\n } = this\n\n const selectedSpecsIndex = selectedSpecs.indexOf('')\n const isProductOnSale = checkProductOnSale(product?.status, product?.has_stock)\n const productStatusDesc = formatProductStatus(product?.status, product?.has_stock)\n\n if (skuList[0].item_ids.length !== 0 && selectedSpecsIndex >= 0) {\n return {\n isValid: false,\n errMsg: `请选择${productSpecGroupList[selectedSpecsIndex].title}`,\n }\n }\n\n if (!isProductOnSale && !negativeStockSaleEnabled) {\n return { isValid: false, errMsg: productStatusDesc }\n }\n\n if (customizationGroupList.length > 0) {\n const res = checkCustomizationItemList(customizationGroupList, customizationItemList)\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n }\n\n const productCustomizationItemList = getSubmitCustomizationItemListArr(customizationItemList)\n const finalPromotionActivityProductId = sku?.is_promotion_activity ? promotionActivityProductId : undefined\n\n const params: IAddCartParams = {\n productId,\n promotionActivityProductId: finalPromotionActivityProductId,\n skuId,\n count: perOrderMinLimit !== -1 ? perOrderMinLimit : 1,\n productCustomizationItemList,\n }\n\n return { isValid: true, params }\n }\n\n // ────────── 价格计算 ──────────\n\n getSalePrice(): number {\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n this.customizationGroupList,\n this.customizationItemList,\n )\n return this.salePrice + selectedCustomizationPrice\n }\n\n getOriginalPrice(): number {\n // 没有原价时返回 -1\n if (isEmpty(this.originalPrice) || this.originalPrice <= 0) {\n return this.originalPrice\n }\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n this.customizationGroupList,\n this.customizationItemList,\n )\n return this.originalPrice + selectedCustomizationPrice\n }\n\n // 会员价未加载或不存在时返回 undefined,否则叠加做法加料价格\n getMemberPrice(): number | undefined {\n if (isEmpty(this.memberPrice) || this.memberPrice <= 0) {\n return undefined\n }\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n this.customizationGroupList,\n this.customizationItemList,\n )\n return this.memberPrice + selectedCustomizationPrice\n }\n\n // 获取选中规格和做法合并后的数据\n getSelectedSpecAndCustomization(): string {\n let name = this.selectedSpecs.join('、')\n const flattenCustomizationItemList = flattenDeep(this.customizationItemList)\n\n name = formatSkuNameWithCustomization(name, flattenCustomizationItemList)\n const countTypeName = formatCustomizationCountType(flattenCustomizationItemList)\n\n if (isEmpty(name) && isEmpty(countTypeName)) {\n return ''\n }\n\n if (isEmpty(name) || isEmpty(countTypeName)) {\n return name ? name : countTypeName\n }\n\n return `${name}、${countTypeName}`\n }\n\n // ────────── 构造购物车查询参数(供 UI 层使用) ──────────\n\n buildCartCountParams(): IFetchCustomCartCountParams {\n const productCustomizationItemList = getSubmitCustomizationItemListArr(this.customizationItemList)\n\n return {\n channel1_type: this.channel1Type,\n checked: 1,\n sku_id: this.skuId,\n sku_type: this._getSkuType(),\n product_customization_item_list: JSON.stringify(productCustomizationItemList),\n cart: 1,\n }\n }\n\n /**\n * 构造会员价查询参数(供 UI 层使用)\n * sku 未选中时返回 undefined\n */\n buildMemberPriceParams(): IFetchMemberPriceParams | undefined {\n if (!this.skuId) {\n return undefined\n }\n\n return {\n sku_id: this.skuId,\n sku_type: this._getSkuType(),\n }\n }\n\n // ────────── 私有方法 ──────────\n\n private _initProductData(data: ISkuPopupData): void {\n const {\n product,\n promotionActivityProduct,\n skuList,\n productCover,\n productSpecGroupList,\n productCustomizationGroupList,\n } = data\n\n const specObj = formatSpecObj(productSpecGroupList)\n const newProductSpecGroupList = formatSpecList(productSpecGroupList)\n const skuListAfter = formatSkuListAfter(skuList, specObj, this.negativeStockSaleEnabled)\n const specImage = getSpecImage(productSpecGroupList, productCover)\n const activitySpecList = getActivitySpecList(productSpecGroupList)\n const customizationGroupList = formatCustomizationGroupList(productCustomizationGroupList || [])\n\n this.product = product\n this.promotionActivityProduct = promotionActivityProduct\n this.specImage = specImage\n this.skuList = skuList\n this.skuListAfter = skuListAfter\n this.selectedSpecs = fill(new Array(newProductSpecGroupList.length), '')\n this.productSpecGroupList = newProductSpecGroupList\n this.specList = productSpecGroupList\n this.activitySpecList = activitySpecList\n this.customizationGroupList = customizationGroupList\n this.customizationItemList = productCustomizationGroupList\n ? formatInitCustomizationItemList(customizationGroupList)\n : []\n }\n\n private _updateSkuData(sku: IFormatSku): void {\n const skuId = sku.id\n const stockCount = sku.stock_count\n const perOrderMinLimit = sku.per_order_min_limit\n const perOrderMaxLimit = sku.per_order_max_limit\n const minCount = perOrderMinLimit === -1 ? 1 : Math.min(perOrderMinLimit, stockCount)\n const maxCount = perOrderMaxLimit === -1 ? stockCount : Math.min(perOrderMaxLimit, stockCount)\n\n this.sku = sku\n this.skuId = skuId\n this.stockCount = stockCount\n this.salePrice = sku.sale_price\n this.originalPrice = sku.original_price\n this.minCount = minCount\n this.maxCount = maxCount\n this.perOrderMinLimit = perOrderMinLimit\n this.perOrderMaxLimit = perOrderMaxLimit\n\n this._findSkuCartItem(skuId)\n }\n\n private _checkProductCount(count: number): ICountChangeResult {\n const { minCount, maxCount, stockCount, perOrderMinLimit, negativeStockSaleEnabled } = this\n\n if (count < minCount || count < perOrderMinLimit) {\n const errMsg = perOrderMinLimit !== -1\n ? `该商品 ${perOrderMinLimit} 件起售哦`\n : `购买数量至少 ${minCount} 件`\n return { isValid: false, errMsg }\n }\n\n if (count > maxCount && !negativeStockSaleEnabled) {\n const errMsg = count > stockCount ? '库存不足' : `该商品最多购买 ${maxCount} 件哦`\n return { isValid: false, errMsg }\n }\n\n return { isValid: true }\n }\n\n private _selectSpec(isOption: boolean, value: string, index: number): boolean {\n const { selectedSpecs, productSpecGroupList } = this\n\n if (productSpecGroupList.length === 0) {\n return false\n }\n\n if (selectedSpecs[index] === value || !isOption) {\n return false\n }\n\n selectedSpecs[index] = value\n this.selectedSpecs = selectedSpecs.slice()\n return true\n }\n\n private _notifyChange(): void {\n this.onChange()\n }\n\n /**\n * 获取当前 sku 类型,活动 sku 返回活动类型,否则返回商城类型\n */\n private _getSkuType(): number {\n return this.sku?.is_promotion_activity\n ? ORDER_EXTERNAL_SKU_TYPE_MARKETING_PROMOTION_ACTIVITY\n : ORDER_EXTERNAL_SKU_TYPE_MALL\n }\n\n /**\n * 从购物车列表中查找匹配的购物车项\n * 匹配逻辑:\n * 1. 判断购物车商品是否是当前商品(优先使用活动商品 id 比较)\n * 2. 判断 sku_id 是否一样(优先使用活动 sku_id)\n * 3. 比较做法值列表是否相等(数组长度一致,且 id 和 count 一致)\n */\n private _findSkuCartItem(skuId?: number): ICartListItem | undefined {\n const { cartList } = this\n\n if (isEmpty(cartList)) {\n return undefined\n }\n\n const {\n product,\n promotionActivityProduct,\n customizationItemList,\n } = this\n\n const findCartItem = find(cartList, (cartItem: ICartListItem) => {\n const productId = product.id\n const productCode = product.code\n\n const cartItemProduct = cartItem.product\n const cartItemExternalProduct = cartItem.external_product\n\n // 1. 判断购物车商品是否是当前商品\n let isProductFind = false\n // 优先使用活动商品 id 进行比较\n if (cartItemExternalProduct) {\n isProductFind = cartItemExternalProduct.id === promotionActivityProduct?.id\n } else {\n isProductFind = productId\n ? cartItemProduct.id === productId\n : cartItemProduct.code === productCode\n }\n\n if (!isProductFind) {\n return false\n }\n\n // 2. 如果没有 skuId,则匹配到商品即可\n const targetSkuId = skuId || this.skuId\n if (!targetSkuId) {\n return true\n }\n\n const cartItemSku = cartItem.sku\n const cartItemSkuExternal = cartItem.external_sku\n // 3. 判断 sku_id 是否一样,优先使用活动 sku_id\n const isSkuEqual = cartItemSkuExternal\n ? cartItemSkuExternal.id === targetSkuId\n : cartItemSku.id === targetSkuId\n\n if (!isSkuEqual) {\n return false\n }\n\n const cartItemCustomizationItemList = cartItem.product_customization_item_list || []\n // 4. 如果做法值列表为空,则匹配到商品 + sku_id 即可\n if (isEmpty(customizationItemList) && isEmpty(cartItemCustomizationItemList)) {\n return true\n }\n\n const flattenCustomizationItemList = flattenDeep(customizationItemList)\n\n // 5. 比较做法值列表是否相等, 数组长度一致,且 id 和 count 一致\n return checkCustomizationItemListEqual(flattenCustomizationItemList, cartItemCustomizationItemList)\n })\n\n return findCartItem ? cloneDeep(findCartItem) : undefined\n }\n\n /**\n * 更新当前 sku 对应的购物车数据\n */\n private _updateSkuCartItem(): void {\n const skuCartItem = this._findSkuCartItem(this.skuId)\n\n this.cartItem = skuCartItem\n this.cartCount = skuCartItem?.cart?.count || 0\n }\n}\n","import {\n fill,\n find,\n isEqual,\n findIndex,\n flattenDeep,\n} from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n MALL_PRODUCT_SPEC_TYPE_SINGLE,\n} from './constant'\n\nimport {\n IImage,\n IProduct,\n ISpecList,\n IFormatSku,\n ISkuCombination,\n IProductSpecGroup,\n IProductCustomizationGroupItemView,\n IProductSelectedCustomizationItem,\n ISkuPopupData,\n ISkuPopupSbumitData,\n} from './type'\n\nimport {\n getSpecImage,\n formatSpecObj,\n formatSpecList,\n formatSkuListAfter,\n\n checkProductOnSale,\n formatProductStatus,\n} from './productUtil'\n\nimport {\n checkCustomizationItemList,\n formatCustomizationGroupList,\n formatInitCustomizationItemList,\n reconstructCustomizationItemList,\n calculateSelectedCustomizationPrice,\n formatSkuNameWithCustomization,\n formatCustomizationCountType,\n} from './customizationUtil'\n\nexport interface IChildCustomSelectorOptions {\n productData: ISkuPopupData\n initSkuId?: number\n customizationItemList?: IProductSelectedCustomizationItem[][]\n exchangeRate?: number\n channel1Type: number\n onChange: () => void\n}\n\n// ────────── 提交校验结果 ──────────\n\nexport interface IChildCustomSubmitResult {\n isValid: boolean\n errMsg?: string\n data?: ISkuPopupSbumitData\n}\n\n// ────────── Selector 视图数据 ──────────\n\nexport interface IChildCustomSelectorView {\n product: IProduct\n specImage: IImage | undefined\n skuListAfter: ISkuCombination[]\n selectedSpecs: string[]\n productSpecGroupList: ISpecList[]\n customizationGroupList: IProductCustomizationGroupItemView[]\n customizationItemList: IProductSelectedCustomizationItem[][]\n count: number\n isScrollable: boolean\n salePrice: number\n}\n\nexport class ChildCustomSelector {\n\n // ────────── 私有状态 ──────────\n\n private product: IProduct = {} as IProduct\n private specImage: IImage | undefined = undefined\n\n private skuId: number = 0\n private sku: IFormatSku | undefined = undefined\n private count: number = 1\n\n private stockCount: number = 0\n private minCount: number = 1\n private maxCount: number = 1\n private perOrderMinLimit: number = -1\n private perOrderMaxLimit: number = -1\n\n private skuList: IFormatSku[] = []\n private skuListAfter: ISkuCombination[] = []\n private selectedSpecs: string[] = []\n private productSpecGroupList: ISpecList[] = []\n private specList: IProductSpecGroup[] = []\n\n private customizationGroupList: IProductCustomizationGroupItemView[] = []\n private customizationItemList: IProductSelectedCustomizationItem[][] = []\n\n private isScrollable: boolean = false\n\n // ────────── 初始化参数保存 ──────────\n\n private exchangeRate: number\n private channel1Type: number\n private onChange: () => void\n\n private _initCustomizationItemList: IProductSelectedCustomizationItem[][] | undefined\n\n constructor(options: IChildCustomSelectorOptions) {\n const {\n productData,\n initSkuId,\n customizationItemList,\n exchangeRate = 10000,\n channel1Type,\n onChange,\n } = options\n\n this.exchangeRate = exchangeRate\n this.channel1Type = channel1Type\n this.onChange = onChange\n this._initCustomizationItemList = customizationItemList\n\n this._initProductData(productData, initSkuId)\n }\n\n // ────────── 视图数据 ──────────\n\n getView(): IChildCustomSelectorView {\n return {\n product: this.product,\n specImage: this.specImage,\n skuListAfter: this.skuListAfter,\n selectedSpecs: this.selectedSpecs,\n productSpecGroupList: this.productSpecGroupList,\n customizationGroupList: this.customizationGroupList,\n customizationItemList: this.customizationItemList,\n count: this.count,\n isScrollable: this.isScrollable,\n salePrice: this._formatSalePrice(),\n }\n }\n\n // ────────── 规格选择 ──────────\n\n handleSelectSpecs(isOption: boolean, value: string, index: number): void {\n const { specList, skuListAfter, selectedSpecs, productSpecGroupList } = this\n\n if (productSpecGroupList.length > 0) {\n if (selectedSpecs[index] === value || !isOption) {\n return\n }\n\n selectedSpecs[index] = selectedSpecs[index] === value ? '' : value\n\n this.selectedSpecs = selectedSpecs.slice()\n }\n\n if (selectedSpecs.indexOf('') < 0) {\n find(skuListAfter, item => {\n const equal = isEqual(item.specs, selectedSpecs)\n\n if (equal) {\n this._updateSkuData(item)\n }\n\n return equal\n })\n\n if (specList[0]?.items[0].image !== undefined) {\n specList[0].items.forEach(item => {\n if (item.name === selectedSpecs[0]) {\n this.specImage = item.image\n }\n })\n }\n }\n\n this._notifyChange()\n }\n\n // ────────── 做法选择 ──────────\n\n handleCustomizationItemListSelect(customizationItemList: IProductSelectedCustomizationItem[][]): void {\n this.customizationItemList = customizationItemList\n this._notifyChange()\n }\n\n // 获取选中规格和做法合并后的数据\n getSelectedSpecAndCustomization(): string {\n let name = this.selectedSpecs.join('、')\n const flattenCustomizationItemList = flattenDeep(this.customizationItemList)\n\n name = formatSkuNameWithCustomization(name, flattenCustomizationItemList)\n const countTypeName = formatCustomizationCountType(flattenCustomizationItemList)\n\n if (isEmpty(name) && isEmpty(countTypeName)) {\n return ''\n }\n\n if (isEmpty(name) || isEmpty(countTypeName)) {\n return name ? name : countTypeName\n }\n\n return `${name}、${countTypeName}`\n }\n\n // ────────── 数量变化 ──────────\n\n handleProductCountChange(count: number, type: string): { isValid: boolean; errMsg?: string } {\n const { selectedSpecs, customizationItemList, customizationGroupList, perOrderMinLimit } = this\n\n if (selectedSpecs.indexOf('') < 0) {\n if (count > 0) {\n if (type === 'CHANGE_TYPE_DECREASE' && perOrderMinLimit !== -1 && count < perOrderMinLimit) {\n return { isValid: false }\n }\n\n const res = checkCustomizationItemList(customizationGroupList || [], customizationItemList || [])\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n\n const countCheck = this._checkProductCount(count)\n if (!countCheck.isValid) {\n return countCheck\n }\n }\n\n return { isValid: true }\n }\n else {\n return { isValid: false, errMsg: '请选择规格' }\n }\n }\n\n // ────────── 提交 ──────────\n\n handleSubmit(): IChildCustomSubmitResult {\n const {\n sku,\n count,\n product,\n skuList,\n selectedSpecs,\n productSpecGroupList,\n customizationItemList,\n customizationGroupList,\n } = this\n\n const selectedSpecsIndex = selectedSpecs.indexOf('')\n const isProductOnSale = checkProductOnSale(product?.status, product?.has_stock)\n const productStatusDesc = formatProductStatus(product?.status, product?.has_stock)\n\n if (skuList[0].item_ids.length === 0 || selectedSpecsIndex < 0) {\n if (!isProductOnSale) {\n return { isValid: false, errMsg: productStatusDesc }\n }\n\n if (!isEmpty(customizationGroupList)) {\n const res = checkCustomizationItemList(customizationGroupList, customizationItemList || [])\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n }\n\n const data: ISkuPopupSbumitData = {\n sku: sku!,\n count,\n customizationItemList,\n }\n\n return { isValid: true, data }\n }\n else {\n return {\n isValid: false,\n errMsg: `请选择${productSpecGroupList[selectedSpecsIndex].title}`,\n }\n }\n }\n\n // ────────── 滚动状态更新 ──────────\n\n setScrollable(isScrollable: boolean): void {\n this.isScrollable = isScrollable\n this._notifyChange()\n }\n\n // ────────── 私有方法 ──────────\n\n private _initProductData(data: ISkuPopupData, initSkuId?: number): void {\n const {\n product,\n skuList,\n productCover,\n productSpecGroupList,\n productCustomizationGroupList,\n } = data\n\n const specObj = formatSpecObj(productSpecGroupList)\n const newProductSpecGroupList = formatSpecList(productSpecGroupList)\n const skuListAfter = formatSkuListAfter(skuList, specObj)\n const specImage = getSpecImage(productSpecGroupList, productCover)\n const customizationGroupList = formatCustomizationGroupList(productCustomizationGroupList || [])\n const initCustomizationItemList = formatInitCustomizationItemList(customizationGroupList)\n\n this.product = product\n this.specImage = specImage\n this.skuList = skuList\n this.skuListAfter = skuListAfter\n this.selectedSpecs = fill(new Array(newProductSpecGroupList.length), '')\n this.productSpecGroupList = newProductSpecGroupList\n this.specList = productSpecGroupList\n this.customizationGroupList = customizationGroupList\n this.customizationItemList = initCustomizationItemList\n\n // 购物车中有做法值,初始化时,需回填做法值列表\n if (!isEmpty(this._initCustomizationItemList)) {\n const res = reconstructCustomizationItemList(\n customizationGroupList,\n flattenDeep(this._initCustomizationItemList)\n )\n this.customizationGroupList = res.customizationGroupList\n this.customizationItemList = res.selectedCustomizationItemList\n }\n\n const specType = product.spec_type\n\n // 单规格商品\n if (specType === MALL_PRODUCT_SPEC_TYPE_SINGLE) {\n this._updateSkuData(skuList[0])\n return\n }\n\n let skuIndex = 0\n if (!isEmpty(initSkuId)) {\n skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) {\n skuIndex = 0\n }\n }\n\n skuListAfter[skuIndex]?.specs.forEach((item, index) => {\n this.handleSelectSpecs(true, item, index)\n })\n }\n\n private _updateSkuData(sku: IFormatSku): void {\n const skuId = sku.id\n const stockCount = sku.stock_count\n const perOrderMinLimit = sku.per_order_min_limit\n const perOrderMaxLimit = sku.per_order_max_limit\n const minCount = perOrderMinLimit === -1 ? 1 : Math.min(perOrderMinLimit, stockCount)\n const maxCount = perOrderMaxLimit === -1 ? stockCount : Math.min(perOrderMaxLimit, stockCount)\n\n this.sku = sku\n this.skuId = skuId\n this.stockCount = stockCount\n this.minCount = minCount\n this.maxCount = maxCount\n this.perOrderMinLimit = perOrderMinLimit\n this.perOrderMaxLimit = perOrderMaxLimit\n }\n\n private _checkProductCount(count: number): { isValid: boolean; errMsg?: string } {\n const { minCount, maxCount, stockCount, perOrderMinLimit } = this\n\n if (count < minCount || count < perOrderMinLimit) {\n if (perOrderMinLimit !== -1) {\n return { isValid: false, errMsg: `该商品 ${perOrderMinLimit} 件起售哦` }\n }\n else {\n return { isValid: false, errMsg: `购买数量至少 ${minCount} 件` }\n }\n }\n\n if (count > maxCount) {\n if (count > stockCount) {\n return { isValid: false, errMsg: '库存不足' }\n }\n else {\n return { isValid: false, errMsg: `该商品最多购买 ${maxCount} 件哦` }\n }\n }\n\n return { isValid: true }\n }\n\n private _formatSalePrice(): number {\n const { customizationGroupList, customizationItemList } = this\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n customizationGroupList || [],\n customizationItemList || []\n )\n\n return selectedCustomizationPrice\n }\n\n private _notifyChange(): void {\n this.onChange()\n }\n}\n","/** 折扣券。对齐 coupon_type = 1,走折扣票面 */\nexport const COUPON_TYPE_DISCOUNT = 1\n/** 满减券。对齐 coupon_type = 2,走金额票面 */\nexport const COUPON_TYPE_AMOUNT = 2\n/** 配送券。对齐 coupon_type = 3,走金额票面 */\nexport const COUPON_TYPE_FREIGHT = 3\n\n/** 使用门槛:按金额。对齐 threshold_type */\nexport const COUPON_THRESHOLD_TYPE_AMOUNT = 1\n/** 使用门槛:按件数。对齐 threshold_type */\nexport const COUPON_THRESHOLD_TYPE_COUNT = 2\n\n/** 生效开始:立即。对齐 effective_start_type */\nexport const COUPON_EFFECTIVE_START_TYPE_NOW = 1\n/** 生效开始:指定时间。对齐 effective_start_type */\nexport const COUPON_EFFECTIVE_START_TYPE_FUTURE = 2\n\n/** 生效结束:永久。对齐 effective_end_type */\nexport const COUPON_EFFECTIVE_END_TYPE_FOREVER = 1\n/** 生效结束:指定时间。对齐 effective_end_type */\nexport const COUPON_EFFECTIVE_END_TYPE_FUTURE = 2\n/** 生效结束:领取后延长 N 天。对齐 effective_end_type */\nexport const COUPON_EFFECTIVE_END_TYPE_EXTEND = 3\n\n/** 可用日期:按天(每天)。对齐 available_repeat_type */\nexport const COUPON_AVAILABLE_REPEAT_TYPE_DAILY = 0\n/** 可用日期:按周。对齐 available_repeat_type */\nexport const COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY = 1\n/** 可用日期:按月。对齐 available_repeat_type */\nexport const COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY = 2\n\n/** 券实例状态:待生效。对齐 coupon.status */\nexport const COUPON_STATUS_PENDING = 1\n/** 券实例状态:已生效。对齐 coupon.status */\nexport const COUPON_STATUS_ENABLED = 2\n/** 券实例状态:已使用。对齐 coupon.status */\nexport const COUPON_STATUS_USED = 3\n/** 券实例状态:已过期。对齐 coupon.status */\nexport const COUPON_STATUS_EXPIRED = 4\n/** 券实例状态:已注销。对齐 coupon.status */\nexport const COUPON_STATUS_CANCELED = 5\n/** 券实例状态:已锁定。对齐 coupon.status */\nexport const COUPON_STATUS_LOCKED = 6\n\n/** 券模板状态:草稿。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_DRAFT = 1\n/** 券模板状态:已上线。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_ONLINE = 2\n/** 券模板状态:已下线。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_OFFLINE = 3\n/** 券模板状态:已过期。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_EXPIRED = 4\n\n/** 接口没给 available_error 时,按已知状态补不可用原因 */\nexport const COUPON_TEMPLATE_STATUS_UNAVAILABLE_ERROR: Record<number, string> = {\n [COUPON_TEMPLATE_STATUS_DRAFT]: '优惠券为草稿状态',\n [COUPON_TEMPLATE_STATUS_OFFLINE]: '优惠券已下线',\n [COUPON_TEMPLATE_STATUS_EXPIRED]: '优惠券已过期',\n}\n\n/** 券实例独有状态:已注销 / 已锁定。数字不与模板冲突 */\nexport const COUPON_STATUS_UNAVAILABLE_ERROR: Record<number, string> = {\n ...COUPON_TEMPLATE_STATUS_UNAVAILABLE_ERROR,\n [COUPON_STATUS_CANCELED]: '优惠券已注销',\n [COUPON_STATUS_LOCKED]: '优惠券已锁定',\n}\n\n/** 可用券展开:使用规则等额外信息 */\nexport const COUPON_EXPAND_TYPE_EXTRA = 'extra'\n/** 不可用券展开:本单不可用原因 */\nexport const COUPON_EXPAND_TYPE_REASON = 'reason'\n/** 没有可展开内容 */\nexport const COUPON_EXPAND_TYPE_NONE = 'none'\n\n/** confirm 未选券时的默认提示 */\nexport const COUPON_CONFIRM_EMPTY_MSG = '请选择优惠券'\n\n/** 实例票面:过期时间展示具体截止日期 */\nexport const COUPON_EXPIRE_MODE_DEADLINE = 'deadline'\n/** 模板票面:有效期,按次卡同一套开始/结束类型拼文案 */\nexport const COUPON_EXPIRE_MODE_VALIDITY = 'validity'\n","import { formatMinuteSegments } from '@yorkjs/hive'\n\nimport {\n COUPON_AVAILABLE_REPEAT_TYPE_DAILY,\n COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY,\n COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY,\n} from './constant'\n\n/**\n * 可用日期 / 时段格式化。\n * 优惠券、次卡共用同一套营销字段(available_repeat_*、available_minute_segments),\n * 文案不走 i18n,与列表页中文规则对齐。\n */\n\n/** 一周顺序:周一 ~ 周日(周日为 0) */\nconst WEEK_ORDER = [1, 2, 3, 4, 5, 6, 0]\n\n/** 连续天数达到该值才用区间展示;2 天仍逐个列出 */\nconst MIN_CONSECUTIVE_RANGE_LENGTH = 3\n\nconst WEEK_SHORT_LABEL_MAP: Record<number, string> = {\n 1: '一',\n 2: '二',\n 3: '三',\n 4: '四',\n 5: '五',\n 6: '六',\n 0: '日',\n}\n\nconst WORKDAYS = [1, 2, 3, 4, 5]\nconst WEEKEND = [6, 0]\n\n/** 文档全天为 [0, 1440];选择器常只能选到 23:59,即 [0, 1439] */\nconst FULL_DAY_START = 0\nconst FULL_DAY_END = 1440\nconst LAST_MINUTE_OF_DAY = 1439\n\nexport interface IFormatAvailableRepeatOptions {\n /** 重复类型:0 每天 / 1 每周 / 2 每月 */\n repeatType?: number\n /** 周几或每月几号;周:0-6,月:1-28。也可传接口 JSON 字符串 */\n repeatValue?: Array<number | string> | string\n /** 日内时段,一维 [start, end, ...],单位分钟 */\n minuteSegments?: Array<number | string> | string\n}\n\n/** 00:00-24:00 或 00:00-23:59 都视为全天 */\nexport function isFullDayMinuteSegment(start: number, end: number) {\n return start === FULL_DAY_START && (end === FULL_DAY_END || end === LAST_MINUTE_OF_DAY)\n}\n\n/**\n * 接口里的周几 / 日期 / 时段可能是 number[] 或 JSON 字符串。\n * formatItem 原样搬运即可,这里统一收成 number[]。\n */\nexport function parseCouponNumberList(value?: Array<number | string> | string): number[] {\n if (Array.isArray(value)) {\n return value\n .map(item => Number(item))\n .filter(item => Number.isFinite(item) && item >= 0)\n }\n\n if (typeof value === 'string' && value) {\n try {\n const parsed = JSON.parse(value)\n if (Array.isArray(parsed)) {\n return parseCouponNumberList(parsed)\n }\n }\n catch (error) {\n return value\n .split(',')\n .map(item => Number(item))\n .filter(item => Number.isFinite(item) && item >= 0)\n }\n }\n\n return []\n}\n\nconst isSameNumberSet = (source: number[], target: number[]) => {\n if (source.length !== target.length) {\n return false\n }\n const targetSet = new Set(target)\n return source.every(item => targetSet.has(item))\n}\n\n/** 已排序序列切成连续段。周几不绕回:周六、周日、周一不算连续 */\nconst splitConsecutiveGroups = (\n items: number[],\n isConsecutivePair: (prev: number, curr: number) => boolean = (prev, curr) => curr === prev + 1,\n) => {\n if (!items.length) {\n return [] as number[][]\n }\n\n const groups: number[][] = [[items[0]]]\n\n for (let i = 1; i < items.length; i++) {\n const prev = items[i - 1]\n const curr = items[i]\n if (isConsecutivePair(prev, curr)) {\n groups[groups.length - 1].push(curr)\n continue\n }\n groups.push([curr])\n }\n\n return groups\n}\n\nconst isConsecutiveWeekDayPair = (prev: number, curr: number) => {\n const prevIndex = WEEK_ORDER.indexOf(prev)\n const currIndex = WEEK_ORDER.indexOf(curr)\n return prevIndex >= 0 && currIndex === prevIndex + 1\n}\n\nconst formatConsecutiveGroupParts = (\n groups: number[][],\n formatRange: (start: number, end: number) => string,\n formatSingle: (item: number) => string,\n) => {\n const parts: string[] = []\n\n groups.forEach((group) => {\n if (group.length >= MIN_CONSECUTIVE_RANGE_LENGTH) {\n parts.push(formatRange(group[0], group[group.length - 1]))\n return\n }\n group.forEach((item) => {\n parts.push(formatSingle(item))\n })\n })\n\n return parts\n}\n\n/**\n * 每周:工作日 / 周六日 / 周一到周三 / 每周一、二、三\n */\nconst formatWeeklyRepeatDateText = (repeatValue: number[]) => {\n if (!repeatValue.length) {\n return ''\n }\n\n if (isSameNumberSet(repeatValue, WORKDAYS)) {\n return '工作日'\n }\n\n if (isSameNumberSet(repeatValue, WEEKEND)) {\n return '周六日'\n }\n\n const orderedDays = WEEK_ORDER.filter(day => repeatValue.includes(day))\n const groups = splitConsecutiveGroups(orderedDays, isConsecutiveWeekDayPair)\n const hasRange = groups.some(group => group.length >= MIN_CONSECUTIVE_RANGE_LENGTH)\n\n if (!hasRange) {\n const labels = orderedDays.map(day => WEEK_SHORT_LABEL_MAP[day])\n return `每周${labels.join('、')}`\n }\n\n const parts = formatConsecutiveGroupParts(\n groups,\n (start, end) => `周${WEEK_SHORT_LABEL_MAP[start]}到周${WEEK_SHORT_LABEL_MAP[end]}`,\n day => `周${WEEK_SHORT_LABEL_MAP[day]}`,\n )\n\n return parts.join('、')\n}\n\n/**\n * 每月:连续 >=3 用 1-20号;否则 每月4, 6号\n */\nconst formatMonthlyRepeatDateText = (repeatValue: number[]) => {\n if (!repeatValue.length) {\n return ''\n }\n\n const sortedDays = [...new Set(repeatValue)].sort((a, b) => a - b)\n const groups = splitConsecutiveGroups(sortedDays)\n const hasRange = groups.some(group => group.length >= MIN_CONSECUTIVE_RANGE_LENGTH)\n\n if (!hasRange) {\n return `每月${sortedDays.join(', ')}号`\n }\n\n const parts = formatConsecutiveGroupParts(\n groups,\n (start, end) => `${start} - ${end}号`,\n day => `${day}号`,\n )\n\n return parts.join('、')\n}\n\n/** 仅日期部分,不含时段。按天且未选具体日时返回空,由调用方补「每天」 */\nexport function formatAvailableRepeatDateText(options: IFormatAvailableRepeatOptions = {}) {\n const {\n repeatType = COUPON_AVAILABLE_REPEAT_TYPE_DAILY,\n repeatValue = [],\n } = options\n\n const days = parseCouponNumberList(repeatValue)\n\n if (repeatType === COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY) {\n return formatWeeklyRepeatDateText(days)\n }\n\n if (repeatType === COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY) {\n return formatMonthlyRepeatDateText(days)\n }\n\n return ''\n}\n\n/**\n * 日期 + 时段拼成一句,次卡列表等场景用。\n * 例:工作日08:00-11:00;都空时「全天」\n */\nexport function formatAvailableRepeatText(options: IFormatAvailableRepeatOptions = {}) {\n const {\n repeatType = COUPON_AVAILABLE_REPEAT_TYPE_DAILY,\n repeatValue = [],\n minuteSegments = [],\n } = options\n\n const dateText = formatAvailableRepeatDateText({\n repeatType,\n repeatValue,\n })\n const timeText = formatMinuteSegments(parseCouponNumberList(minuteSegments))\n\n return `${dateText}${timeText}` || '全天'\n}\n\n/**\n * 使用次数限制。例:每日2次、每周3次、每月5次;都没有则「不限制」\n */\nexport function formatUseLimitText(options: {\n daily?: number | string\n weekly?: number | string\n monthly?: number | string\n} = {}) {\n const parts: string[] = []\n const dailyNum = Number(options.daily) || 0\n const weeklyNum = Number(options.weekly) || 0\n const monthlyNum = Number(options.monthly) || 0\n\n if (dailyNum > 0) {\n parts.push(`每日${dailyNum}次`)\n }\n if (weeklyNum > 0) {\n parts.push(`每周${weeklyNum}次`)\n }\n if (monthlyNum > 0) {\n parts.push(`每月${monthlyNum}次`)\n }\n\n return parts.length ? parts.join('、') : '不限制'\n}\n","import * as hive from '@yorkjs/hive'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n formatAvailableRepeatDateText,\n formatUseLimitText,\n parseCouponNumberList,\n} from './availableRepeat'\n\nimport {\n COUPON_EXPAND_TYPE_EXTRA,\n COUPON_EXPAND_TYPE_NONE,\n COUPON_EXPAND_TYPE_REASON,\n COUPON_EXPIRE_MODE_DEADLINE,\n COUPON_EXPIRE_MODE_VALIDITY,\n COUPON_EFFECTIVE_END_TYPE_EXTEND,\n COUPON_EFFECTIVE_END_TYPE_FOREVER,\n COUPON_EFFECTIVE_END_TYPE_FUTURE,\n COUPON_EFFECTIVE_START_TYPE_FUTURE,\n COUPON_EFFECTIVE_START_TYPE_NOW,\n COUPON_THRESHOLD_TYPE_AMOUNT,\n COUPON_THRESHOLD_TYPE_COUNT,\n COUPON_TEMPLATE_STATUS_ONLINE,\n COUPON_STATUS_UNAVAILABLE_ERROR,\n COUPON_TYPE_DISCOUNT,\n} from './constant'\n\nimport {\n CouponExpandType,\n CouponExpireMode,\n CouponFormatItem,\n ICoupon,\n ICouponKvLine,\n ICouponViewItem,\n} from './type'\n\n/** id 统一转字符串再比,避免 number / string 回显对不上 */\nexport function isSameCouponId(a?: string | number, b?: string | number) {\n if (a == null || b == null) {\n return false\n }\n return String(a) === String(b)\n}\n\n/**\n * 接口是否给了不可用原因。\n * 0 / false / 空字符串视为没返回原因,避免把占位值当成 available_error。\n */\nfunction hasCouponApiAvailableError(error: unknown) {\n if (error == null || error === false || error === 0) {\n return false\n }\n if (typeof error === 'string') {\n return error.trim().length > 0\n }\n return !isEmpty(error)\n}\n\n/**\n * 可用态。\n * 1. availableError 有值:一定不可用\n * 2. 带了 status 则只有 2(已上线 / 已生效)可用\n * 3. 没带 status:没有 availableError 则可用(兼容列表只筛 status、项上不回传该字段)\n */\nexport function resolveCouponAvailable(coupon: Pick<ICoupon, 'availableError' | 'status'>) {\n if (hasCouponApiAvailableError(coupon.availableError)) {\n return false\n }\n if (coupon.status == null || coupon.status === ('' as any)) {\n return true\n }\n return Number(coupon.status) === COUPON_TEMPLATE_STATUS_ONLINE\n}\n\n/**\n * 展开用的不可用原因。\n * 接口 availableError 优先;没有时按已知状态补文案(草稿/下线/过期/注销/锁定),其它灰态不展开。\n */\nexport function resolveCouponAvailableError(coupon: Pick<ICoupon, 'availableError' | 'status'>) {\n if (hasCouponApiAvailableError(coupon.availableError)) {\n return String(coupon.availableError)\n }\n return COUPON_STATUS_UNAVAILABLE_ERROR[Number(coupon.status)] || ''\n}\n\n/**\n * 原始列表 → 标准 ICoupon。\n * 有 formatItem 就逐项转换(返回空则跳过);没有则把项当作已是 ICoupon。\n * 未带 original 时自动挂上原始 item。顺序与接口一致,不做可用/不可用重排。\n */\nexport function formatCouponList(rawList?: any[], formatItem?: CouponFormatItem): ICoupon[] {\n const source = Array.isArray(rawList) ? rawList : []\n const result: ICoupon[] = []\n\n source.forEach((item) => {\n const coupon = formatItem ? formatItem(item) : (item as ICoupon)\n if (!coupon || coupon.id == null) {\n return\n }\n const next: ICoupon = {\n ...coupon,\n original: coupon.original !== undefined ? coupon.original : item,\n }\n result.push(next)\n })\n\n return result\n}\n\nconst DISCOUNT_UNIT = '折'\n\n/**\n * 是否走折扣票面(折)。\n * couponType === 1 为折扣;2/3 为金额。\n */\nexport function isCouponDiscountBenefit(coupon: ICoupon): boolean {\n return Number(coupon.couponType) === COUPON_TYPE_DISCOUNT\n}\n\n/** 票面数字。满减走 formatAmount;折扣走 formatDiscount,只返回数字部分 */\nexport function formatCouponAmountValue(coupon: ICoupon): string {\n if (isEmpty(coupon.couponValue)) {\n return ''\n }\n if (isCouponDiscountBenefit(coupon)) {\n const formatted = hive.formatDiscount(Number(coupon.couponValue))\n if (!formatted || formatted === 'NaN折') {\n return ''\n }\n return formatted.endsWith(DISCOUNT_UNIT)\n ? formatted.slice(0, -DISCOUNT_UNIT.length)\n : formatted\n }\n\n // 票面大字用 5 而不是 5.00\n return stripAmountZero(hive.formatAmount(coupon.couponValue, ''))\n}\n\n/** 票面左侧前缀。满减 / 配送为 ¥,折扣为空 */\nexport function formatCouponAmountPrefix(coupon: ICoupon): string {\n if (!isCouponDiscountBenefit(coupon) && !isEmpty(coupon.couponValue)) {\n return '¥'\n }\n return ''\n}\n\n/** 票面右侧单位。折扣为「折」,满减 / 配送为空 */\nexport function formatCouponAmountSuffix(coupon: ICoupon): string {\n if (isCouponDiscountBenefit(coupon) && !isEmpty(coupon.couponValue)) {\n return DISCOUNT_UNIT\n }\n return ''\n}\n\n/**\n * 门槛展示值(不含「使用门槛:」)。\n * 由 thresholdType + thresholdValue 生成;0 为无门槛。\n */\nexport function formatCouponThreshold(coupon: ICoupon): string {\n const thresholdType = Number(coupon.thresholdType)\n const thresholdValue = Number(coupon.thresholdValue) || 0\n if (!thresholdValue) {\n return '无门槛'\n }\n if (thresholdType === COUPON_THRESHOLD_TYPE_COUNT) {\n return `满${thresholdValue}件`\n }\n if (thresholdType === COUPON_THRESHOLD_TYPE_AMOUNT) {\n return `满${stripAmountZero(hive.formatAmount(thresholdValue, ''))}元`\n }\n return '无门槛'\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000\n\nfunction formatExpireDate(timestamp?: number) {\n if (!timestamp) {\n return ''\n }\n return hive.formatDateTime(Number(timestamp))\n}\n\n/**\n * 算出券的截止时间戳。\n * 优惠券票面只要具体日期,和次卡「开始至结束 / 领取后 N 天」文案不是一套。\n * 有 effectiveEndTime 直接用;领取后 N 天则用开始时间(没有则当前时间)加上天数。\n */\nfunction resolveCouponExpireTimestamp(coupon: ICoupon): number | undefined {\n const endTime = Number(coupon.effectiveEndTime)\n if (Number.isFinite(endTime) && endTime > 0) {\n return endTime\n }\n\n const days = Number(coupon.effectiveEndDays)\n if (!Number.isFinite(days) || days <= 0) {\n return undefined\n }\n\n const startType = Number(coupon.effectiveStartType)\n const startTime = Number(coupon.effectiveStartTime)\n if (\n startType === COUPON_EFFECTIVE_START_TYPE_FUTURE\n && Number.isFinite(startTime)\n && startTime > 0\n ) {\n return startTime + days * DAY_MS\n }\n\n return Date.now() + days * DAY_MS\n}\n\n/**\n * 过期时间展示值(不含「过期时间:」)。\n * 给已发出的券实例用,只展示截止日期年月日时分,或永久有效。\n */\nexport function formatCouponExpireText(coupon: ICoupon): string {\n if (Number(coupon.effectiveEndType) === COUPON_EFFECTIVE_END_TYPE_FOREVER) {\n return '长期有效'\n }\n\n const expireDate = formatExpireDate(resolveCouponExpireTimestamp(coupon))\n if (expireDate) {\n return expireDate\n }\n\n return '长期有效'\n}\n\n/**\n * 有效期展示值(不含「有效期:」)。\n * 给发券选模板用,字段和次卡同一套开始/结束类型,不把「领取后 N 天」折成当前时间。\n */\nexport function formatCouponValidityText(coupon: ICoupon): string {\n const startType = Number(coupon.effectiveStartType) || COUPON_EFFECTIVE_START_TYPE_NOW\n const endType = Number(coupon.effectiveEndType)\n const startDate = formatExpireDate(coupon.effectiveStartTime)\n const endDate = formatExpireDate(coupon.effectiveEndTime)\n const days = coupon.effectiveEndDays\n\n if (startType === COUPON_EFFECTIVE_START_TYPE_NOW) {\n if (endType === COUPON_EFFECTIVE_END_TYPE_FOREVER) {\n return '自获取后永久有效'\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_FUTURE) {\n return endDate ? `自获取后截止${endDate}期间有效` : ''\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_EXTEND) {\n return days ? `自获取后${days}天内有效` : ''\n }\n }\n\n if (startType === COUPON_EFFECTIVE_START_TYPE_FUTURE) {\n if (endType === COUPON_EFFECTIVE_END_TYPE_FOREVER) {\n return startDate ? `${startDate}起永久有效` : ''\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_FUTURE) {\n return startDate && endDate ? `${startDate}至${endDate}有效` : ''\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_EXTEND) {\n return startDate && days ? `${startDate}起${days}天内有效` : ''\n }\n }\n\n return ''\n}\n\nfunction resolveExpireMode(expireMode?: CouponExpireMode) {\n return expireMode === COUPON_EXPIRE_MODE_VALIDITY\n ? COUPON_EXPIRE_MODE_VALIDITY\n : COUPON_EXPIRE_MODE_DEADLINE\n}\n\n/** 可用日期。按天未选具体日时为「每天」 */\nexport function formatCouponAvailableDateText(coupon: ICoupon): string {\n const dateText = formatAvailableRepeatDateText({\n repeatType: coupon.availableRepeatType,\n repeatValue: coupon.availableRepeatValue,\n })\n return dateText || '每天'\n}\n\n/** 可用时段。空或全天时段走 hive formatMinuteSegments,空数组为「全天」 */\nexport function formatCouponAvailableTimeText(coupon: ICoupon): string {\n const segments = parseCouponNumberList(coupon.availableMinuteSegments)\n if (!segments.length) {\n return '全天'\n }\n return hive.formatMinuteSegments(segments) || '全天'\n}\n\n/** 使用限制展示值(不含「使用限制:」)。无限制时为「不限制」 */\nexport function formatCouponUseLimitText(coupon: ICoupon): string {\n return formatUseLimitText({\n daily: coupon.useLimitCountDaily,\n weekly: coupon.useLimitCountWeekly,\n monthly: coupon.useLimitCountMonthly,\n })\n}\n\nfunction stripAmountZero(text: string) {\n return String(text).replace(/\\.00$/, '')\n}\n\n/** 把键值行拼成「键:值」;label 为空时只返回 value */\nexport function formatCouponKvText(line: ICouponKvLine): string {\n if (!line.label) {\n return line.value\n }\n return `${line.label}:${line.value}`\n}\n\n/** 票面信息区:使用门槛、过期时间 / 有效期 */\nexport function getCouponContentLines(\n coupon: ICoupon,\n expireMode?: CouponExpireMode,\n): ICouponKvLine[] {\n const lines: ICouponKvLine[] = []\n const threshold = formatCouponThreshold(coupon)\n if (threshold) {\n lines.push({ label: '使用门槛', value: threshold })\n }\n\n const mode = resolveExpireMode(expireMode)\n if (mode === COUPON_EXPIRE_MODE_VALIDITY) {\n const validityText = formatCouponValidityText(coupon)\n if (validityText) {\n lines.push({ label: '有效期', value: validityText })\n }\n return lines\n }\n\n const expireText = formatCouponExpireText(coupon)\n if (expireText) {\n lines.push({ label: '过期时间', value: expireText })\n }\n return lines\n}\n\nfunction isPresentNumber(value: unknown) {\n return value != null && value !== '' && !Number.isNaN(Number(value))\n}\n\n/** 是否带了可用日期 / 时段,用来决定要不要生成展开行 */\nexport function hasCouponAvailableRepeat(coupon: ICoupon) {\n return isPresentNumber(coupon.availableRepeatType)\n || !isEmpty(parseCouponNumberList(coupon.availableRepeatValue))\n || !isEmpty(parseCouponNumberList(coupon.availableMinuteSegments))\n}\n\n/** 是否带了使用限制字段(含 0,表示明确「不限制」也要展示) */\nexport function hasCouponUseLimit(coupon: ICoupon) {\n return coupon.useLimitCountDaily != null\n || coupon.useLimitCountWeekly != null\n || coupon.useLimitCountMonthly != null\n}\n\nfunction getCouponGeneratedExtraLines(coupon: ICoupon): ICouponKvLine[] {\n const lines: ICouponKvLine[] = []\n if (hasCouponAvailableRepeat(coupon)) {\n lines.push({ label: '可用日期', value: formatCouponAvailableDateText(coupon) })\n lines.push({ label: '可用时间', value: formatCouponAvailableTimeText(coupon) })\n }\n if (hasCouponUseLimit(coupon)) {\n lines.push({ label: '使用限制', value: formatCouponUseLimitText(coupon) })\n }\n return lines\n}\n\n/** 把「键:值」拆回键值行;没有分隔符则整句当 value */\nexport function parseCouponKvLine(text: string): ICouponKvLine {\n const match = String(text).match(/^(.+?)[::](.*)$/)\n if (match && match[1] && match[2] !== '') {\n return {\n label: match[1].trim(),\n value: match[2].trim(),\n }\n }\n return {\n label: '',\n value: String(text),\n }\n}\n\n/** 展开区键值行。extra 走 extraLines 或生成规则,reason 为本单不可用原因 */\nexport function getCouponExpandKvLines(coupon: ICoupon): ICouponKvLine[] {\n const expandType = getCouponExpandType(coupon)\n if (expandType === COUPON_EXPAND_TYPE_EXTRA) {\n if (coupon.extraLines && coupon.extraLines.length > 0) {\n return coupon.extraLines.map(parseCouponKvLine)\n }\n return getCouponGeneratedExtraLines(coupon)\n }\n if (expandType === COUPON_EXPAND_TYPE_REASON) {\n const reason = resolveCouponAvailableError(coupon)\n if (reason) {\n return [{\n label: '本单不可用原因',\n value: reason,\n }]\n }\n }\n return []\n}\n\n/** 当前券应展示的展开类型:extra / reason / none */\nexport function getCouponExpandType(coupon: ICoupon): CouponExpandType {\n if (resolveCouponAvailable(coupon)) {\n const hasExtraLines = !!(coupon.extraLines && coupon.extraLines.length > 0)\n const hasGeneratedExtra = hasCouponAvailableRepeat(coupon) || hasCouponUseLimit(coupon)\n return hasExtraLines || hasGeneratedExtra\n ? COUPON_EXPAND_TYPE_EXTRA\n : COUPON_EXPAND_TYPE_NONE\n }\n return isEmpty(resolveCouponAvailableError(coupon))\n ? COUPON_EXPAND_TYPE_NONE\n : COUPON_EXPAND_TYPE_REASON\n}\n\n/** 展开区展示文案。reason 只出原因正文,extra 为「键:值」 */\nexport function getCouponExpandLines(coupon: ICoupon): string[] {\n return getCouponExpandKvLines(coupon).map((line) => {\n if (getCouponExpandType(coupon) === COUPON_EXPAND_TYPE_REASON) {\n return line.value\n }\n return formatCouponKvText(line)\n })\n}\n\n/**\n * ICoupon → 票面数据。选券弹层和单独挂 CouponCard 共用。\n * selected / expanded 由调用方控制,available 由 availableError + status 推出。\n */\nexport function formatCouponViewItem(\n coupon: ICoupon,\n state: {\n selected?: boolean\n expanded?: boolean\n expireMode?: CouponExpireMode\n } = {},\n): ICouponViewItem {\n const expireMode = resolveExpireMode(state.expireMode)\n return {\n coupon,\n selected: !!state.selected,\n expanded: !!state.expanded,\n available: resolveCouponAvailable(coupon),\n amountPrefix: formatCouponAmountPrefix(coupon),\n amountValue: formatCouponAmountValue(coupon),\n amountSuffix: formatCouponAmountSuffix(coupon),\n title: coupon.title || '',\n contentLines: getCouponContentLines(coupon, expireMode).map(formatCouponKvText),\n expandType: getCouponExpandType(coupon),\n expandLines: getCouponExpandLines(coupon),\n }\n}\n\n/**\n * 原始项或 ICoupon → 票面。\n * 有 formatItem 时先映射;没有则把 source 当 ICoupon。\n * formatItem 跳过该项时返回 undefined。\n */\nexport function toCouponViewItem(\n source: any,\n state: {\n selected?: boolean\n expanded?: boolean\n formatItem?: CouponFormatItem\n expireMode?: CouponExpireMode\n } = {},\n): ICouponViewItem | undefined {\n const coupon = formatCouponList([source], state.formatItem)[0]\n if (!coupon) {\n return undefined\n }\n return formatCouponViewItem(coupon, {\n selected: state.selected,\n expanded: state.expanded,\n expireMode: state.expireMode,\n })\n}\n","import {\n COUPON_CONFIRM_EMPTY_MSG,\n COUPON_EXPAND_TYPE_REASON,\n} from './constant'\n\nimport {\n ICoupon,\n ICouponConfirmResult,\n ICouponSelectorOptions,\n ICouponSelectorView,\n ICouponViewItem,\n} from './type'\n\nimport {\n formatCouponList,\n formatCouponViewItem,\n getCouponExpandType,\n isSameCouponId,\n resolveCouponAvailable,\n} from './couponUtil'\n\n/**\n * 优惠券选择器(无 UI、不发请求)。\n *\n * 列表来源由调用方决定:静态 list 或接口拉完后 setList / appendList。\n * formatItem 只把后端字段收到 ICoupon(数字 / 枚举即可);\n * 门槛、过期、可用日期/时间、使用限制由 couponUtil 格式化,getView 产出 contentLines / expandLines。\n */\nexport class CouponSelector {\n private list: ICoupon[] = []\n private selectedId?: string | number\n /**\n * 调用方传入的回显 id。\n * 接口列表异步到达前不要丢掉;分页补齐后继续用它匹配。\n */\n private preferredSelectedId?: string | number\n private expandedIds: Array<string | number> = []\n private formatItem?: ICouponSelectorOptions['formatItem']\n private exclusiveExpand = false\n private expireMode?: ICouponSelectorOptions['expireMode']\n private onChange: () => void = () => {}\n\n constructor(options: ICouponSelectorOptions) {\n this.formatItem = options.formatItem\n this.exclusiveExpand = !!options.exclusiveExpand\n this.expireMode = options.expireMode\n this.onChange = options.onChange\n this.preferredSelectedId = this._normalizeSelectedId(options.value)\n if (options.list) {\n this.list = formatCouponList(options.list, this.formatItem)\n this._dedupeList()\n }\n this.selectedId = this._pickValidSelectedId(this.preferredSelectedId)\n }\n\n /** 全量替换列表,并清掉已不存在的选中 / 展开 */\n setList(list: any[]) {\n this.list = formatCouponList(list, this.formatItem)\n this._dedupeList()\n this._syncSelectedId()\n this.expandedIds = this.expandedIds.filter(id => this._findCoupon(id))\n this._notifyChange()\n }\n\n /** 分页追加,保持接口顺序,不把后一页可用券插到已渲染的过期券前面 */\n appendList(list: any[]) {\n const next = formatCouponList(list, this.formatItem)\n this.list = this.list.concat(next)\n this._dedupeList()\n this._syncSelectedId()\n this._notifyChange()\n }\n\n /** 当前列表票面快照,给 CouponCard 渲染 */\n getView(): ICouponSelectorView {\n const selectedCoupon = this._findCoupon(this.selectedId)\n return {\n items: this.list.map(coupon => this._toViewItem(coupon)),\n selectedId: this.selectedId,\n selectedCoupon,\n }\n }\n\n /**\n * 点票面。\n * 可用:选中,再点取消;不可用:不选中,只展开原因。\n */\n select(id: string | number) {\n const coupon = this._findCoupon(id)\n if (!coupon) {\n return\n }\n if (!resolveCouponAvailable(coupon)) {\n // 有不可用原因才展开;已知状态会补原因,其它灰态不展开\n if (getCouponExpandType(coupon) === COUPON_EXPAND_TYPE_REASON) {\n this._setExpanded(id, true)\n }\n this._notifyChange()\n return\n }\n this.selectedId = isSameCouponId(this.selectedId, id) ? undefined : coupon.id\n this.preferredSelectedId = this.selectedId\n this._notifyChange()\n }\n\n /** 点箭头,只切换展开,不改变选中 */\n toggleExpand(id: string | number) {\n const coupon = this._findCoupon(id)\n if (!coupon) {\n return\n }\n const expanded = this._isExpanded(id)\n this._setExpanded(id, !expanded)\n this._notifyChange()\n }\n\n /** 确认选中。未选可用券时 isValid 为 false */\n confirm(): ICouponConfirmResult {\n const coupon = this._findCoupon(this.selectedId)\n if (!coupon || !resolveCouponAvailable(coupon)) {\n return {\n isValid: false,\n errMsg: COUPON_CONFIRM_EMPTY_MSG,\n }\n }\n return {\n isValid: true,\n coupon,\n }\n }\n\n private _toViewItem(coupon: ICoupon): ICouponViewItem {\n return formatCouponViewItem(coupon, {\n selected: isSameCouponId(coupon.id, this.selectedId),\n expanded: this._isExpanded(coupon.id),\n expireMode: this.expireMode,\n })\n }\n\n /**\n * 同一 id 只保留第一次出现的项。\n * 置顶回显 / 分页重叠会出现两张相同券,选中态会同时亮。\n */\n private _dedupeList() {\n const seen = new Set<string>()\n this.list = this.list.filter((coupon) => {\n const key = String(coupon.id)\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n }\n\n private _findCoupon(id?: string | number) {\n const selectedId = this._normalizeSelectedId(id)\n if (selectedId == null) {\n return undefined\n }\n return this.list.find(item => isSameCouponId(item.id, selectedId))\n }\n\n /** 0 / 空字符串视为未选 */\n private _normalizeSelectedId(id?: string | number) {\n if (id == null || id === '' || id === 0 || id === '0') {\n return undefined\n }\n return id\n }\n\n /** 列表尚未包含该券时先留着 preferred,等 setList / appendList 再匹配 */\n private _syncSelectedId() {\n this.selectedId = this._pickValidSelectedId(\n this._normalizeSelectedId(this.selectedId) ?? this.preferredSelectedId,\n )\n }\n\n /** 回显只认当前列表里的可用券 */\n private _pickValidSelectedId(id?: string | number) {\n const coupon = this._findCoupon(id)\n if (!coupon || !resolveCouponAvailable(coupon)) {\n return undefined\n }\n return coupon.id\n }\n\n private _isExpanded(id: string | number) {\n return this.expandedIds.some(item => isSameCouponId(item, id))\n }\n\n private _setExpanded(id: string | number, expanded: boolean) {\n if (expanded) {\n if (this.exclusiveExpand) {\n this.expandedIds = [id]\n return\n }\n if (!this._isExpanded(id)) {\n this.expandedIds = this.expandedIds.concat(id)\n }\n return\n }\n this.expandedIds = this.expandedIds.filter(item => !isSameCouponId(item, id))\n }\n\n private _notifyChange() {\n this.onChange()\n }\n}\n"],"names":["isEmpty","value","isNaN","isEmptyValue","Object","prototype","toString","call","keys","length","trim","AdjoinMatrix","_createClass","vertx","_classCallCheck","_defineProperty","this","vertex","quantity","adjoinArray","init","key","fill","Array","id","sides","weight","_this","pIndex","indexOf","forEach","item","i","index","cur","push","_this2","col","params","_this3","paramsVertex","map","getVertexCol","collections","some","_this4","unions","type","row","filter","t","isItemEqual","includes","isArrayUnions","every","_t","SpecAdjoinMatrix","specList","specCombinationList","vertices","group","gi","list","concat","_callSuper","initSpec","initSameLevel","_inherits","specs","spec","fillInSpec","specsOption","getCollection","vertexId","specOptionCanchoose","Boolean","mappedParams","val","getUnions","param","setAdjoinVertexs","SpecSelector","options","productSpecGroupList","skuListAfter","_options$activitySpec","activitySpecList","specAdjoinMatrix","listIndex","find","name","selectedSpecs","optionSpecs","getSpecsOptions","_ref","title","items","isEnabled","isActive","isActivitySpec","groupIndex","_this$productSpecGrou","_this$productSpecGrou2","newSelectedSpecs","_toConsumableArray","currentGroupList","idx","validSelected","groupCount","sku","SKU_STOCK_COUNT_UNLIMITED","CHAGNE_TYPE_DECREASE","formatSkuWithPromotionActivitySaleInfoItem","promotionActivitySaleInfoItem","newSku","_objectSpread","activity_sku_id","origin_sku_id","is_promotion_activity","is_set_activity_price","sale_price","original_price","stock_count","formatProductComboChildrenSkuList","skuList","children","newSkuList","childItem","combo_sku","min_count","max_count","skuItem","newItem","per_order_min_limit","per_order_max_limit","formatProductSku","formatProductSkuList","promotionActivitySaleInfoList","isSelfActivity","mall_sku_id","saleInfoItem","formatProductActivitySkuList","formatProductSpecGroupList","useActivityFlag","newProductSpecGroupList","groupItem","newGroup","itemIds","item_ids","findItemIndex","findIndex","specValueItem","formatSpecList","formatSkuListAfter","specObj","negativeStockSaleEnabled","formatSpecObj","getSpecImage","productCover","_productSpecGroupList","specImage","undefined","image","getActivitySpecList","activitySpecItemList","formatProductBuyText","product","combo_type","select_type","checkProductOnSale","productStatus","hasStock","checkUseReducePlusBtn","formatProductStatus","arguments","formatSkuPrice","salePriceArr","minPrice","Math","min","apply","maxPrice","max","moneyToDisplay","formatPriceRange","priceRange","end_price","start_price","formatSkuListStockCount","sum","findProductCartList","cartList","activityProductId","findCartList","cartCount","productId","productCode","code","cartItem","cartItemProduct","cartItemExternalProduct","external_product","error","cart","count","formatWithExternalSku","externalSku","getSubmitCustomizationItemList","customizationItemList","pick","pickSubmitCustomizationItem","getSubmitCustomizationItemListArr","flattenDeep","calculateSelectedCustomizationPrice","customizationGroupList","price","selectedCustomizationItemList","customization_item","increase_type","increase_sale_price","selectedItem","timesNumber","formatCustomizationPrice","selectedCustomizationPrice","plusNumber","checkCustomizationItemListEqual","selectCustomizationItemList","cartCustomizationItemList","cartCustomizationItem","formatCustomizationGroupList","selected","selected_count","formatInitCustomizationItemList","formatSelectedCustomizationItemList","customizationGroupItem","customizationItems","customization","count_type","reconstructCustomizationItemList","newSelectedCustomizationItemList","newCustomizationGroupList","cloneDeep","groupItems","selectedItems","selectable","isValid","checkCustomizationItemList","errMsg","countTypeUnit","formatCountTypeUnit","customizationCount","countType","checkCustomizationItemIsUseSelectCount","customizationItem","checkCustomizationItemCanPlusCount","selectCount","checkCustomizationItemIsFixedSelected","checkCustomizationItemIsDisabledSelected","findCustomizationSkuCartItem","skuId","promotionActivityProduct","findCartItem","cartItemSku","cartItemSkuExternal","external_sku","cartItemCustomizationItemList","product_customization_item_list","genereateCartProductCustomizationItemList","submitSelectedCustomizationItemList","productCustomizationGroupList","orderSkuCustomizationItemList","customizationSalePrice","formatCustomizationGroupItemSelectTips","selectTips","selectedCount","join","handleCustomizationGroupItemSelectedChange","itemSelected","itemIndex","onChange","isSingleSelect","handleCustomizationGroupItemCountChange","handleCustomizationItemCountChange","newCount","onCountChange","itemMinCount","itemMaxCount","groupMaxCount","handleCustomizationItemToggleSelected","onSelectedChange","formatSkuNameWithCustomization","skuName","kindItemList","kindItemName","formatCustomizationCountType","itemList","formatCustomizationInfo","customizationInfos","isCountTypeQuantity","getSubmitComboItemList","skuComboItemList","comboProductCustomizationItemList","combo_product_customization_item_list","pickSubmitComboItem","getSubmitComboItemListArr","calculateSelectedComboPrice","skuComboGroupList","selectedComboItemList","hive","formatComboPrice","checkSkuComboItemListEqual","cartItemSkuComboItemList","cartItemComboItem","combo_sku_id","formatSkuComboItemName","combo_sku_name","comboSkuName","countTypeName","formatSkuComboItemList","checkComboGroupItemCanPlusCount","comboGroupItem","checkComboGroupItemIsCanChangeSelectCheckbox","_","checkComboItemIsFixedSelect","comboItem","checkComboItemIsUseSelectCheckbox","checkHasChildren","checkComboItemIsUseSelectCount","checkComboItemIsUseSelectSkuDialog","combo_product","formatComboSkuAndCustomizationName","combo_customization_item_list","checkItemCanPlusCount","canGroupPlus","formatIncreaseSalePrice","formatAmount","checkItemCanMinusCount","isFixedItem","canGroupMinus","checkGroupCanMinusCount","checkIsFixedSelectNeedSelectSku","checkIsUseSelectSkuBtn","getSkuComboItemGroup","groupMap","skuComboItem","combo_group_name","comboGroupName","reconstructComboGroupList","comboGroupList","newItems","findComboItem","child","_item$combo_sku$stock","_item$combo_sku","formatSelectSkuComboItemList","skuComboItems","combo_sku_type","selectItem","c","validateComboGroupList","_skuComboItemList$gro","skuComboCount","formatComboGroupItemSelectTips","repeatable","generateCartSkuComboItemList","handleSelectComboSkuSubmit","data","isComboChild","onComboChildChange","onComboSkuChange","setComboItemCountChange","handleComboItemCountChange","newComboGroupItem","handleComboGroupItemChildChange","comboGroupItem1","handleComboGroupItemSelected","handleComboGroupItemComboSkuChange","_comboItem$combo_sku$","_comboItem$combo_sku","isUseSelectCount","setToggleComboItemSelecte","toggleSelected","ComboSpecSelector","productData","channel1Type","_validateComboGroupList","_initProductData","_initSkuId","skuDetailData","_initCartItem$cart","_skuListAfter$skuInde","specType","_initSpecType","_initSkuListAfter","initCartItem","_findSkuCartItem","skuIndex","initSkuId","_initSkuDetail","_updateSkuData","isComponentLoading","_notifyChange","specValue","_selectSpec","_refreshCartItem","salePrice","getSalePrice","originalPrice","getOriginalPrice","memberPrice","getMemberPrice","maxCount","visibleComboInfo","isOption","_this$specList$","needFetchSkuDetail","matchedSku","isEqual","perOrderMinLimit","comboErrMsg","_validateCombo","countCheckResult","_checkProductCount","promotionActivityProductId","selectedSpecsIndex","isProductOnSale","status","has_stock","productStatusDesc","submitSkuComboItemList","channel1_type","checked","sku_id","sku_type","sku_combo_item_list","JSON","stringify","spec_type","_ref4","_skuListAfter$0$id","_skuListAfter$","_skuList$2","_ref3","_skuListAfter$skuInde2","_skuListAfter$skuInde3","_skuList$","_ref2","_skuList$0$id","_skuList$3","skuData","_this$cartItem","sku_combo_group_list","_skuCartItem$cart","stockCount","perOrderMaxLimit","minCount","skuCartItem","slice","_skuCartItem$cart2","CustomSpecSelector","_updateSkuCartItem","res","changed","emptyCartParams","buildCartCountParams","needFetchCart","cartParams","result","productCustomizationItemList","flattenCustomizationItemList","_getSkuType","_this$sku","targetSkuId","ChildCustomSelector","_options$exchangeRate","exchangeRate","_initCustomizationItemList","isScrollable","_formatSalePrice","_specList$","equal","countCheck","initCustomizationItemList","handleSelectSpecs","COUPON_TYPE_DISCOUNT","COUPON_TYPE_AMOUNT","COUPON_TYPE_FREIGHT","COUPON_THRESHOLD_TYPE_AMOUNT","COUPON_THRESHOLD_TYPE_COUNT","COUPON_EFFECTIVE_START_TYPE_NOW","COUPON_EFFECTIVE_START_TYPE_FUTURE","COUPON_EFFECTIVE_END_TYPE_FOREVER","COUPON_EFFECTIVE_END_TYPE_FUTURE","COUPON_EFFECTIVE_END_TYPE_EXTEND","COUPON_AVAILABLE_REPEAT_TYPE_DAILY","COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY","COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY","COUPON_STATUS_PENDING","COUPON_STATUS_ENABLED","COUPON_STATUS_USED","COUPON_STATUS_EXPIRED","COUPON_STATUS_CANCELED","COUPON_STATUS_LOCKED","COUPON_TEMPLATE_STATUS_DRAFT","COUPON_TEMPLATE_STATUS_ONLINE","COUPON_TEMPLATE_STATUS_OFFLINE","COUPON_TEMPLATE_STATUS_EXPIRED","COUPON_TEMPLATE_STATUS_UNAVAILABLE_ERROR","COUPON_STATUS_UNAVAILABLE_ERROR","COUPON_EXPAND_TYPE_EXTRA","COUPON_EXPAND_TYPE_REASON","COUPON_EXPAND_TYPE_NONE","COUPON_CONFIRM_EMPTY_MSG","COUPON_EXPIRE_MODE_DEADLINE","COUPON_EXPIRE_MODE_VALIDITY","WEEK_ORDER","WEEK_SHORT_LABEL_MAP","WORKDAYS","WEEKEND","isFullDayMinuteSegment","start","end","parseCouponNumberList","isArray","Number","isFinite","parsed","parse","split","isSameNumberSet","source","target","targetSet","Set","has","splitConsecutiveGroups","isConsecutivePair","prev","curr","groups","isConsecutiveWeekDayPair","prevIndex","currIndex","formatConsecutiveGroupParts","formatRange","formatSingle","parts","formatAvailableRepeatDateText","_options$repeatType","repeatType","_options$repeatValue","repeatValue","days","orderedDays","day","labels","formatWeeklyRepeatDateText","sortedDays","sort","a","b","formatMonthlyRepeatDateText","formatAvailableRepeatText","_options$repeatType2","_options$repeatValue2","_options$minuteSegmen","minuteSegments","dateText","timeText","formatMinuteSegments","formatUseLimitText","dailyNum","daily","weeklyNum","weekly","monthlyNum","monthly","isSameCouponId","String","hasCouponApiAvailableError","resolveCouponAvailable","coupon","availableError","resolveCouponAvailableError","formatCouponList","rawList","formatItem","next","original","isCouponDiscountBenefit","couponType","formatCouponAmountValue","couponValue","formatted","formatDiscount","endsWith","DISCOUNT_UNIT","stripAmountZero","formatCouponAmountPrefix","formatCouponAmountSuffix","formatCouponThreshold","thresholdType","thresholdValue","DAY_MS","formatExpireDate","timestamp","formatDateTime","formatCouponExpireText","effectiveEndType","expireDate","endTime","effectiveEndTime","effectiveEndDays","startType","effectiveStartType","startTime","effectiveStartTime","Date","now","resolveCouponExpireTimestamp","formatCouponValidityText","endType","startDate","endDate","resolveExpireMode","expireMode","formatCouponAvailableDateText","availableRepeatType","availableRepeatValue","formatCouponAvailableTimeText","segments","availableMinuteSegments","formatCouponUseLimitText","useLimitCountDaily","useLimitCountWeekly","useLimitCountMonthly","text","replace","formatCouponKvText","line","label","getCouponContentLines","lines","threshold","validityText","expireText","hasCouponAvailableRepeat","hasCouponUseLimit","parseCouponKvLine","match","getCouponExpandKvLines","expandType","getCouponExpandType","extraLines","getCouponGeneratedExtraLines","reason","hasExtraLines","hasGeneratedExtra","getCouponExpandLines","formatCouponViewItem","state","expanded","available","amountPrefix","amountValue","amountSuffix","contentLines","expandLines","toCouponViewItem","CouponSelector","exclusiveExpand","preferredSelectedId","_normalizeSelectedId","_dedupeList","selectedId","_pickValidSelectedId","_syncSelectedId","expandedIds","_findCoupon","selectedCoupon","_toViewItem","_setExpanded","_isExpanded","seen","add","_this$_normalizeSelec"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hive-biz.esm.min.js","sources":["../src/util/dataType.ts","../src/util/adjoinMartix.ts","../src/util/specAdjoinMartix.ts","../src/selector/specSelector.ts","../src/selector/constant.ts","../src/selector/productUtil.ts","../src/selector/customizationUtil.ts","../src/selector/comboUtil.ts","../src/selector/comboSpecSelector.ts","../src/selector/customSpecSelector.ts","../src/selector/childCustomSelector.ts","../src/coupon/constant.ts","../src/coupon/availableRepeat.ts","../src/coupon/couponUtil.ts","../src/coupon/couponSelector.ts"],"sourcesContent":["import {\n isNaN\n} from 'lodash-es'\n\n// 定义一个空字符串类型\ntype EmptyString = '' | ' '\n\n// 定义一个包含所有\"空\"值的联合类型\ntype EmptyValue = null | undefined | EmptyString | [] | Record<string, never> | typeof NaN\n\n// 空值: {}, [], '', ' ', null, undefined, NaN\nexport function isEmpty(value: any): value is EmptyValue {\n if (value == null\n || isNaN(value)\n ) {\n return true\n }\n let isEmptyValue = false\n const protoType = Object.prototype.toString.call(value)\n switch (protoType) {\n\n case '[object Object]':\n isEmptyValue = Object.keys(value).length === 0\n break\n\n case '[object Array]':\n isEmptyValue = value.length === 0\n break\n\n case '[object String]':\n if (value.trim().length === 0) {\n isEmptyValue = true\n }\n break\n\n default:\n break\n }\n\n return isEmptyValue\n}\n","import { fill } from 'lodash-es'\n\nexport default class AdjoinMatrix {\n vertex = [] // 顶点数组\n quantity = 0 // 矩阵长度\n adjoinArray = [] // 矩阵数组\n\n constructor(vertx) {\n this.vertex = vertx\n this.quantity = this.vertex.length\n this.adjoinArray = []\n this.init()\n }\n // 初始化数组\n init() {\n this.adjoinArray = fill(new Array(this.quantity * this.quantity), 0)\n }\n\n /*\n * @param id string\n * @param sides Array<string>\n * 传入一个顶点,和当前顶点可达的顶点数组,将对应位置设置权值\n */\n setAdjoinVertexs(id, sides, weight) {\n const pIndex = this.vertex.indexOf(id)\n sides.forEach((item, i) => {\n const index = this.vertex.indexOf(item)\n const cur = this.adjoinArray[pIndex * this.quantity + index]\n if (typeof cur !== 'number') { // specList.length > 3时,存在单边多权的情况\n this.adjoinArray[pIndex * this.quantity + index].push(weight)\n }\n else if (cur > 1) {\n this.adjoinArray[pIndex * this.quantity + index] = [cur, weight]\n }\n else {\n this.adjoinArray[pIndex * this.quantity + index] = weight\n }\n })\n }\n\n /*\n * @param id string\n * 传入顶点的值,获取该顶点的列\n */\n getVertexCol(id) {\n const index = this.vertex.indexOf(id)\n const col = []\n this.vertex.forEach((item, pIndex) => {\n col.push(this.adjoinArray[index + this.quantity * pIndex])\n })\n return col\n }\n\n /*\n * @param params Array<string>\n * 传入一个顶点数组,求出并集\n */\n getCollection(params) {\n const paramsVertex = params.map(id => this.getVertexCol(id))\n let collections = []\n paramsVertex.forEach((col, index) => {\n if (col.some(item => item !== 0)) {\n collections.push(params[index])\n }\n })\n return collections\n }\n\n /*\n * @param params Array<string>\n * 传入一个顶点数组,求出交集\n */\n getUnions(params) {\n const paramsVertex = params.map(id => this.getVertexCol(id))\n let unions = []\n this.vertex.forEach((type, index) => {\n const row = paramsVertex.map(col => col[index]).filter(t => t !== 1)\n if (this.isItemEqual(row)) {\n unions.push(type)\n }\n })\n return unions\n }\n\n /*\n * @param params\n * 传入一个交集行,判断内部是否互相相等\n */\n isItemEqual(params) {\n if (params.includes(0)) {\n return false\n }\n\n let weight = -1\n\n // 找出权值\n if (params.length) {\n params.some(t => {\n if (typeof t === 'number') {\n weight = t\n }\n return typeof t === 'number'\n })\n if (weight === -1) { // 都是多权边数组的情况\n return this.isArrayUnions(params)\n }\n }\n\n return params.every(t => {\n if (typeof t === 'number') {\n return t === weight\n } \n else {\n return t.includes(weight)\n }\n })\n }\n\n /*\n * @param params\n * 传入多个数组,判断是否有交集\n */\n isArrayUnions(params) {\n if (!params.length) {\n return false\n }\n return params[0].some(t => {\n return params.every(_t => _t.includes(t))\n })\n }\n}\n","import AdjoinMatrix from \"./adjoinMartix\"\n\nexport default class SpecAdjoinMatrix extends AdjoinMatrix {\n specList = []\n specCombinationList = []\n\n constructor(specList, specCombinationList) {\n // 使用 \"组索引_值\" 作为唯一顶点标识,避免不同组同名规格被当作同一顶点\n const vertices: string[] = []\n specList.forEach((group, gi) => {\n group.list.forEach(value => {\n vertices.push(`${gi}_${value}`)\n })\n })\n super(vertices)\n this.specList = specList\n\n this.specCombinationList = specCombinationList\n // 根据可选规格列表矩阵创建\n this.initSpec()\n // 同级顶点创建\n this.initSameLevel()\n }\n\n /**\n * 根据可选规格组合填写邻接矩阵的值\n */\n initSpec() {\n this.specCombinationList.forEach((item, index) => {\n // 将 SKU 规格按组索引映射为唯一标识\n const specs = item.specs.map((spec, gi) => `${gi}_${spec}`)\n this.fillInSpec(specs, index + 2) // 0用于互不相连,1用于同级,权级就从2开始\n })\n }\n // 填写同级点\n initSameLevel() {\n // 获得初始所有可选项\n const specsOption = this.getCollection(this.vertex)\n this.specList.forEach((group, gi) => {\n const params = []\n // 获取同级别顶点\n group.list.forEach(value => {\n const vertexId = `${gi}_${value}`\n if (specsOption.includes(vertexId)) {\n params.push(vertexId)\n }\n })\n // 同级点位创建\n this.fillInSpec(params, 1)\n })\n }\n /*\n * @params\n * 传入顶点数组(按组索引排列的已选规格值),查询出可选规格\n */\n getSpecsOptions(params) {\n let specOptionCanchoose: string[] = []\n if (params.some(Boolean)) {\n // 将 flat selectedSpecs 映射为 \"组索引_值\" 唯一标识再求交集\n const mappedParams = params.map((val, gi) => (val ? `${gi}_${val}` : '')).filter(Boolean)\n specOptionCanchoose = this.getUnions(mappedParams)\n }\n else {\n // 所有可选项\n specOptionCanchoose = this.getCollection(this.vertex)\n }\n return specOptionCanchoose\n }\n\n /*\n * @params\n * 填写邻接矩阵的值\n */\n fillInSpec(params, weight) {\n params.forEach(param => {\n this.setAdjoinVertexs(param, params, weight)\n })\n }\n}\n","import { find } from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\nimport SpecAdjoinMatrix from '../util/specAdjoinMartix'\n\nimport {\n ISpecList,\n ISkuCombination,\n IProductSpecItem,\n} from './type'\n\nexport interface ISpecSelectorOptions {\n /** 规格组列表,包含每组规格标题和可选值 */\n productSpecGroupList: ISpecList[]\n /** 格式化后的 sku 组合列表 */\n skuListAfter: ISkuCombination[]\n /** 活动规格列表,二维数组,与 productSpecGroupList 下标对应 */\n activitySpecList?: IProductSpecItem[][]\n}\n\nexport interface ISpecItemState {\n /** 规格值 */\n value: string\n /** 是否可选(未被禁用) */\n isEnabled: boolean\n /** 是否已选中 */\n isActive: boolean\n /** 是否是活动规格 */\n isActivitySpec: boolean\n}\n\nexport interface ISpecGroupState {\n /** 规格组标题 */\n title: string\n /** 该组下所有规格项的状态 */\n items: ISpecItemState[]\n}\n\nexport class SpecSelector {\n private productSpecGroupList: ISpecList[]\n private skuListAfter: ISkuCombination[]\n private activitySpecList: IProductSpecItem[][]\n private specAdjoinMatrix: InstanceType<typeof SpecAdjoinMatrix>\n\n constructor(options: ISpecSelectorOptions) {\n const { productSpecGroupList, skuListAfter, activitySpecList = [] } = options\n\n this.productSpecGroupList = productSpecGroupList\n this.skuListAfter = skuListAfter\n this.activitySpecList = activitySpecList\n this.specAdjoinMatrix = new SpecAdjoinMatrix(productSpecGroupList, skuListAfter)\n }\n\n /**\n * 判断某个规格值是否是活动规格\n * @param listIndex 规格组下标\n * @param value 规格值\n */\n isActivitySpec(listIndex: number, value: string): boolean {\n if (isEmpty(this.activitySpecList)) {\n return false\n }\n\n return !!find(this.activitySpecList[listIndex], item => item.name === value)\n }\n\n /**\n * 根据当前已选规格,获取所有规格组的渲染状态\n * @param selectedSpecs 当前已选规格值数组\n */\n getSpecGroupStateList(selectedSpecs: string[]): ISpecGroupState[] {\n const optionSpecs = this.specAdjoinMatrix.getSpecsOptions(selectedSpecs)\n\n return this.productSpecGroupList.map(({ title, list }, listIndex) => {\n const items: ISpecItemState[] = list.map(value => {\n // 使用 \"组索引_值\" 唯一标识检查可选性,避免跨组同名规格误匹配\n const isEnabled = optionSpecs.indexOf(`${listIndex}_${value}`) !== -1\n // 按组索引检查是否选中,避免跨组同名规格误匹配\n const isActive = selectedSpecs[listIndex] === value\n\n const isActivitySpec = this.isActivitySpec(listIndex, value)\n\n return {\n value,\n isEnabled,\n isActive,\n isActivitySpec,\n }\n })\n\n return { title, items }\n })\n }\n\n /**\n * 根据当前已选规格,获取可选规格值列表(扁平数组)\n * @param selectedSpecs 当前已选规格值数组\n */\n getOptionSpecs(selectedSpecs: string[]): string[] {\n return this.specAdjoinMatrix.getSpecsOptions(selectedSpecs)\n }\n\n /**\n * 处理规格选择/取消选择,返回新的已选规格数组\n * @param isEnabled 当前规格是否可选\n * @param value 被点击的规格值\n * @param groupIndex 规格组下标\n * @param selectedSpecs 当前已选规格值数组\n */\n toggleSpec(\n isEnabled: boolean,\n value: string,\n groupIndex: number,\n selectedSpecs: string[],\n ): string[] {\n if (!isEnabled) {\n return selectedSpecs\n }\n\n const newSelectedSpecs = [...selectedSpecs]\n const currentGroupList = this.productSpecGroupList[groupIndex]?.list ?? []\n\n if (newSelectedSpecs.indexOf(value) !== -1) {\n // 已选中 → 取消选中\n newSelectedSpecs[groupIndex] = ''\n }\n else {\n // 未选中 → 选中,同时清除同组内原来的选中项\n currentGroupList.forEach(item => {\n const idx = newSelectedSpecs.indexOf(item)\n if (idx !== -1) {\n newSelectedSpecs[idx] = ''\n }\n })\n newSelectedSpecs[groupIndex] = value\n }\n\n return newSelectedSpecs\n }\n\n /**\n * 根据当前已选规格找到匹配的 sku 组合\n * @param selectedSpecs 当前已选规格值数组\n */\n findMatchedSku(selectedSpecs: string[]): ISkuCombination | undefined {\n const validSelected = selectedSpecs.filter(Boolean)\n const groupCount = this.productSpecGroupList.length\n\n if (validSelected.length !== groupCount) {\n return undefined\n }\n\n return this.skuListAfter.find(sku =>\n validSelected.every(spec => sku.specs.includes(spec))\n )\n }\n\n /**\n * 判断规格是否已全部选完\n * @param selectedSpecs 当前已选规格值数组\n */\n isAllSpecSelected(selectedSpecs: string[]): boolean {\n const groupCount = this.productSpecGroupList.length\n return selectedSpecs.filter(spec => !isEmpty(spec)).length === groupCount\n }\n}\n","export const VALUE_UNDEFINED = -1\n\nexport const ENTITY_BOOL_YES = 1\nexport const ENTITY_BOOL_NO = 2\n\n// 无(第三方使用)\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_NONE = 1\n// 全部 sku\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_ALL = 2\n// 部分 sku\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_PART = 3\n// 某一个 sku\nexport const SKU_COMBO_ITEM_COMBO_SKU_TYPE_ONE = 4\n\n\nexport const SKU_STOCK_COUNT_UNLIMITED = 10000000\n\n// 商品规格\nexport const MALL_PRODUCT_SPEC_TYPE_SINGLE = 1\nexport const MALL_PRODUCT_SPEC_TYPE_MULTIPLE = 2\n\n// 商城商品 sku(原来企服系统里的商品sku),sku_id 传商城 sku ID\nexport const ORDER_EXTERNAL_SKU_TYPE_MALL = 0\n// 促销活动 sku,sku_id 传促销活动 sku ID\nexport const ORDER_EXTERNAL_SKU_TYPE_MARKETING_PROMOTION_ACTIVITY = 1\n\n// 商品组合\nexport const PRODUCT_COMBO_TYPE_SINGLE = 1\nexport const PRODUCT_COMBO_TYPE_MULTIPLE = 2\n\n// 添加购物车,是否要弹对话框\nexport const PRODUCT_SELECT_TYPE_DIRECT = 1\nexport const PRODUCT_SELECT_TYPE_DIALOG = 2\n\n// 店铺类型\nexport const SHOP_TYPE_DISTRIBUTOR = 1\nexport const SHOP_TYPE_PROMOTER = 2\nexport const SHOP_TYPE_MAHUA = 3\n\n// 做法计数类型\nexport const CUSTOMIZATION_COUNT_TYPE_KIND = 1\nexport const CUSTOMIZATION_COUNT_TYPE_QUANTITY = 2\n\n// 免费\nexport const CUSTOMIZATION_ITEM_INCREASE_TYPE_FREE = 1\n// 固定加价\nexport const CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED = 2\n\nexport const CHAGNE_TYPE_DECREASE = 'decrease'\nexport const CHAGNE_TYPE_INCREASE = 'increase'\nexport const CHAGNE_TYPE_EDIT = 'edit'\n\n// 商品类型\nexport const PRODUCT_STATUS_ALL = -1 // 全部\nexport const PRODUCT_STATUS_ONLINE = 1 // 上架\nexport const PRODUCT_STATUS_OFFLINE = 2 // 下架\n","import {\n find,\n findIndex,\n} from \"lodash-es\"\n\nimport {\n moneyToDisplay\n} from '@yorkjs/hive'\n\nimport {\n ENTITY_BOOL_NO,\n ENTITY_BOOL_YES,\n SHOP_TYPE_MAHUA,\n PRODUCT_STATUS_ONLINE,\n PRODUCT_COMBO_TYPE_MULTIPLE,\n PRODUCT_SELECT_TYPE_DIALOG,\n VALUE_UNDEFINED,\n PRODUCT_SELECT_TYPE_DIRECT,\n} from \"./constant\"\n\nimport {\n ISku,\n IFormatSku,\n IProductSpecGroup,\n IProductSpecItem,\n\n ICartListItem,\n IFindProductCart,\n\n ISpecList,\n ISkuCombination,\n ISpecObj,\n IImage,\n ISkuComboChildItem,\n ISimpleProduct,\n IProductPriceRange,\n IExternalSku,\n IProductPromotionActivitySaleInfoItem,\n} from \"./type\"\nimport { isEmpty } from \"../util/dataType\"\n\n// 合并 sku\nexport function formatSkuWithPromotionActivitySaleInfoItem(\n sku: ISku,\n promotionActivitySaleInfoItem: IProductPromotionActivitySaleInfoItem,\n): IFormatSku {\n const newSku: IFormatSku = {\n ...sku,\n id: promotionActivitySaleInfoItem.activity_sku_id,\n\n origin_sku_id: sku.id,\n is_promotion_activity: true,\n is_set_activity_price: false,\n }\n\n if (promotionActivitySaleInfoItem.sale_price !== VALUE_UNDEFINED\n && promotionActivitySaleInfoItem.sale_price !== sku.sale_price\n ) {\n // 新的原价则设置为老的 sku 的售价\n newSku.original_price = sku.sale_price\n newSku.sale_price = promotionActivitySaleInfoItem.sale_price\n newSku.is_set_activity_price = true\n }\n\n if (promotionActivitySaleInfoItem.stock_count !== VALUE_UNDEFINED) {\n newSku.stock_count = promotionActivitySaleInfoItem.stock_count\n }\n\n return newSku\n}\n\n// 格式化组合商品 children skuList 列表\nexport function formatProductComboChildrenSkuList(\n skuList: IFormatSku[],\n children: ISkuComboChildItem[]\n) {\n const newSkuList: IFormatSku[] = []\n\n children.forEach(function (childItem) {\n const {\n combo_sku,\n min_count,\n max_count,\n } = childItem\n\n const sku = find(skuList, skuItem => skuItem.id === combo_sku.id)\n if (!sku) {\n return\n }\n\n const newItem: IFormatSku = {\n ...sku,\n }\n\n if (min_count > 0) {\n newItem.per_order_min_limit = min_count\n }\n\n if (max_count > 0) {\n newItem.per_order_max_limit = max_count\n }\n\n newSkuList.push(newItem)\n })\n\n return newSkuList\n}\n\n// 格式化 sku\nexport function formatProductSku(\n sku: ISku,\n) {\n return {\n ...sku,\n origin_sku_id: sku.id,\n is_promotion_activity: false,\n is_set_activity_price: false,\n }\n}\n\n// 格式化商品 skuList 列表\nexport function formatProductSkuList(\n skuList: ISku[],\n promotionActivitySaleInfoList?: IProductPromotionActivitySaleInfoItem[],\n isSelfActivity?: boolean,\n): IFormatSku[] {\n if (promotionActivitySaleInfoList) {\n return formatProductActivitySkuList(skuList, promotionActivitySaleInfoList, isSelfActivity)\n }\n\n return skuList.map(sku => {\n return formatProductSku(sku)\n })\n}\n\n// 格式化活动商品 skuList 列表\nfunction formatProductActivitySkuList(\n skuList: ISku[],\n promotionActivitySaleInfoList: IProductPromotionActivitySaleInfoItem[],\n isSelfActivity?: boolean,\n): IFormatSku[] {\n\n // 1.1 活动为商家自建\n if (isSelfActivity) {\n return skuList.map(sku => {\n const promotionActivitySaleInfoItem: IProductPromotionActivitySaleInfoItem | undefined = find(promotionActivitySaleInfoList, item => item.mall_sku_id === sku.id)\n\n let newSku: IFormatSku = formatProductSku(sku)\n\n if (promotionActivitySaleInfoItem) {\n newSku = formatSkuWithPromotionActivitySaleInfoItem(sku, promotionActivitySaleInfoItem)\n }\n\n return newSku\n })\n }\n\n // 1.2 活动非商家自建\n return promotionActivitySaleInfoList.map(saleInfoItem => {\n const skuItem: ISku | undefined = find(skuList, item => item.id === saleInfoItem.mall_sku_id)\n\n return formatSkuWithPromotionActivitySaleInfoItem(skuItem!, saleInfoItem)\n })\n}\n\n// 格式化 productSpecGroupList 规格\nexport function formatProductSpecGroupList(\n skuList: IFormatSku[],\n productSpecGroupList: IProductSpecGroup[],\n useActivityFlag?: boolean,\n): IProductSpecGroup[] {\n const newProductSpecGroupList: IProductSpecGroup[] = []\n\n productSpecGroupList.forEach((groupItem, groupIndex) => {\n const {\n items,\n } = groupItem\n\n const newGroup: IProductSpecGroup = {\n ...groupItem,\n items: [],\n }\n\n skuList.forEach(item => {\n const itemIds = item.item_ids\n\n const findItemIndex = findIndex(items, function (value: IProductSpecItem) {\n return value.id === itemIds[groupIndex]\n })\n\n if (findItemIndex === -1) {\n return\n }\n\n // 判断规格值是否已经存在,不存在则添加\n const specValueItem = items[findItemIndex]\n const specValueIndex = findIndex(newGroup.items, function (value: IProductSpecItem) {\n return value.id === specValueItem.id\n })\n\n if (specValueIndex === -1) {\n if (item.is_promotion_activity && useActivityFlag) {\n specValueItem.is_promotion_activity = true\n }\n\n newGroup.items.push(specValueItem)\n }\n })\n\n newProductSpecGroupList.push(newGroup)\n })\n\n return newProductSpecGroupList\n}\n\n// 格式化 specList\nexport function formatSpecList(\n productSpecGroupList: IProductSpecGroup[],\n): ISpecList[] {\n return productSpecGroupList.map(groupItem => ({\n title: groupItem.spec.name,\n list: groupItem.items.map(item => item.name),\n }))\n}\n\n// 格式化 formatSkuListAfter\nexport function formatSkuListAfter(\n skuList: IFormatSku[],\n specObj: ISpecObj,\n negativeStockSaleEnabled?: boolean,\n): ISkuCombination[] {\n const skuListAfter: ISkuCombination[] = []\n\n skuList.map(item => {\n if (negativeStockSaleEnabled || item.stock_count > 0) {\n skuListAfter.push({\n ...item,\n specs: item.item_ids.map(id => specObj[id]),\n })\n }\n })\n\n return skuListAfter\n}\n\n// 格式化 specObj\nexport function formatSpecObj(\n productSpecGroupList: IProductSpecGroup[],\n): ISpecObj {\n const specObj = {}\n\n productSpecGroupList.forEach(groupItem => {\n groupItem.items.forEach(item => {\n specObj[item.id] = item.name\n })\n })\n\n return specObj\n}\n\n// 获取 specImage\nexport function getSpecImage(\n productSpecGroupList: IProductSpecGroup[],\n productCover: IImage,\n): IImage {\n let specImage = productCover\n\n if (productSpecGroupList.length !== 0) {\n if (productSpecGroupList[0].items[0]?.image !== undefined) {\n specImage = productSpecGroupList[0].items[0].image\n }\n }\n\n return specImage\n}\n\n// 获取活动规格列表\nexport function getActivitySpecList(\n productSpecGroupList: IProductSpecGroup[],\n): IProductSpecItem[][] {\n const activitySpecList: IProductSpecItem[][] = []\n\n productSpecGroupList.forEach(groupItem => {\n const activitySpecItemList: IProductSpecItem[] = []\n\n groupItem.items.forEach(item => {\n if (item.is_promotion_activity) {\n activitySpecItemList.push(item)\n }\n })\n\n activitySpecList.push(activitySpecItemList)\n })\n\n return activitySpecList\n}\n\n// 购买文字\nexport function formatProductBuyText(\n product: ISimpleProduct,\n): string {\n const {\n combo_type,\n select_type,\n } = product\n\n const isMultiComboType = combo_type === PRODUCT_COMBO_TYPE_MULTIPLE\n const isDialogSelect = select_type === PRODUCT_SELECT_TYPE_DIALOG\n\n if (isMultiComboType) {\n return '选套餐'\n }\n\n // 组合商品\n if (isDialogSelect) {\n return '选规格'\n }\n\n return '加入购物车'\n}\n\n// 商品是否在销售中\nexport function checkProductOnSale(productStatus: number, hasStock: number): boolean {\n return productStatus === PRODUCT_STATUS_ONLINE && hasStock === ENTITY_BOOL_YES\n}\n\n// 列表中商品是否使用加减按钮\nexport function checkUseReducePlusBtn(\n product: ISimpleProduct,\n) {\n const {\n combo_type,\n select_type,\n } = product\n\n const isMultiComboType = combo_type === PRODUCT_COMBO_TYPE_MULTIPLE\n const isDirectSelect = select_type === PRODUCT_SELECT_TYPE_DIRECT\n\n // 组合商品\n if (isMultiComboType) {\n return false\n }\n\n return isDirectSelect\n}\n\nexport function formatProductStatus(\n productStatus: number,\n hasStock: number,\n skuDeleted: number = ENTITY_BOOL_NO\n): string {\n if (productStatus === PRODUCT_STATUS_ONLINE && skuDeleted === ENTITY_BOOL_NO) {\n return hasStock === ENTITY_BOOL_YES ? '销售中' : '已售罄'\n }\n\n return '已下架'\n}\n\n\nexport function formatSkuPrice(skuList: ISku[]): string {\n const salePriceArr = skuList.map(item => item.sale_price)\n const minPrice = Math.min(...salePriceArr) || 0\n const maxPrice = Math.max(...salePriceArr) || 0\n\n if (minPrice === maxPrice) {\n return `¥${moneyToDisplay(minPrice)}`\n }\n\n return `¥${moneyToDisplay(minPrice)} ~ ¥${moneyToDisplay(maxPrice)}`\n}\n\n\nexport function formatPriceRange(priceRange: IProductPriceRange): string {\n const {\n end_price,\n start_price,\n } = priceRange\n\n if (start_price === end_price) {\n return `¥${moneyToDisplay(start_price)}`\n }\n\n return `¥${moneyToDisplay(start_price)}~${moneyToDisplay(end_price)}`\n}\n\nexport function formatSkuListStockCount(list: ISku[]): number {\n let sum = 0\n list.forEach(item => {\n sum += item.stock_count\n })\n return sum\n}\n\n// 注意有可能是活动商品\nexport function findProductCartList(\n cartList: ICartListItem[],\n product: ISimpleProduct,\n activityProductId?: number\n): IFindProductCart {\n const findCartList: IFindProductCart = {\n cartList: [],\n cartCount: 0,\n }\n\n const productId = product.id\n const productCode = product.code\n\n cartList.forEach(cartItem => {\n const cartItemProduct = cartItem.product\n const cartItemExternalProduct = cartItem.external_product\n\n // 过滤掉错误商品\n if (cartItem.error) {\n return\n }\n\n if (activityProductId) {\n if (cartItemExternalProduct?.id === activityProductId) {\n findCartList.cartList.push(cartItem)\n findCartList.cartCount += cartItem.cart.count\n }\n }\n else {\n if (productId) {\n if (cartItemProduct.id === productId) {\n findCartList.cartList.push(cartItem)\n findCartList.cartCount += cartItem.cart.count\n }\n }\n else if (cartItemProduct.code === productCode) {\n findCartList.cartList.push(cartItem)\n findCartList.cartCount += cartItem.cart.count\n }\n }\n })\n\n return findCartList\n}\n\n// 合并 sku\nexport function formatWithExternalSku(sku: ISku, externalSku?: IExternalSku): ISku {\n if (isEmpty(externalSku)) {\n return sku\n }\n\n const newSku = {\n ...sku,\n ...externalSku,\n }\n\n if (externalSku.sale_price === -1) {\n newSku.sale_price = sku.sale_price\n }\n else {\n // 新的原价则设置为老的 sku 的售价\n newSku.original_price = sku.sale_price\n }\n\n if (externalSku.stock_count === -1) {\n newSku.stock_count = sku.stock_count\n }\n\n return newSku\n}\n","import {\n pick,\n find,\n every,\n filter,\n cloneDeep,\n flattenDeep,\n} from 'lodash-es'\n\nimport { plusNumber, timesNumber } from '@yorkjs/hive'\n\nimport {\n ICartListItem,\n ICustomizationItem,\n IOrderSkuCustomizationItem,\n IProduct,\n IProductCustomizationGroupItem,\n IProductCustomizationGroupItemView,\n IProductCustomizationItemView,\n IProductSelectedCustomizationItem,\n IPromotionActivityProduct,\n ISubmitSelectedCustomizationItem\n} from './type'\n\nimport {\n ENTITY_BOOL_NO,\n ENTITY_BOOL_YES,\n CUSTOMIZATION_COUNT_TYPE_KIND,\n CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED,\n CUSTOMIZATION_COUNT_TYPE_QUANTITY,\n} from './constant'\nimport { isEmpty } from '../util/dataType'\n\ninterface ISelectedCustomizationItem {\n id: number\n count: number\n}\n\nfunction pickSubmitCustomizationItem(customizationItemList: ISelectedCustomizationItem): ISubmitSelectedCustomizationItem {\n return pick(customizationItemList, ['id', 'count'])\n}\n\nexport function getSubmitCustomizationItemList(customizationItemList: ISelectedCustomizationItem[]): ISubmitSelectedCustomizationItem[] {\n const submitItemList = customizationItemList.map(item => {\n return pickSubmitCustomizationItem(item)\n })\n\n return submitItemList\n}\n\n// 格式化二维选中的组合商品\nexport function getSubmitCustomizationItemListArr(customizationItemList: ISelectedCustomizationItem[][]): ISubmitSelectedCustomizationItem[] {\n return getSubmitCustomizationItemList(flattenDeep(customizationItemList))\n}\n\n// 计算做法选中的价格\nexport function calculateSelectedCustomizationPrice(\n customizationGroupList: IProductCustomizationGroupItemView[],\n customizationItemList: IProductSelectedCustomizationItem[][]\n): number {\n\n let price = 0\n const selectedCustomizationItemList = flattenDeep(customizationItemList)\n\n customizationGroupList.forEach((groupItem) => {\n const {\n items,\n } = groupItem\n\n items.forEach(item => {\n const {\n id,\n customization_item,\n } = item\n\n const {\n increase_type,\n increase_sale_price,\n } = customization_item\n\n const selectedItem = find(selectedCustomizationItemList, selectedItem => selectedItem.id === id)\n if (selectedItem && increase_type === CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED) {\n price += timesNumber(increase_sale_price, selectedItem.count)\n }\n })\n })\n\n return price\n}\n\nexport function formatCustomizationPrice(\n price: number,\n customizationGroupList: IProductCustomizationGroupItemView[],\n customizationItemList?: IProductSelectedCustomizationItem[][]\n): number {\n if (price === -1) {\n return price\n }\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(customizationGroupList, customizationItemList || [])\n\n return plusNumber(price, selectedCustomizationPrice)\n}\n\n// 比较做法值列表是否相等, 数组长度一致,且 id 和 count 一致\nexport function checkCustomizationItemListEqual(selectCustomizationItemList: IProductSelectedCustomizationItem[], cartCustomizationItemList: IOrderSkuCustomizationItem[]) {\n return selectCustomizationItemList.length === cartCustomizationItemList.length &&\n every(selectCustomizationItemList, item => {\n return find(cartCustomizationItemList, cartCustomizationItem => {\n // 做法值的 id 和 count 一致才是相等\n return cartCustomizationItem.id === item.id && cartCustomizationItem.count === item.count\n })\n })\n}\n\n // 格式化做法数据\nexport function formatCustomizationGroupList(\n customizationGroupList: IProductCustomizationGroupItem[]\n): IProductCustomizationGroupItemView[] {\n return customizationGroupList.map(group => {\n const newGroup: IProductCustomizationGroupItemView = {\n ...group,\n items: [],\n }\n\n newGroup.items = group.items.map(item => {\n const {\n count,\n selected,\n } = item\n\n // 初始化 selected_count 为 0\n const newItem: IProductCustomizationItemView = {\n ...item,\n selected_count: 0,\n }\n\n // 选中了,则设置 selected_count 为 count\n if (selected === ENTITY_BOOL_YES) {\n newItem.selected_count = count\n }\n\n return newItem\n })\n\n return newGroup\n })\n}\n\n// 初始化选中的做法值列表\nexport function formatInitCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[]\n): IProductSelectedCustomizationItem[][] {\n return formatSelectedCustomizationItemList(customizationGroupList)\n}\n\nexport function formatSelectedCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[]\n): IProductSelectedCustomizationItem[][] {\n const customizationItemList: IProductSelectedCustomizationItem[][] = []\n\n customizationGroupList.forEach(customizationGroupItem => {\n const customizationItems: IProductSelectedCustomizationItem[] = []\n\n const {\n items,\n customization,\n } = customizationGroupItem\n\n items.forEach(item => {\n const {\n id,\n count,\n selected,\n selected_count,\n customization_item,\n } = item\n\n if (selected === ENTITY_BOOL_YES) {\n customizationItems.push({\n id,\n name: customization_item.name,\n // NOTE: 初始可能没有 selected_count,设置为 count\n count: selected_count || count,\n count_type: customization.count_type,\n })\n }\n })\n\n customizationItemList.push(customizationItems)\n })\n\n return customizationItemList\n}\n\n// 回填做法值列表\nexport function reconstructCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[],\n selectedCustomizationItemList: IProductSelectedCustomizationItem[]\n): {\n isValid: boolean\n customizationGroupList: IProductCustomizationGroupItemView[],\n selectedCustomizationItemList: IProductSelectedCustomizationItem[][]\n} {\n const newSelectedCustomizationItemList: IProductSelectedCustomizationItem[][] = []\n\n // NOTE: 复制一份,避免修改原数据\n const copyCustomizationGroupList = cloneDeep(customizationGroupList)\n const newCustomizationGroupList: IProductCustomizationGroupItemView[] = copyCustomizationGroupList.map(group => {\n const groupItems = cloneDeep(group.items)\n const customization = group.customization\n\n const selectedItems: IProductSelectedCustomizationItem[] = []\n\n groupItems.forEach(item => {\n const {\n id,\n count,\n selected,\n selectable,\n customization_item,\n } = item\n\n const selectedItem = find(selectedCustomizationItemList, selectedItem => selectedItem.id === item.id)\n if (selectedItem) {\n selectedItems.push(selectedItem)\n\n item.selected_count = selectedItem.count\n item.selected = ENTITY_BOOL_YES\n }\n else {\n if (selectable === ENTITY_BOOL_NO) {\n // 固定选中的,加到选择列表中\n if (selected === ENTITY_BOOL_YES) {\n selectedItems.push({\n id,\n name: customization_item.name,\n count,\n count_type: customization.count_type,\n })\n }\n }\n else {\n // 不在选中列表中,强制设置为未选中\n item.selected_count = 0\n item.selected = ENTITY_BOOL_NO\n }\n }\n })\n\n newSelectedCustomizationItemList.push(selectedItems)\n\n return {\n ...group,\n items: groupItems,\n }\n })\n\n // 校验回填的是否正确\n const res = checkCustomizationItemList(newCustomizationGroupList, newSelectedCustomizationItemList)\n\n return {\n isValid: res.isValid,\n customizationGroupList: newCustomizationGroupList,\n selectedCustomizationItemList: newSelectedCustomizationItemList,\n }\n}\n\n// 校验选中的做法值列表\nexport function checkCustomizationItemList(\n customizationGroupList: IProductCustomizationGroupItemView[],\n customizationItemList: IProductSelectedCustomizationItem[][]\n): {\n isValid: boolean\n errMsg: string\n} {\n let isValid = true\n let errMsg = ''\n\n customizationGroupList.forEach((customizationGroupItem, index) => {\n const {\n customization,\n min_count,\n max_count,\n } = customizationGroupItem\n\n const {\n count_type,\n } = customization\n\n const countTypeUnit = formatCountTypeUnit(count_type)\n\n // 有报错,直接返回\n if (!isValid) {\n return\n }\n\n let customizationCount = 0\n customizationItemList[index].forEach(item => {\n customizationCount += item.count\n })\n\n // 分组被选中商品个数不足\n if (customizationCount < min_count) {\n isValid = false\n errMsg = `【${customization.name}】:至少选择 ${min_count} ${countTypeUnit}`\n\n // 单选\n if (max_count === 1) {\n errMsg = `请选择【${customization.name}】`\n }\n\n return\n }\n\n if (customizationCount > max_count) {\n isValid = false\n errMsg = `【${customization.name}】:最多选择 ${max_count} ${countTypeUnit}`\n return\n }\n })\n\n return {\n isValid,\n errMsg,\n }\n}\n\nexport function formatCountTypeUnit(countType: number) {\n if (countType === CUSTOMIZATION_COUNT_TYPE_KIND) {\n return '种'\n }\n return '份'\n}\n\nexport const checkCustomizationItemIsUseSelectCount = (customizationItem: IProductCustomizationItemView) => {\n const {\n selectable,\n min_count,\n max_count,\n } = customizationItem\n\n // 是否需要选择份数\n return selectable === ENTITY_BOOL_YES &&\n min_count !== max_count &&\n max_count > 1\n}\n\nexport const checkCustomizationItemCanPlusCount = (customizationGroupItem: IProductCustomizationGroupItemView) => {\n const {\n max_count,\n } = customizationGroupItem\n\n // 检测数量是否超过最大值\n let selectCount = 0\n customizationGroupItem.items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.selected_count\n }\n })\n\n return max_count === -1 || selectCount < max_count\n}\n\nexport const checkCustomizationItemIsFixedSelected = (customizationItem: IProductCustomizationItemView) => {\n const {\n selected,\n selectable,\n } = customizationItem\n\n // 是否固定选中\n return selectable === ENTITY_BOOL_NO &&\n selected === ENTITY_BOOL_YES\n}\n\n// 是否禁用选中\nexport const checkCustomizationItemIsDisabledSelected = (customizationItem: IProductCustomizationItemView) => {\n const {\n selected,\n selectable,\n } = customizationItem\n\n // 是否禁用选中\n return selectable === ENTITY_BOOL_NO &&\n selected === ENTITY_BOOL_NO\n}\n\n// 获取当前商品,对应 skuId 在购物车中的数据\nexport function findCustomizationSkuCartItem(\n item: {\n skuId?: number\n product: IProduct\n promotionActivityProduct?: IPromotionActivityProduct\n customizationItemList?: IProductSelectedCustomizationItem[][]\n },\n cartList: ICartListItem[]\n): ICartListItem | undefined {\n if (isEmpty(cartList)) {\n return\n }\n\n const {\n skuId,\n product,\n promotionActivityProduct,\n customizationItemList,\n } = item\n\n const findCartItem = find(cartList, (cartItem: ICartListItem) => {\n const productId = product.id\n const productCode = product.code\n\n const cartItemProduct = cartItem.product\n const cartItemExternalProduct = cartItem.external_product\n\n // 1. 判断购物车商品是否是当前商品\n let isProductFind = false\n // 优先使用活动商品 id 进行比较\n if (cartItemExternalProduct) {\n isProductFind = cartItemExternalProduct.id === promotionActivityProduct?.id\n }\n else {\n isProductFind = productId ?\n cartItemProduct.id === productId :\n cartItemProduct.code === productCode\n }\n\n if (!isProductFind) {\n return false\n }\n\n // 2. 如果没有 skuId,则匹配到商品即可\n if (!skuId) {\n return true\n }\n\n const cartItemSku = cartItem.sku\n const cartItemSkuExternal = cartItem.external_sku\n // 3. 判断 sku_id 是否一样,优先使用活动 sku_id\n const isSkuEqual = cartItemSkuExternal ?\n cartItemSkuExternal.id === skuId :\n cartItemSku.id === skuId\n\n if (!isSkuEqual) {\n return false\n }\n\n const cartItemCustomizationItemList = cartItem.product_customization_item_list || []\n // 4. 如果做法值列表为空,则匹配到商品 + sku_id 即可\n if (isEmpty(customizationItemList) && isEmpty(cartItemCustomizationItemList)) {\n return true\n }\n\n const flattenCustomizationItemList = flattenDeep(customizationItemList)\n\n // 5. 比较做法值列表是否相等, 数组长度一致,且 id 和 count 一致\n return checkCustomizationItemListEqual(flattenCustomizationItemList, cartItemCustomizationItemList)\n })\n\n return findCartItem ? cloneDeep(findCartItem) : undefined\n}\n\nexport function genereateCartProductCustomizationItemList(\n submitSelectedCustomizationItemList: ISubmitSelectedCustomizationItem[] | undefined,\n productCustomizationGroupList: IProductCustomizationGroupItem[] | undefined\n): {\n orderSkuCustomizationItemList: IOrderSkuCustomizationItem[]\n customizationSalePrice: number\n} {\n // 根据选中的做法,生成购物车中的商品做法\n const orderSkuCustomizationItemList: IOrderSkuCustomizationItem[] = []\n let customizationSalePrice = 0\n\n if (isEmpty(submitSelectedCustomizationItemList) || isEmpty(productCustomizationGroupList)) {\n return {\n orderSkuCustomizationItemList,\n customizationSalePrice,\n }\n }\n\n productCustomizationGroupList.forEach(group => {\n const groupItems = group.items\n const customization = group.customization\n\n groupItems.forEach((item: ICustomizationItem) => {\n const {\n id,\n customization_item,\n } = item\n\n const selectedItem: ISubmitSelectedCustomizationItem | undefined = find(submitSelectedCustomizationItemList,\n (selectedItem: ISubmitSelectedCustomizationItem) => selectedItem.id === id)\n\n if (selectedItem) {\n orderSkuCustomizationItemList.push({\n ...selectedItem,\n name: customization_item.name,\n count_type: customization.count_type,\n })\n\n if (customization_item.increase_type === CUSTOMIZATION_ITEM_INCREASE_TYPE_FIXED) {\n customizationSalePrice = plusNumber(customizationSalePrice, timesNumber(customization_item.increase_sale_price, selectedItem.count))\n }\n }\n })\n })\n\n return {\n orderSkuCustomizationItemList,\n customizationSalePrice,\n }\n}\n\nexport function formatCustomizationGroupItemSelectTips(customizationGroupItem: IProductCustomizationGroupItemView): string {\n const { items, min_count, max_count, customization } = customizationGroupItem\n const selectTips: string[] = []\n const countTypeUnit = formatCountTypeUnit(customization.count_type)\n\n if (min_count === max_count) {\n selectTips.push(`请选择${min_count}${countTypeUnit}`)\n } else {\n if (min_count > 0) {\n selectTips.push(`至少选择${min_count}${countTypeUnit}`)\n }\n if (max_count > 0) {\n selectTips.push(`最多可选${max_count}${countTypeUnit}`)\n }\n }\n\n let selectedCount = 0\n items.forEach(item => {\n selectedCount += item.selected_count\n })\n\n if (selectedCount > 0) {\n selectTips.push(`已选${selectedCount}${countTypeUnit}`)\n }\n\n return selectTips.join(',')\n}\n\nexport function handleCustomizationGroupItemSelectedChange(\n group: IProductCustomizationGroupItemView,\n itemSelected: number,\n itemIndex: number,\n onChange?: (item: IProductCustomizationGroupItemView) => void\n) {\n const newGroup: IProductCustomizationGroupItemView = cloneDeep(group)\n const customizationItem = newGroup.items[itemIndex]\n\n const {\n items: groupItems,\n max_count\n } = newGroup\n\n const isSingleSelect = max_count === 1\n\n // 统计已选中的个数\n let selectedCount = 0\n groupItems.forEach((item, index) => {\n const {\n count,\n selected,\n selected_count\n } = item\n\n if (index === itemIndex) {\n if (itemSelected === ENTITY_BOOL_YES) {\n selectedCount += count\n }\n return\n }\n if (selected === ENTITY_BOOL_YES) {\n selectedCount += selected_count\n }\n })\n\n if (!isSingleSelect && selectedCount > max_count) {\n return\n }\n\n if (isSingleSelect) {\n newGroup.items.forEach((item, index) => {\n if (index !== itemIndex) {\n item.selected = ENTITY_BOOL_NO\n item.selected_count = 0\n }\n })\n }\n\n customizationItem.selected = itemSelected\n customizationItem.selected_count = itemSelected === ENTITY_BOOL_YES\n ? customizationItem.count\n : 0\n\n onChange?.(newGroup)\n}\n\nexport function handleCustomizationGroupItemCountChange(\n group: IProductCustomizationGroupItemView,\n count: number,\n index: number,\n onChange?: (item: IProductCustomizationGroupItemView) => void\n) {\n const newGroup: IProductCustomizationGroupItemView = cloneDeep(group)\n const customizationItem = newGroup.items[index]\n\n customizationItem.selected_count = count\n customizationItem.selected = count === 0\n ? ENTITY_BOOL_NO\n : ENTITY_BOOL_YES\n\n onChange?.(newGroup)\n}\n\nexport function handleCustomizationItemCountChange(\n customizationItem: IProductCustomizationItemView,\n customizationGroupItem: IProductCustomizationGroupItemView,\n newCount: number,\n onCountChange?: (count: number) => void\n) {\n const { items } = customizationGroupItem\n\n const {\n min_count,\n max_count,\n customization_item,\n } = customizationItem\n\n const itemMinCount = min_count\n const itemMaxCount = max_count\n const groupMaxCount = customizationGroupItem.max_count\n\n // 计算已选数量\n let selectCount = 0\n items.forEach(item => {\n if (item.customization_item.id === customization_item.id) {\n selectCount += newCount\n }\n else {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.selected_count\n }\n }\n })\n\n if (groupMaxCount !== -1 && selectCount > groupMaxCount) {\n return\n }\n if (itemMaxCount !== -1 && newCount > itemMaxCount) {\n return\n }\n\n if (newCount < itemMinCount) {\n onCountChange?.(0)\n return\n }\n\n onCountChange?.(newCount)\n}\n\nexport function handleCustomizationItemToggleSelected(\n customizationItem: IProductCustomizationItemView,\n onSelectedChange?: (selected: number) => void\n) {\n const {\n selected,\n selectable\n } = customizationItem\n\n if (selectable !== ENTITY_BOOL_YES) {\n return\n }\n\n const newSelected = selected === ENTITY_BOOL_YES\n ? ENTITY_BOOL_NO\n : ENTITY_BOOL_YES\n\n onSelectedChange?.(newSelected)\n}\n\nexport function formatSkuNameWithCustomization(\n skuName?: string,\n customizationItemList?: IOrderSkuCustomizationItem[]\n): string {\n const kindItemList = filter(customizationItemList || [], item => item.count_type === CUSTOMIZATION_COUNT_TYPE_KIND)\n\n if (isEmpty(kindItemList)) {\n return skuName || ''\n }\n\n const kindItemName = kindItemList.map(item => item.name).join('、')\n\n return skuName ? `${skuName}、${kindItemName}` : kindItemName\n}\n\n// 格式化做法中数量类型的做法\nexport function formatCustomizationCountType(\n customizationItemList?: IOrderSkuCustomizationItem[]\n): string {\n const itemList = filter(customizationItemList || [], item => item.count_type !== CUSTOMIZATION_COUNT_TYPE_KIND)\n if (isEmpty(itemList)) {\n return ''\n }\n\n return itemList.map(item => `${item.name}x${item.count}`).join('、')\n}\n\nexport function formatCustomizationInfo(\n customizationItemList?: IOrderSkuCustomizationItem[]\n): string {\n\n let customizationInfos: string[] = []\n\n if (isEmpty(customizationItemList)) {\n return ''\n }\n\n customizationItemList.map(item => {\n const {\n name,\n count,\n count_type,\n } = item\n\n const isCountTypeQuantity = count_type === CUSTOMIZATION_COUNT_TYPE_QUANTITY\n\n customizationInfos.push(`${name}${isCountTypeQuantity ? ` x${count}` : ''}`)\n })\n\n return customizationInfos.join('、')\n}\n","import {\n pick,\n find,\n every,\n cloneDeep,\n flattenDeep,\n} from 'lodash-es'\n\nimport * as hive from '@yorkjs/hive'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n ISkuComboChildItem,\n ICartSkuComboItem,\n ISelectSkuComboItem,\n ISkuComboGroupItem,\n ISkuComboGroupList,\n ISkuComboItem,\n ISubmitSelectSkuComboItem,\n ISkuPopupSbumitData,\n ISkuPopupSubmitData\n} from './type'\n\nimport {\n formatCustomizationCountType,\n formatSkuNameWithCustomization,\n checkCustomizationItemListEqual,\n getSubmitCustomizationItemList\n} from './customizationUtil'\n\nimport {\n ENTITY_BOOL_NO,\n ENTITY_BOOL_YES,\n SKU_COMBO_ITEM_COMBO_SKU_TYPE_NONE,\n SKU_STOCK_COUNT_UNLIMITED,\n PRODUCT_SELECT_TYPE_DIALOG,\n} from './constant'\n\nfunction pickSubmitComboItem(skuComboItemList: ISelectSkuComboItem): ISubmitSelectSkuComboItem {\n const item: ISubmitSelectSkuComboItem = pick(skuComboItemList, ['id', 'count', 'combo_sku_id', 'combo_product_customization_item_list'])\n\n const comboProductCustomizationItemList = item.combo_product_customization_item_list\n if (comboProductCustomizationItemList) {\n item.combo_product_customization_item_list = getSubmitCustomizationItemList(comboProductCustomizationItemList)\n }\n\n return item\n}\n\nexport function getSubmitComboItemList(skuComboItemList: ISelectSkuComboItem[]): ISubmitSelectSkuComboItem[] {\n const comboItemList = skuComboItemList.map(item => {\n return pickSubmitComboItem(item)\n })\n\n return comboItemList\n}\n\n// 格式化二维选中的组合商品\nexport function getSubmitComboItemListArr(skuComboItemList: ISelectSkuComboItem[][]): ISubmitSelectSkuComboItem[] {\n return getSubmitComboItemList(flattenDeep(skuComboItemList))\n}\n\n// 计算做法选中的价格\nexport function calculateSelectedComboPrice(\n skuComboGroupList: ISkuComboGroupItem[],\n skuComboItemList: ISelectSkuComboItem[][]\n): number {\n\n let price = 0\n const selectedComboItemList = flattenDeep(skuComboItemList)\n\n skuComboGroupList.forEach((groupItem) => {\n const {\n items,\n } = groupItem\n\n items.forEach(item => {\n const {\n id,\n increase_sale_price,\n } = item\n\n const selectedItem = find(selectedComboItemList, selectedItem => selectedItem.id === id)\n if (selectedItem && increase_sale_price > 0) {\n price += hive.timesNumber(increase_sale_price, selectedItem.count)\n }\n })\n })\n\n return price\n}\n\nexport function formatComboPrice(price: number, skuComboGroupList: ISkuComboGroupItem[], skuComboItemList?: ISelectSkuComboItem[][]): number {\n if (price === -1) {\n return price\n }\n\n const selectedCustomizationPrice = calculateSelectedComboPrice(skuComboGroupList, skuComboItemList || [])\n\n return hive.plusNumber(price, selectedCustomizationPrice)\n}\n\n// 5. 比较套餐值列表是否相等, 数组长度一致,且 id 和 count 一致\nexport function checkSkuComboItemListEqual(\n skuComboItemList: ISelectSkuComboItem[],\n cartItemSkuComboItemList: ICartSkuComboItem[]\n): boolean {\n return skuComboItemList.length === cartItemSkuComboItemList.length &&\n every(skuComboItemList, item => {\n return find(cartItemSkuComboItemList, cartItemComboItem => {\n // 做法值的 id 和 count 不一致,不匹配\n if (cartItemComboItem.id !== item.id || cartItemComboItem.count !== item.count) {\n return false\n }\n\n // 套餐值的 combo_sku_id 不一致,不匹配\n if (cartItemComboItem.combo_sku_id !== item.combo_sku_id) {\n return false\n }\n\n // 做法值的 combo_product_customization_item_list 不一致,不匹配\n const cartItemCustomizationItemList = cartItemComboItem.combo_product_customization_item_list || []\n const customizationItemList = item.combo_product_customization_item_list || []\n\n // 做法值列表都为空,匹配到商品 + sku_id 即可\n if (isEmpty(customizationItemList) && isEmpty(cartItemCustomizationItemList)) {\n return true\n }\n\n return checkCustomizationItemListEqual(customizationItemList, cartItemCustomizationItemList)\n })\n })\n}\n\n\nexport function formatSkuComboItemName(item: ICartSkuComboItem) {\n const {\n name,\n combo_sku_name,\n combo_product_customization_item_list\n } = item\n\n let skuName = name\n\n if (combo_product_customization_item_list) {\n const comboSkuName = formatSkuNameWithCustomization(combo_sku_name, combo_product_customization_item_list)\n skuName = comboSkuName ? `${name}(${comboSkuName})` : name\n\n const countTypeName = formatCustomizationCountType(combo_product_customization_item_list)\n if (countTypeName) {\n skuName = `${skuName}、${countTypeName}`\n }\n }\n\n return skuName\n}\n\nexport function formatSkuComboItemList(skuComboItemList: ICartSkuComboItem[]) {\n if (isEmpty(skuComboItemList)) {\n return ''\n }\n\n const skuNameList = skuComboItemList.map(item => formatSkuComboItemName(item))\n\n return skuNameList.join('+')\n}\n\n// 判断本组是否可以增加数量\nexport function checkComboGroupItemCanPlusCount(comboGroupItem: ISkuComboGroupItem): boolean {\n const {\n items,\n max_count,\n } = comboGroupItem\n\n // 检测数量是否超过最大值\n let selectCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n })\n\n return max_count === -1 || selectCount < max_count\n}\n\n// 判断是否可以改变选择框的状态\nexport function checkComboGroupItemIsCanChangeSelectCheckbox(comboGroupItem: ISkuComboGroupItem, selected: number): boolean {\n\n const {\n items,\n min_count,\n max_count\n } = comboGroupItem\n\n // 统计已选中的个数\n let selectedCount = 0\n items.forEach((item, _) => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectedCount++\n }\n })\n\n if (selected === ENTITY_BOOL_NO) {\n // 至少一个\n if (min_count === 1 && selectedCount <= 1) {\n return false\n }\n }\n else {\n // 如果是多选\n if (max_count > 1) {\n // 如果选中已达上限,则不能选中\n if (selectedCount >= max_count) {\n return false\n }\n }\n }\n\n return true\n}\n\nexport function checkComboItemIsFixedSelect(comboItem: ISkuComboItem): boolean {\n const {\n selected,\n selectable,\n } = comboItem\n\n return selected === ENTITY_BOOL_YES && selectable === ENTITY_BOOL_NO\n}\n\n// 判断是否使用选择框\nexport function checkComboItemIsUseSelectCheckbox(comboItem: ISkuComboItem): boolean {\n const {\n selectable,\n } = comboItem\n\n if (selectable === ENTITY_BOOL_NO) {\n return false\n }\n\n if (checkHasChildren(comboItem)) {\n return false\n }\n\n if (checkComboItemIsUseSelectCount(comboItem)) {\n return false\n }\n\n return true\n}\n\nexport function checkHasChildren(comboItem: ISkuComboItem): boolean {\n const {\n children,\n } = comboItem\n\n // 是否是定制\n return !isEmpty(children)\n}\n\n\nexport function checkComboItemIsUseSelectCount(comboItem: ISkuComboItem): boolean {\n const {\n min_count,\n max_count,\n } = comboItem\n\n // 是否需要选择份数\n return min_count !== max_count && max_count > 1\n}\n\n// 是否使用弹框选择商品\nexport function checkComboItemIsUseSelectSkuDialog(comboItem: ISkuComboItem) {\n const {\n combo_product,\n } = comboItem\n\n return combo_product?.select_type === PRODUCT_SELECT_TYPE_DIALOG\n}\n\n\nexport function formatComboSkuAndCustomizationName(comboItem: ISkuComboItem): string {\n const {\n combo_sku,\n combo_customization_item_list,\n } = comboItem\n\n if (isEmpty(combo_sku)) {\n return ''\n }\n\n let skuName = formatSkuNameWithCustomization(combo_sku.name, flattenDeep(combo_customization_item_list))\n\n const countTypeName = formatCustomizationCountType(flattenDeep(combo_customization_item_list))\n if (countTypeName) {\n skuName = `${skuName}、${countTypeName}`\n }\n\n return skuName\n}\n\n// 判断本组是否可以增加数量\nexport function checkItemCanPlusCount(comboGroupItem: ISkuComboGroupItem, comboItem: ISkuComboItem): boolean {\n const {\n selected,\n count,\n max_count,\n } = comboItem\n\n const canGroupPlus = checkComboGroupItemCanPlusCount(comboGroupItem)\n\n if (!canGroupPlus || selected === ENTITY_BOOL_NO) {\n return canGroupPlus\n }\n\n return count < max_count\n}\n\nexport function formatIncreaseSalePrice(comboItem: ISkuComboItem): string {\n const {\n increase_sale_price,\n } = comboItem\n\n return increase_sale_price > 0 ? `¥${hive.formatAmount(increase_sale_price, '')}` : ''\n}\n\n// 判断本项是否可以减少数量\nexport function checkItemCanMinusCount(comboGroupItem: ISkuComboGroupItem, comboItem: ISkuComboItem): boolean {\n const {\n count,\n min_count,\n } = comboItem\n\n const isFixedItem = checkComboItemIsFixedSelect(comboItem)\n const canGroupMinus = checkGroupCanMinusCount(comboGroupItem)\n\n if (!isFixedItem) {\n return canGroupMinus\n }\n\n return count > min_count\n}\n\n// 判断本组是否可以减少数量\nexport function checkGroupCanMinusCount(comboGroupItem: ISkuComboGroupItem): boolean {\n const {\n items,\n } = comboGroupItem\n\n // 检测数量是否超过最大值\n let selectCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n })\n\n return selectCount > 0\n}\n\n// 判断固定选中的是否需要选规格\nexport function checkIsFixedSelectNeedSelectSku(comboItem: ISkuComboItem): boolean {\n const {\n selected,\n selectable,\n } = comboItem\n\n if (selectable === ENTITY_BOOL_YES || selected === ENTITY_BOOL_NO) {\n return false\n }\n\n return checkComboItemIsUseSelectSkuDialog(comboItem)\n}\n\n// 判断是否使用选规格按钮\nexport function checkIsUseSelectSkuBtn(comboItem: ISkuComboItem) {\n const {\n combo_sku,\n combo_product,\n } = comboItem\n\n if (combo_product?.select_type !== PRODUCT_SELECT_TYPE_DIALOG) {\n return false\n }\n\n if (combo_sku) {\n return false\n }\n\n return true\n}\n\nexport function getSkuComboItemGroup(\n skuComboItemList: ICartSkuComboItem[]\n): ISkuComboGroupList[] {\n // 以 combo_group_name 分组\n const groupMap: Record<string, ICartSkuComboItem[]> = {}\n\n skuComboItemList.forEach((skuComboItem) => {\n const {\n combo_group_name\n } = skuComboItem\n\n const groupItem = groupMap[combo_group_name]\n if (groupItem) {\n groupItem.push(skuComboItem)\n }\n else {\n groupMap[combo_group_name] = [skuComboItem]\n }\n })\n\n return Object.keys(groupMap).map((comboGroupName) => {\n const list = groupMap[comboGroupName]\n\n return {\n comboGroupName,\n list\n }\n })\n}\n\n\n/** 将购物车数据回填到 comboGroupList */\nexport function reconstructComboGroupList(\n comboGroupList: ISkuComboGroupItem[],\n skuComboItemList?: ICartSkuComboItem[]\n): ISkuComboGroupItem[] {\n if (isEmpty(skuComboItemList)) {\n return comboGroupList\n }\n\n return comboGroupList.map(comboGroupItem => {\n const newItems = comboGroupItem.items.map(item => {\n const findComboItem = find(\n skuComboItemList,\n skuComboItem => skuComboItem.id === item.id\n )\n\n if (!findComboItem) {\n if (item.selectable === ENTITY_BOOL_YES) {\n item.selected = ENTITY_BOOL_NO\n }\n return item\n }\n\n const { children, combo_product } = item\n\n if (!isEmpty(children)) {\n children!.forEach((child: ISkuComboChildItem) => {\n if (child.combo_sku.id === findComboItem.combo_sku_id) {\n child.selected = ENTITY_BOOL_YES\n child.count = findComboItem.count\n }\n else {\n child.selected = ENTITY_BOOL_NO\n }\n })\n return item\n }\n\n if (combo_product) {\n if (findComboItem.combo_sku_id) {\n item.combo_sku = {\n id: findComboItem.combo_sku_id,\n name: findComboItem.combo_sku_name!,\n stock_count: item.combo_sku?.stock_count ?? SKU_STOCK_COUNT_UNLIMITED,\n }\n }\n\n if (findComboItem.combo_product_customization_item_list) {\n item.combo_customization_item_list = [\n findComboItem.combo_product_customization_item_list as any,\n ]\n }\n }\n\n item.count = findComboItem.count\n item.selected = ENTITY_BOOL_YES\n\n return item\n })\n\n return { ...comboGroupItem, items: newItems }\n })\n}\n\n/** 格式化当前选中的 skuComboItemList(二维数组) */\nexport function formatSelectSkuComboItemList(\n comboGroupList: ISkuComboGroupItem[]\n): ISelectSkuComboItem[][] {\n return comboGroupList.map(comboGroupItem => {\n const skuComboItems: ISelectSkuComboItem[] = []\n const comboGroupName = comboGroupItem.name\n\n comboGroupItem.items.forEach(item => {\n const {\n id,\n name,\n count,\n selected,\n children,\n combo_sku,\n combo_sku_type,\n combo_customization_item_list,\n } = item\n\n // 1. 有 children(定制商品),优先处理\n if (!isEmpty(children)) {\n const childItem: ISkuComboChildItem | undefined = find(\n children,\n (c: ISkuComboChildItem) => c.selected === ENTITY_BOOL_YES\n )\n\n if (childItem) {\n skuComboItems.push({\n id,\n name: `${name}(${childItem.name})`,\n combo_group_name: comboGroupName,\n combo_sku_id: childItem.combo_sku.id,\n count: childItem.count,\n })\n }\n return\n }\n\n // 未选中,跳过\n if (selected === ENTITY_BOOL_NO) {\n return\n }\n\n // 2. 无 SKU 类型的品牌店铺商品\n if (combo_sku_type === SKU_COMBO_ITEM_COMBO_SKU_TYPE_NONE) {\n skuComboItems.push({\n id,\n name,\n count,\n combo_group_name: comboGroupName,\n })\n return\n }\n\n // 3. 普通商品(有 combo_sku)\n if (combo_sku) {\n const selectItem: ISelectSkuComboItem = {\n id,\n name,\n count,\n combo_sku_id: combo_sku.id,\n combo_sku_name: combo_sku.name,\n combo_group_name: comboGroupName,\n }\n\n if (combo_customization_item_list) {\n selectItem.combo_product_customization_item_list = flattenDeep(\n combo_customization_item_list\n )\n }\n\n skuComboItems.push(selectItem)\n }\n })\n\n return skuComboItems\n })\n}\n\n/** 校验 comboGroupList 选中是否合法,合法返回 '',否则返回错误信息 */\nexport function validateComboGroupList(\n comboGroupList: ISkuComboGroupItem[],\n skuComboItemList?: ISelectSkuComboItem[][]\n): string {\n let isValid = true\n let errMsg = ''\n\n if (isEmpty(skuComboItemList)) {\n skuComboItemList = formatSelectSkuComboItemList(comboGroupList)\n }\n\n comboGroupList.forEach((comboGroupItem: ISkuComboGroupItem, groupIndex: number) => {\n if (!isValid) {\n return\n }\n\n const { items, min_count, max_count } = comboGroupItem\n const comboGroupName = comboGroupItem.name\n\n // 1. 逐个校验 item 选中状态\n items.forEach((item: ISkuComboItem, index: number) => {\n if (!isValid) {\n return\n }\n\n const { count, min_count: itemMinCount, selected, children, combo_sku, combo_product } = item\n\n if (selected === ENTITY_BOOL_NO) {\n return\n }\n\n // 有 children:必须选中一个定制子项\n if (!isEmpty(children)) {\n const childItem: ISkuComboChildItem | undefined = find(\n children,\n (c: ISkuComboChildItem) => c.selected === ENTITY_BOOL_YES\n )\n if (isEmpty(childItem)) {\n isValid = false\n errMsg = `【${comboGroupName}】:第${index + 1}个商品,请选择定制项`\n }\n return\n }\n\n // 有 combo_product 但未选规格\n if (combo_product && isEmpty(combo_sku)) {\n isValid = false\n errMsg = `【${comboGroupName}】:第${index + 1}个商品,请选择规格`\n return\n }\n\n // 数量不足本商品最小值\n if (count < itemMinCount) {\n isValid = false\n errMsg = `【${comboGroupName}】:第${index + 1}个商品,至少选择 ${itemMinCount} 件`\n }\n })\n\n if (!isValid) {\n return\n }\n\n // 2. 校验分组内总选中数量\n let skuComboCount = 0\n skuComboItemList[groupIndex]?.forEach(item => {\n skuComboCount += item.count\n })\n\n if (skuComboCount < min_count) {\n isValid = false\n errMsg = `【${comboGroupName}】:至少选择 ${min_count} 件商品`\n return\n }\n\n if (skuComboCount > max_count) {\n isValid = false\n errMsg = `【${comboGroupName}】:最多选择 ${max_count} 件商品`\n }\n })\n\n return errMsg\n}\n\nexport function formatComboGroupItemSelectTips(comboGroupItem: ISkuComboGroupItem) {\n const {\n items,\n repeatable,\n min_count,\n max_count,\n } = comboGroupItem\n\n const isAllSelectableNo = every(items, item => {\n return item.selectable === ENTITY_BOOL_NO\n })\n\n if (isAllSelectableNo) {\n return ''\n }\n\n const selectTips: string[] = []\n\n if (min_count === max_count) {\n selectTips.push(`请选择${min_count}项`)\n }\n else {\n if (min_count > 0) {\n selectTips.push(`至少选择${min_count}项`)\n }\n\n if (max_count > 0) {\n selectTips.push(`最多可选${max_count}项`)\n }\n }\n\n if (repeatable === ENTITY_BOOL_YES) {\n selectTips.push('可重复选')\n }\n\n // 当前已选数量\n let selectedCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectedCount += item.count\n }\n })\n\n if (selectedCount > 0) {\n selectTips.push(`已选${selectedCount}`)\n }\n\n return selectTips.join(',')\n}\n\nexport function generateCartSkuComboItemList(\n skuComboItemList: ISelectSkuComboItem[][] | undefined\n): ICartSkuComboItem[] {\n if (isEmpty(skuComboItemList)) {\n return []\n }\n\n // 将二维数组扁平化\n const flattenComboItemList = flattenDeep(skuComboItemList) as ISelectSkuComboItem[]\n\n // 直接转换为 ICartSkuComboItem[]\n const cartSkuComboItemList: ICartSkuComboItem[] = flattenComboItemList.map(item => {\n const cartItem: ICartSkuComboItem = {\n id: item.id,\n name: item.name,\n count: item.count,\n combo_group_name: item.combo_group_name,\n }\n\n // 如果有选中的规格,添加规格信息\n if (item.combo_sku_id) {\n cartItem.combo_sku_id = item.combo_sku_id\n }\n\n // 如果有规格名称\n if (item.combo_sku_name) {\n cartItem.combo_sku_name = item.combo_sku_name\n }\n\n // 如果有做法加料,添加做法信息\n if (!isEmpty(item.combo_product_customization_item_list)) {\n cartItem.combo_product_customization_item_list = item.combo_product_customization_item_list.map(customizationItem => ({\n id: customizationItem.id,\n name: customizationItem.name,\n count: customizationItem.count,\n count_type: customizationItem.count_type,\n }))\n }\n\n return cartItem\n })\n\n return cartSkuComboItemList\n}\n\nexport function handleSelectComboSkuSubmit(\n data: ISkuPopupSubmitData,\n isComboChild: boolean,\n onComboChildChange?: (data: ISkuPopupSubmitData) => void,\n onComboSkuChange?: (data: ISkuPopupSubmitData) => void\n) {\n if (isComboChild) {\n onComboChildChange?.(data)\n return\n }\n onComboSkuChange?.(data)\n}\n\nexport function setComboItemCountChange(\n comboGroupItem: ISkuComboGroupItem,\n comboItem: ISkuComboItem,\n count: number,\n onCountChange?: (count: number) => void\n) {\n const { items } = comboGroupItem\n const itemMinCount = comboItem.min_count\n const itemMaxCount = comboItem.max_count\n const groupMaxCount = comboGroupItem.max_count\n const isFixedItem = checkComboItemIsFixedSelect(comboItem)\n\n let selectCount = 0\n items.forEach(item => {\n if (item.id === comboItem.id) {\n selectCount += count\n }\n else {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n }\n })\n\n if (groupMaxCount !== -1 && selectCount > groupMaxCount) {\n return\n }\n if (itemMaxCount !== -1 && count > itemMaxCount) {\n return\n }\n if (count < 0 || selectCount < 0) {\n return\n }\n if (isFixedItem && count < itemMinCount) {\n return\n }\n\n onCountChange?.(count)\n}\n\nexport function handleComboItemCountChange(\n comboGroupItem: ISkuComboGroupItem,\n count: number,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem)\n const comboItem = newComboGroupItem.items[index]\n\n comboItem.count = count\n comboItem.selected = count === 0 ? ENTITY_BOOL_NO : ENTITY_BOOL_YES\n\n onChange?.(newComboGroupItem)\n}\n\nexport function handleComboGroupItemChildChange(\n comboGroupItem1: ISkuComboGroupItem,\n data: ISkuPopupSbumitData,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem1)\n\n const { sku, count } = data\n const skuId = sku.id\n const comboItem = newComboGroupItem.items[index]\n\n comboItem.children!.forEach(item => {\n if (item.combo_sku.id === skuId) {\n item.selected = ENTITY_BOOL_YES\n item.count = count\n }\n else {\n item.selected = ENTITY_BOOL_NO\n }\n })\n\n comboItem.selected = ENTITY_BOOL_YES\n\n onChange?.(newComboGroupItem)\n}\n\n\nexport function handleComboGroupItemSelected(\n comboGroupItem: ISkuComboGroupItem,\n selected: number,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem)\n\n const comboItem = newComboGroupItem.items[index]\n const { items, min_count, max_count } = newComboGroupItem\n\n let selectedCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectedCount++\n }\n })\n\n if (selected === ENTITY_BOOL_NO) {\n if (min_count === 1 && selectedCount <= 1) {\n onChange?.(newComboGroupItem)\n return\n }\n } else {\n if (max_count === 1) {\n newComboGroupItem.items.forEach((item, itemIndex) => {\n if (itemIndex !== index) {\n item.selected = ENTITY_BOOL_NO\n }\n })\n }\n else {\n if (selectedCount >= max_count) {\n onChange?.(newComboGroupItem)\n return\n }\n }\n }\n\n comboItem.selected = selected\n\n onChange?.(newComboGroupItem)\n}\n\nexport function handleComboGroupItemComboSkuChange(\n comboGroupItem: ISkuComboGroupItem,\n data: ISkuPopupSbumitData,\n index: number,\n onChange?: (comboGroupItem: ISkuComboGroupItem) => void\n) {\n const newComboGroupItem: ISkuComboGroupItem = cloneDeep(comboGroupItem)\n\n const { sku, customizationItemList } = data\n const comboItem = newComboGroupItem.items[index]\n const isUseSelectCount = checkComboItemIsUseSelectCount(comboItem)\n\n comboItem.combo_sku = {\n id: sku.id,\n name: sku.name,\n stock_count: comboItem.combo_sku?.stock_count ?? SKU_STOCK_COUNT_UNLIMITED,\n }\n\n if (customizationItemList) {\n comboItem.combo_customization_item_list = customizationItemList\n }\n\n if (isUseSelectCount && comboItem.count === 0) {\n comboItem.count = 1\n }\n\n handleComboGroupItemSelected(newComboGroupItem, ENTITY_BOOL_YES, index, onChange)\n}\n\n\nexport function setToggleComboItemSelecte(comboItem: ISkuComboItem, comboGroupItem: ISkuComboGroupItem, onSelectedChange?: (selected: number) => void) {\n const toggleSelected = comboItem.selected === ENTITY_BOOL_YES ? ENTITY_BOOL_NO : ENTITY_BOOL_YES\n\n if (!isEmpty(comboItem.children)) {\n return\n }\n\n const { items, max_count } = comboGroupItem\n\n if (toggleSelected === ENTITY_BOOL_YES) {\n if (max_count > 1) {\n let selectCount = 0\n items.forEach(item => {\n if (item.selected === ENTITY_BOOL_YES) {\n selectCount += item.count\n }\n })\n if (selectCount >= max_count) {\n return\n }\n }\n }\n\n onSelectedChange?.(toggleSelected)\n}\n","import { fill, find, isEqual, findIndex, flattenDeep, cloneDeep } from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n MALL_PRODUCT_SPEC_TYPE_SINGLE,\n MALL_PRODUCT_SPEC_TYPE_MULTIPLE,\n ORDER_EXTERNAL_SKU_TYPE_MALL,\n} from './constant'\n\nimport {\n IImage,\n IProduct,\n ISpecList,\n IFormatSku,\n ICartListItem,\n ISkuCombination,\n ISkuComboGroupItem,\n ISelectSkuComboItem,\n IProductSpecGroup,\n ISkuPopupData,\n} from './type'\n\nimport {\n formatSpecList,\n formatSpecObj,\n formatSkuListAfter,\n getSpecImage,\n checkProductOnSale,\n formatProductStatus,\n} from './productUtil'\n\nimport {\n reconstructComboGroupList,\n formatSelectSkuComboItemList,\n checkSkuComboItemListEqual,\n formatComboPrice,\n getSubmitComboItemListArr,\n} from './comboUtil'\n\nimport {\n ICountChangeResult,\n IAddToCartParamsResult,\n IComboSpecSelectorView,\n IComboSpecSelectorOptions,\n IFetchCartCountParams,\n IFetchMemberPriceParams,\n IMallSkuDetailDataForCombo,\n} from './type'\n\nimport { CHAGNE_TYPE_DECREASE } from './constant'\n\n/**\n * 套餐商品规格选择器\n *\n * 设计原则:类内部不发起任何接口请求,所有数据处理逻辑封装在此,\n * 网络请求由 UI 层发起,将结果通过公开方法回填。\n */\nexport class ComboSpecSelector {\n // ────────── 私有状态 ──────────\n private product: IProduct = {} as IProduct\n private specImage: IImage | undefined = undefined\n private skuId: number = 0\n private sku: IFormatSku | undefined = undefined\n private skuList: IFormatSku[] = []\n private skuListAfter: ISkuCombination[] = []\n private selectedSpecs: string[] = []\n private productSpecGroupList: ISpecList[] = []\n private specList: IProductSpecGroup[] = []\n\n private stockCount: number = 0\n private minCount: number = 1\n private maxCount: number = 1\n private perOrderMinLimit: number = -1\n private perOrderMaxLimit: number = -1\n\n private salePrice: number = 0\n private originalPrice: number = -1\n private memberPrice: number | undefined = undefined\n\n private skuComboGroupList: ISkuComboGroupItem[] = []\n private skuComboItemList: ISelectSkuComboItem[][] = []\n\n private cartCount: number = 0\n private cartItem: ICartListItem | undefined = undefined\n\n private visibleComboInfo: boolean = false\n private isComponentLoading: boolean = true\n\n // ────────── 初始化参数保存 ──────────\n private channel1Type: number\n private cartList: ICartListItem[]\n private negativeStockSaleEnabled?: boolean\n private onChange: () => void\n\n // 记录初始化时解析的 skuListAfter 与 specType,供 init 方法使用\n private _initSkuListAfter: ISkuCombination[] = []\n private _initSpecType: number = 0\n private _initSkuId: number = 0\n private _validateComboGroupList: () => string = () => ''\n\n constructor(options: IComboSpecSelectorOptions) {\n const { productData, cartList, channel1Type, negativeStockSaleEnabled, onChange, validateComboGroupList } = options\n this.cartList = cartList || []\n this.channel1Type = channel1Type\n this.negativeStockSaleEnabled = negativeStockSaleEnabled\n this.onChange = onChange\n this._validateComboGroupList = validateComboGroupList\n\n this._initProductData(productData as ISkuPopupData)\n }\n\n /** 获取初始 sku 列表(供 UI 在调用 fetchSkuDetail 前获取初始 skuId) */\n getInitialSkuId(): number {\n return this._initSkuId\n }\n // ────────── 初始化:接收 sku 详情数据 ──────────\n\n /**\n * 初始化,接收 UI 层拉取的 sku 详情数据\n * 调用后触发 onChange,UI 可通过 getView() 拿到渲染数据\n */\n init(skuDetailData: IMallSkuDetailDataForCombo): void {\n const specType = this._initSpecType\n const skuListAfter = this._initSkuListAfter\n\n // 找购物车中对应的初始化 cartItem\n const initCartItem = this._findSkuCartItem()\n\n let skuIndex = 0\n if (specType === MALL_PRODUCT_SPEC_TYPE_MULTIPLE) {\n if (!isEmpty(initCartItem)) {\n const { sku, external_sku } = initCartItem!\n const initSkuId = external_sku?.id || sku.id\n skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) {\n skuIndex = 0\n }\n }\n }\n\n this.cartItem = initCartItem\n this.cartCount = initCartItem?.cart?.count || 0\n\n const skuItem = skuListAfter[skuIndex]\n\n if (specType === MALL_PRODUCT_SPEC_TYPE_SINGLE) {\n this._initSkuDetail(skuDetailData)\n this._updateSkuData(skuItem || this.skuList[0])\n this.isComponentLoading = false\n this._notifyChange()\n return\n }\n\n // 多规格:先解析 sku 详情,再模拟选中规格\n this._initSkuDetail(skuDetailData)\n\n skuListAfter[skuIndex]?.specs.forEach((specValue, index) => {\n this._selectSpec(true, specValue, index)\n })\n\n this.isComponentLoading = false\n this._notifyChange()\n }\n\n /**\n * 同步最新的购物车列表\n * cartList 更新后调用此方法,会重新计算当前 skuId 在购物车中的数量\n */\n syncCartList(cartList: ICartListItem[]): void {\n this.cartList = cartList\n this._refreshCartItem()\n this._notifyChange()\n }\n\n // ────────── 获取渲染数据 ──────────\n\n getView(): IComboSpecSelectorView {\n return {\n product: this.product,\n skuId: this.skuId,\n salePrice: this.getSalePrice(),\n originalPrice: this.getOriginalPrice(),\n memberPrice: this.getMemberPrice(),\n specImage: this.specImage,\n skuListAfter: this.skuListAfter,\n selectedSpecs: this.selectedSpecs,\n productSpecGroupList: this.productSpecGroupList,\n skuComboGroupList: this.skuComboGroupList,\n skuComboItemList: this.skuComboItemList,\n cartCount: this.cartCount,\n maxCount: this.maxCount,\n isComponentLoading: this.isComponentLoading,\n visibleComboInfo: this.visibleComboInfo,\n }\n }\n\n // ────────── 规格选择 ──────────\n\n /**\n * 选择规格(纯数据处理)\n * @returns needFetchSkuDetail 是否需要重新拉取 sku 详情(为 true 时同样需要重新请求会员价);skuId 目标 skuId\n */\n handleSelectSpecs(\n isOption: boolean,\n value: string,\n index: number,\n ): { needFetchSkuDetail: boolean; skuId: number } {\n const changed = this._selectSpec(isOption, value, index)\n\n // 规格未全选,无需拉取详情\n if (!changed || this.selectedSpecs.indexOf('') >= 0) {\n this._notifyChange()\n return { needFetchSkuDetail: false, skuId: 0 }\n }\n\n // 全选后找到对应 sku\n const matchedSku = find(this.skuListAfter, item =>\n isEqual(item.specs, this.selectedSpecs),\n )\n\n if (!matchedSku) {\n this._notifyChange()\n return { needFetchSkuDetail: false, skuId: 0 }\n }\n\n // 更新规格图片\n if (this.specList[0]?.items[0]?.image !== undefined) {\n this.specList[0].items.forEach(item => {\n if (item.name === this.selectedSpecs[0]) {\n this.specImage = item.image\n }\n })\n }\n\n this._notifyChange()\n return { needFetchSkuDetail: true, skuId: matchedSku.id }\n }\n\n /**\n * 用新的 sku 详情数据更新内部状态\n * (规格切换后,UI 调用 fetchSkuDetail 接口拿到数据后传入此方法)\n */\n updateSkuDetailData(skuDetailData: IMallSkuDetailDataForCombo): void {\n this._initSkuDetail(skuDetailData)\n this._notifyChange()\n }\n\n /**\n * 用会员价查询结果更新内部状态,由 UI 层请求会员价接口后调用\n * @param price 会员价,请求失败或无会员价时传 undefined\n */\n updateMemberPrice(price: number | undefined): void {\n this.memberPrice = price\n this._notifyChange()\n }\n\n // ────────── 套餐选择 ──────────\n\n /**\n * 套餐选中变化(纯数据处理)\n */\n handleSelectComboData(skuComboItemList: ISelectSkuComboItem[][]) {\n this.skuComboItemList = skuComboItemList\n this._refreshCartItem()\n this._notifyChange()\n }\n\n // ────────── 数量变化 ──────────\n\n /**\n * 数量变化(纯逻辑,返回操作结果供 UI 决策)\n */\n handleProductCountChange(count: number, type: string): ICountChangeResult {\n const { perOrderMinLimit, cartItem, selectedSpecs } = this\n\n if (selectedSpecs.indexOf('') >= 0) {\n return { isValid: false, errMsg: '请选择规格' }\n }\n\n if (count > 0) {\n // 减少时,若低于最小购买量则直接置零\n if (type === CHAGNE_TYPE_DECREASE && perOrderMinLimit !== -1 && count < perOrderMinLimit) {\n return {\n isValid: true,\n cartItem: cartItem!,\n count: 0,\n }\n }\n\n // 校验套餐\n const comboErrMsg = this._validateCombo()\n if (comboErrMsg) {\n return { isValid: false, errMsg: comboErrMsg }\n }\n\n const countCheckResult = this._checkProductCount(count)\n if (!countCheckResult.isValid) {\n return countCheckResult\n }\n }\n\n return { isValid: true, cartItem: cartItem!, count }\n }\n\n // ────────── 加入购物车前校验 ──────────\n\n /**\n * 加入购物车前校验,返回提交所需参数\n * 由 UI 层使用参数调用 addToCart 接口\n */\n getAddToCartParams(productId: number, promotionActivityProductId?: number): IAddToCartParamsResult {\n const {\n sku,\n skuId,\n product,\n skuList,\n selectedSpecs,\n negativeStockSaleEnabled,\n productSpecGroupList,\n skuComboItemList,\n perOrderMinLimit,\n } = this\n\n const selectedSpecsIndex = selectedSpecs.indexOf('')\n const isProductOnSale = checkProductOnSale(product?.status, product?.has_stock)\n const productStatusDesc = formatProductStatus(product?.status, product?.has_stock)\n\n if (skuList[0].item_ids.length !== 0 && selectedSpecsIndex >= 0) {\n return {\n isValid: false,\n errMsg: `请选择${productSpecGroupList[selectedSpecsIndex].title}`,\n }\n }\n\n if (!isProductOnSale && !negativeStockSaleEnabled) {\n return { isValid: false, errMsg: productStatusDesc }\n }\n\n const comboErrMsg = this._validateCombo()\n if (comboErrMsg) {\n return { isValid: false, errMsg: comboErrMsg }\n }\n\n // 当前是活动 sku,则使用活动商品 id\n const finalPromotionActivityProductId = sku?.is_promotion_activity\n ? promotionActivityProductId\n : undefined\n\n return {\n isValid: true,\n params: {\n productId,\n promotionActivityProductId: finalPromotionActivityProductId,\n skuId,\n count: perOrderMinLimit !== -1 ? perOrderMinLimit : 1,\n skuComboItemList,\n },\n }\n }\n\n // ────────── 弹框显示 ──────────\n\n handleShowComboInfo(): void {\n const flattenList = flattenDeep(this.skuComboItemList)\n if (!isEmpty(flattenList)) {\n this.visibleComboInfo = true\n this._notifyChange()\n }\n }\n\n handleCloseComboInfo(): void {\n this.visibleComboInfo = false\n this._notifyChange()\n }\n\n // ────────── 价格计算 ──────────\n\n getSalePrice(): number {\n return formatComboPrice(this.salePrice, this.skuComboGroupList, this.skuComboItemList)\n }\n\n getOriginalPrice(): number {\n if (isEmpty(this.originalPrice) || this.originalPrice <= 0) {\n return 0\n }\n\n return formatComboPrice(this.originalPrice, this.skuComboGroupList, this.skuComboItemList)\n }\n\n // 会员价未加载或不存在时返回 undefined,否则叠加套餐加价\n getMemberPrice(): number | undefined {\n if (isEmpty(this.memberPrice) || this.memberPrice <= 0) {\n return undefined\n }\n\n return formatComboPrice(this.memberPrice, this.skuComboGroupList, this.skuComboItemList)\n }\n\n // ────────── 构造购物车查询参数(供 UI 层使用) ──────────\n\n buildCartCountParams(): IFetchCartCountParams {\n const submitSkuComboItemList = getSubmitComboItemListArr(this.skuComboItemList)\n return {\n channel1_type: this.channel1Type,\n checked: 1,\n sku_id: this.skuId,\n sku_type: ORDER_EXTERNAL_SKU_TYPE_MALL,\n sku_combo_item_list: JSON.stringify(submitSkuComboItemList),\n cart: 1,\n }\n }\n\n /**\n * 构造会员价查询参数(供 UI 层使用)\n * sku 未选中时返回 undefined\n */\n buildMemberPriceParams(): IFetchMemberPriceParams | undefined {\n if (!this.skuId) {\n return undefined\n }\n\n return {\n sku_id: this.skuId,\n sku_type: ORDER_EXTERNAL_SKU_TYPE_MALL,\n }\n }\n\n // ────────── 私有方法 ──────────\n\n private _initProductData(data: ISkuPopupData): void {\n const { product, skuList, productCover, productSpecGroupList } = data\n\n const specObj = formatSpecObj(productSpecGroupList)\n const newProductSpecGroupList = formatSpecList(productSpecGroupList)\n const skuListAfter = formatSkuListAfter(skuList, specObj, this.negativeStockSaleEnabled)\n const specImage = getSpecImage(productSpecGroupList, productCover)\n\n this.product = product\n this.specImage = specImage\n this.skuList = skuList\n this.skuListAfter = skuListAfter\n this.selectedSpecs = fill(new Array(newProductSpecGroupList.length), '')\n this.productSpecGroupList = newProductSpecGroupList\n this.specList = productSpecGroupList\n\n // 保存供 init 使用\n this._initSkuListAfter = skuListAfter\n this._initSpecType = product.spec_type\n\n // 计算初始 skuId\n const specType = product.spec_type\n if (specType === MALL_PRODUCT_SPEC_TYPE_MULTIPLE) {\n const initCartItem = this._findSkuCartItem()\n if (!isEmpty(initCartItem)) {\n const { sku, external_sku } = initCartItem!\n const initSkuId = external_sku?.id || sku.id\n let skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) skuIndex = 0\n this._initSkuId = skuListAfter[skuIndex]?.id ?? skuList[0]?.id ?? 0\n } else {\n this._initSkuId = skuListAfter[0]?.id ?? skuList[0]?.id ?? 0\n }\n } else {\n this._initSkuId = skuList[0]?.id ?? 0\n }\n }\n\n private _initSkuDetail(skuData: IMallSkuDetailDataForCombo): void {\n const { sku, sku_combo_group_list } = skuData\n\n this._updateSkuData(sku)\n\n const skuComboGroupList = reconstructComboGroupList(\n sku_combo_group_list || [],\n this.cartItem?.sku_combo_item_list,\n )\n\n this.skuComboGroupList = skuComboGroupList\n this.skuComboItemList = formatSelectSkuComboItemList(skuComboGroupList)\n }\n\n private _updateSkuData(sku: IFormatSku): void {\n const skuId = sku.id\n const stockCount = sku.stock_count\n const perOrderMinLimit = sku.per_order_min_limit\n const perOrderMaxLimit = sku.per_order_max_limit\n const minCount = perOrderMinLimit === -1 ? 1 : Math.min(perOrderMinLimit, stockCount)\n const maxCount = perOrderMaxLimit === -1 ? stockCount : Math.min(perOrderMaxLimit, stockCount)\n\n const skuCartItem = this._findSkuCartItem(skuId)\n\n this.sku = sku\n this.skuId = skuId\n this.stockCount = stockCount\n this.salePrice = sku.sale_price\n this.originalPrice = sku.original_price\n this.minCount = minCount\n this.maxCount = maxCount\n this.perOrderMinLimit = perOrderMinLimit\n this.perOrderMaxLimit = perOrderMaxLimit\n\n this.cartItem = skuCartItem\n this.cartCount = skuCartItem?.cart?.count || 0\n }\n\n private _checkProductCount(count: number): ICountChangeResult {\n const { minCount, maxCount, stockCount, perOrderMinLimit, negativeStockSaleEnabled } = this\n\n if (count < minCount || count < perOrderMinLimit) {\n const errMsg = perOrderMinLimit !== -1\n ? `该商品 ${perOrderMinLimit} 件起售哦`\n : `购买数量至少 ${minCount} 件`\n return { isValid: false, errMsg }\n }\n\n if (count > maxCount && !negativeStockSaleEnabled) {\n const errMsg = count > stockCount ? '库存不足' : `该商品最多购买 ${maxCount} 件哦`\n return { isValid: false, errMsg }\n }\n\n return { isValid: true }\n }\n\n /**\n * 内部规格选择逻辑(被 handleSelectSpecs 和 init 时复用)\n * @returns 是否发生了选中变化\n */\n private _selectSpec(isOption: boolean, value: string, index: number): boolean {\n const { selectedSpecs, productSpecGroupList } = this\n\n if (productSpecGroupList.length === 0) {\n return false\n }\n\n if (selectedSpecs[index] === value || !isOption) {\n return false\n }\n\n selectedSpecs[index] = value\n this.selectedSpecs = selectedSpecs.slice()\n return true\n }\n /**\n * 刷新当前 skuId 对应的购物车数据\n */\n private _refreshCartItem(): void {\n const skuCartItem = this._findSkuCartItem(this.skuId)\n this.cartItem = skuCartItem\n this.cartCount = skuCartItem?.cart?.count || 0\n }\n\n /**\n * 根据 skuId 和当前 skuComboItemList 从 cartList 中查找匹配的购物车项\n */\n private _findSkuCartItem(skuId?: number): ICartListItem | undefined {\n const { cartList, product, skuComboItemList } = this\n\n const findCartItem = find(cartList, (cartItem: ICartListItem) => {\n const productId = product.id\n const productCode = product.code\n const cartItemProduct = cartItem.product\n\n // 1. 判断是否是当前商品\n const isProductFind = productId\n ? cartItemProduct.id === productId\n : cartItemProduct.code === productCode\n\n if (!isProductFind) return false\n\n // 2. 没有 skuId,匹配到商品即可\n if (!skuId) return true\n\n const cartItemSku = cartItem.sku\n const cartItemSkuExternal = cartItem.external_sku\n // 3. 判断 sku_id 是否一致,优先使用活动 sku_id\n const isSkuEqual = cartItemSkuExternal\n ? cartItemSkuExternal.id === skuId\n : cartItemSku.id === skuId\n\n if (!isSkuEqual) return false\n\n const cartItemSkuComboItemList = cartItem.sku_combo_item_list || []\n // 4. 如果套餐列表为空,匹配到商品 + sku_id 即可\n if (isEmpty(skuComboItemList)) return true\n\n const flattenSkuComboItemList = flattenDeep(skuComboItemList)\n // 5. 比较套餐值列表是否相等\n return checkSkuComboItemListEqual(flattenSkuComboItemList, cartItemSkuComboItemList)\n })\n\n return findCartItem ? cloneDeep(findCartItem) : undefined\n }\n\n /**\n * 校验套餐分组是否满足要求,返回错误信息(空字符串表示校验通过)\n */\n private _validateCombo(): string {\n return this._validateComboGroupList()\n }\n\n private _notifyChange(): void {\n this.onChange()\n }\n}\n","import { fill, find, isEqual, findIndex, flattenDeep, cloneDeep } from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n CHAGNE_TYPE_DECREASE,\n MALL_PRODUCT_SPEC_TYPE_SINGLE,\n ORDER_EXTERNAL_SKU_TYPE_MALL,\n ORDER_EXTERNAL_SKU_TYPE_MARKETING_PROMOTION_ACTIVITY,\n} from './constant'\n\nimport {\n IImage,\n IProduct,\n ISpecList,\n IFormatSku,\n ICartListItem,\n ISkuCombination,\n IProductSpecGroup,\n IProductSpecItem,\n ISkuPopupData,\n IPromotionActivityProduct,\n IProductCustomizationGroupItemView,\n IProductSelectedCustomizationItem,\n} from './type'\n\nimport {\n formatSpecList,\n formatSpecObj,\n formatSkuListAfter,\n getSpecImage,\n getActivitySpecList,\n checkProductOnSale,\n formatProductStatus,\n} from './productUtil'\n\nimport {\n formatCustomizationGroupList,\n getSubmitCustomizationItemListArr,\n calculateSelectedCustomizationPrice,\n formatInitCustomizationItemList,\n reconstructCustomizationItemList,\n checkCustomizationItemList,\n checkCustomizationItemListEqual,\n formatSkuNameWithCustomization,\n formatCustomizationCountType,\n} from './customizationUtil'\n\nimport {\n IAddCartParams,\n ICountChangeResult,\n IAddToCartParamsResult,\n ICustomSpecSelectorView,\n ICustomSpecSelectorOptions,\n IFetchCustomCartCountParams,\n IFetchCartCountResult,\n IFetchMemberPriceParams,\n} from './type'\n\n/**\n * 做法加料商品规格选择器\n *\n * 设计原则:类内部不发起任何接口请求,所有数据处理逻辑封装在此,\n * 网络请求由 UI 层发起,将结果通过公开方法回填。\n *\n * 与 ComboSpecSelector 的差异:\n * - productData 已包含做法数据,初始化时无需额外接口\n * - 支持活动 sku(promotionActivityProduct)\n * - 购物车参数含 product_customization_item_list\n */\nexport class CustomSpecSelector {\n // ────────── 私有状态 ──────────\n private product: IProduct = {} as IProduct\n private promotionActivityProduct: IPromotionActivityProduct | undefined = undefined\n private specImage: IImage | undefined = undefined\n private skuId: number = 0\n private sku: IFormatSku | undefined = undefined\n private skuList: IFormatSku[] = []\n private skuListAfter: ISkuCombination[] = []\n private selectedSpecs: string[] = []\n private productSpecGroupList: ISpecList[] = []\n private specList: IProductSpecGroup[] = []\n private activitySpecList: IProductSpecItem[][] = []\n\n private stockCount: number = 0\n private minCount: number = 1\n private maxCount: number = 1\n private perOrderMinLimit: number = -1\n private perOrderMaxLimit: number = -1\n\n private salePrice: number = 0\n private originalPrice: number = -1\n private memberPrice: number | undefined = undefined\n\n private customizationGroupList: IProductCustomizationGroupItemView[] = []\n private customizationItemList: IProductSelectedCustomizationItem[][] = []\n\n private cartCount: number = 0\n private cartItem: ICartListItem | undefined = undefined\n\n // ────────── 初始化参数保存 ──────────\n private cartList: ICartListItem[] = []\n private channel1Type: number\n private negativeStockSaleEnabled?: boolean\n private onChange: () => void\n\n constructor(options: ICustomSpecSelectorOptions) {\n const { productData, cartList, channel1Type, negativeStockSaleEnabled, onChange } = options\n this.cartList = cartList || []\n this.channel1Type = channel1Type\n this.negativeStockSaleEnabled = negativeStockSaleEnabled\n this.onChange = onChange\n\n this._initProductData(productData as ISkuPopupData)\n }\n\n // ────────── 初始化 ──────────\n\n /**\n * 设置购物车列表,当购物车数据变化时调用\n * 会根据当前选中的规格和做法重新匹配购物车数据\n */\n setCartList(cartList: ICartListItem[]): void {\n this.cartList = cartList\n this._updateSkuCartItem()\n this._notifyChange()\n }\n\n /**\n * 初始化(做法加料商品无需额外接口请求,productData 已包含全部数据)\n * 调用后触发 onChange,UI 可通过 getView() 拿到渲染数据;\n * 但购物车数据需 UI 层调用 buildCartCountParams() 拿参数后自行请求。\n */\n init(): void {\n const skuListAfter = this.skuListAfter\n const specType = this.product.spec_type\n\n // 从购物车列表中找到匹配的初始商品\n const initCartItem = this._findSkuCartItem()\n\n let skuIndex = 0\n\n if (!isEmpty(initCartItem)) {\n const { sku, external_sku, product_customization_item_list } = initCartItem!\n const initSkuId = external_sku?.id || sku.id\n skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) {\n skuIndex = 0\n }\n\n // 购物车中有做法值,回填做法值列表\n if (!isEmpty(product_customization_item_list)) {\n const res = reconstructCustomizationItemList(\n this.customizationGroupList,\n product_customization_item_list!,\n )\n this.customizationGroupList = res.customizationGroupList\n this.customizationItemList = res.selectedCustomizationItemList\n }\n }\n\n this._updateSkuCartItem()\n\n if (specType === MALL_PRODUCT_SPEC_TYPE_SINGLE) {\n this._updateSkuData(this.skuList[0])\n this._notifyChange()\n return\n }\n\n // 多规格:模拟选中初始规格\n skuListAfter[skuIndex]?.specs.forEach((specValue, index) => {\n this._selectSpec(true, specValue, index)\n })\n\n // 找到对应 sku 并更新\n const matchedSku = find(skuListAfter, item =>\n isEqual(item.specs, this.selectedSpecs),\n )\n if (matchedSku) {\n this._updateSkuData(matchedSku)\n }\n\n this._notifyChange()\n }\n\n // ────────── 获取渲染数据 ──────────\n\n getView(): ICustomSpecSelectorView {\n return {\n product: this.product,\n promotionActivityProduct: this.promotionActivityProduct,\n skuId: this.skuId,\n sku: this.sku,\n salePrice: this.getSalePrice(),\n originalPrice: this.getOriginalPrice(),\n memberPrice: this.getMemberPrice(),\n specImage: this.specImage,\n skuListAfter: this.skuListAfter,\n selectedSpecs: this.selectedSpecs,\n productSpecGroupList: this.productSpecGroupList,\n activitySpecList: this.activitySpecList,\n customizationGroupList: this.customizationGroupList,\n customizationItemList: this.customizationItemList,\n cartCount: this.cartCount,\n maxCount: this.maxCount,\n cartItem: this.cartItem,\n }\n }\n\n // ────────── 规格选择 ──────────\n\n /**\n * 选择规格(纯数据处理)\n * @returns needFetchCart 是否需要刷新购物车数(为 true 时同样需要重新请求会员价);cartParams 购物车查询参数\n */\n handleSelectSpecs(\n isOption: boolean,\n value: string,\n index: number,\n ): { needFetchCart: boolean; cartParams: IFetchCustomCartCountParams } {\n const changed = this._selectSpec(isOption, value, index)\n\n const emptyCartParams = this.buildCartCountParams()\n\n if (!changed || this.selectedSpecs.indexOf('') >= 0) {\n // 规格未全选时,清空购物车匹配数据\n this._updateSkuCartItem()\n this._notifyChange()\n return { needFetchCart: false, cartParams: emptyCartParams }\n }\n\n // 全选后找到对应 sku\n const matchedSku = find(this.skuListAfter, item =>\n isEqual(item.specs, this.selectedSpecs),\n )\n\n if (!matchedSku) {\n this._updateSkuCartItem()\n this._notifyChange()\n return { needFetchCart: false, cartParams: emptyCartParams }\n }\n\n // 更新规格图片\n if (this.specList[0]?.items[0]?.image !== undefined) {\n this.specList[0].items.forEach(item => {\n if (item.name === this.selectedSpecs[0]) {\n this.specImage = item.image\n }\n })\n }\n\n this._updateSkuData(matchedSku)\n // 规格变化后,重新匹配购物车数据\n this._updateSkuCartItem()\n this._notifyChange()\n\n return { needFetchCart: true, cartParams: this.buildCartCountParams() }\n }\n\n /**\n * 用购物车查询结果更新内部状态\n */\n updateCartCountData(result: IFetchCartCountResult): void {\n if (result && result.cart !== undefined) {\n const cart = result.cart\n this.cartItem = result as any\n this.cartCount = cart?.count || 0\n } else {\n this.cartItem = undefined\n this.cartCount = 0\n }\n this._notifyChange()\n }\n\n /**\n * 用会员价查询结果更新内部状态,由 UI 层请求会员价接口后调用\n * @param price 会员价,请求失败或无会员价时传 undefined\n */\n updateMemberPrice(price: number | undefined): void {\n this.memberPrice = price\n this._notifyChange()\n }\n\n // ────────── 做法选择 ──────────\n\n /**\n * 做法选中变化(纯数据处理)\n * @returns isValid 校验是否通过;cartParams 若通过则返回购物车查询参数\n */\n handleCustomizationItemListSelect(\n customizationItemList: IProductSelectedCustomizationItem[][],\n ): { isValid: boolean; cartParams?: IFetchCustomCartCountParams } {\n this.customizationItemList = customizationItemList\n\n const res = checkCustomizationItemList(\n this.customizationGroupList,\n customizationItemList,\n )\n\n if (!res.isValid) {\n this.cartItem = undefined\n this.cartCount = 0\n this._notifyChange()\n return { isValid: false }\n }\n\n // 做法变化后,重新匹配购物车数据\n this._updateSkuCartItem()\n this._notifyChange()\n return { isValid: true, cartParams: this.buildCartCountParams() }\n }\n\n // ────────── 数量变化 ──────────\n\n /**\n * 数量变化(纯逻辑,返回操作结果供 UI 决策)\n */\n handleProductCountChange(count: number, type: string): ICountChangeResult {\n const { perOrderMinLimit, cartItem, selectedSpecs } = this\n\n if (selectedSpecs.indexOf('') >= 0) {\n return { isValid: false, errMsg: '请选择规格' }\n }\n\n if (count > 0) {\n // 减少时,若低于最小购买量则直接置零\n if (type === CHAGNE_TYPE_DECREASE && perOrderMinLimit !== -1 && count < perOrderMinLimit) {\n return { isValid: true, cartItem: cartItem!, count: 0 }\n }\n\n // 校验做法\n if (this.customizationGroupList.length > 0) {\n const res = checkCustomizationItemList(\n this.customizationGroupList,\n this.customizationItemList,\n )\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n }\n\n const countCheckResult = this._checkProductCount(count)\n if (!countCheckResult.isValid) {\n return countCheckResult\n }\n }\n\n return { isValid: true, cartItem: cartItem!, count }\n }\n\n // ────────── 加入购物车前校验 ──────────\n\n /**\n * 加入购物车前校验,返回提交所需参数\n * 由 UI 层使用参数调用 addToCart 接口\n */\n getAddToCartParams(productId: number, promotionActivityProductId?: number): IAddToCartParamsResult {\n const {\n sku,\n skuId,\n product,\n skuList,\n selectedSpecs,\n negativeStockSaleEnabled,\n productSpecGroupList,\n customizationItemList,\n customizationGroupList,\n perOrderMinLimit,\n } = this\n\n const selectedSpecsIndex = selectedSpecs.indexOf('')\n const isProductOnSale = checkProductOnSale(product?.status, product?.has_stock)\n const productStatusDesc = formatProductStatus(product?.status, product?.has_stock)\n\n if (skuList[0].item_ids.length !== 0 && selectedSpecsIndex >= 0) {\n return {\n isValid: false,\n errMsg: `请选择${productSpecGroupList[selectedSpecsIndex].title}`,\n }\n }\n\n if (!isProductOnSale && !negativeStockSaleEnabled) {\n return { isValid: false, errMsg: productStatusDesc }\n }\n\n if (customizationGroupList.length > 0) {\n const res = checkCustomizationItemList(customizationGroupList, customizationItemList)\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n }\n\n const productCustomizationItemList = getSubmitCustomizationItemListArr(customizationItemList)\n const finalPromotionActivityProductId = sku?.is_promotion_activity ? promotionActivityProductId : undefined\n\n const params: IAddCartParams = {\n productId,\n promotionActivityProductId: finalPromotionActivityProductId,\n skuId,\n count: perOrderMinLimit !== -1 ? perOrderMinLimit : 1,\n productCustomizationItemList,\n }\n\n return { isValid: true, params }\n }\n\n // ────────── 价格计算 ──────────\n\n getSalePrice(): number {\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n this.customizationGroupList,\n this.customizationItemList,\n )\n return this.salePrice + selectedCustomizationPrice\n }\n\n getOriginalPrice(): number {\n // 没有原价时返回 -1\n if (isEmpty(this.originalPrice) || this.originalPrice <= 0) {\n return this.originalPrice\n }\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n this.customizationGroupList,\n this.customizationItemList,\n )\n return this.originalPrice + selectedCustomizationPrice\n }\n\n // 会员价未加载或不存在时返回 undefined,否则叠加做法加料价格\n getMemberPrice(): number | undefined {\n if (isEmpty(this.memberPrice) || this.memberPrice <= 0) {\n return undefined\n }\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n this.customizationGroupList,\n this.customizationItemList,\n )\n return this.memberPrice + selectedCustomizationPrice\n }\n\n // 获取选中规格和做法合并后的数据\n getSelectedSpecAndCustomization(): string {\n let name = this.selectedSpecs.join('、')\n const flattenCustomizationItemList = flattenDeep(this.customizationItemList)\n\n name = formatSkuNameWithCustomization(name, flattenCustomizationItemList)\n const countTypeName = formatCustomizationCountType(flattenCustomizationItemList)\n\n if (isEmpty(name) && isEmpty(countTypeName)) {\n return ''\n }\n\n if (isEmpty(name) || isEmpty(countTypeName)) {\n return name ? name : countTypeName\n }\n\n return `${name}、${countTypeName}`\n }\n\n // ────────── 构造购物车查询参数(供 UI 层使用) ──────────\n\n buildCartCountParams(): IFetchCustomCartCountParams {\n const productCustomizationItemList = getSubmitCustomizationItemListArr(this.customizationItemList)\n\n return {\n channel1_type: this.channel1Type,\n checked: 1,\n sku_id: this.skuId,\n sku_type: this._getSkuType(),\n product_customization_item_list: JSON.stringify(productCustomizationItemList),\n cart: 1,\n }\n }\n\n /**\n * 构造会员价查询参数(供 UI 层使用)\n * sku 未选中时返回 undefined\n */\n buildMemberPriceParams(): IFetchMemberPriceParams | undefined {\n if (!this.skuId) {\n return undefined\n }\n\n return {\n sku_id: this.skuId,\n sku_type: this._getSkuType(),\n }\n }\n\n // ────────── 私有方法 ──────────\n\n private _initProductData(data: ISkuPopupData): void {\n const {\n product,\n promotionActivityProduct,\n skuList,\n productCover,\n productSpecGroupList,\n productCustomizationGroupList,\n } = data\n\n const specObj = formatSpecObj(productSpecGroupList)\n const newProductSpecGroupList = formatSpecList(productSpecGroupList)\n const skuListAfter = formatSkuListAfter(skuList, specObj, this.negativeStockSaleEnabled)\n const specImage = getSpecImage(productSpecGroupList, productCover)\n const activitySpecList = getActivitySpecList(productSpecGroupList)\n const customizationGroupList = formatCustomizationGroupList(productCustomizationGroupList || [])\n\n this.product = product\n this.promotionActivityProduct = promotionActivityProduct\n this.specImage = specImage\n this.skuList = skuList\n this.skuListAfter = skuListAfter\n this.selectedSpecs = fill(new Array(newProductSpecGroupList.length), '')\n this.productSpecGroupList = newProductSpecGroupList\n this.specList = productSpecGroupList\n this.activitySpecList = activitySpecList\n this.customizationGroupList = customizationGroupList\n this.customizationItemList = productCustomizationGroupList\n ? formatInitCustomizationItemList(customizationGroupList)\n : []\n }\n\n private _updateSkuData(sku: IFormatSku): void {\n const skuId = sku.id\n const stockCount = sku.stock_count\n const perOrderMinLimit = sku.per_order_min_limit\n const perOrderMaxLimit = sku.per_order_max_limit\n const minCount = perOrderMinLimit === -1 ? 1 : Math.min(perOrderMinLimit, stockCount)\n const maxCount = perOrderMaxLimit === -1 ? stockCount : Math.min(perOrderMaxLimit, stockCount)\n\n this.sku = sku\n this.skuId = skuId\n this.stockCount = stockCount\n this.salePrice = sku.sale_price\n this.originalPrice = sku.original_price\n this.minCount = minCount\n this.maxCount = maxCount\n this.perOrderMinLimit = perOrderMinLimit\n this.perOrderMaxLimit = perOrderMaxLimit\n\n this._findSkuCartItem(skuId)\n }\n\n private _checkProductCount(count: number): ICountChangeResult {\n const { minCount, maxCount, stockCount, perOrderMinLimit, negativeStockSaleEnabled } = this\n\n if (count < minCount || count < perOrderMinLimit) {\n const errMsg = perOrderMinLimit !== -1\n ? `该商品 ${perOrderMinLimit} 件起售哦`\n : `购买数量至少 ${minCount} 件`\n return { isValid: false, errMsg }\n }\n\n if (count > maxCount && !negativeStockSaleEnabled) {\n const errMsg = count > stockCount ? '库存不足' : `该商品最多购买 ${maxCount} 件哦`\n return { isValid: false, errMsg }\n }\n\n return { isValid: true }\n }\n\n private _selectSpec(isOption: boolean, value: string, index: number): boolean {\n const { selectedSpecs, productSpecGroupList } = this\n\n if (productSpecGroupList.length === 0) {\n return false\n }\n\n if (selectedSpecs[index] === value || !isOption) {\n return false\n }\n\n selectedSpecs[index] = value\n this.selectedSpecs = selectedSpecs.slice()\n return true\n }\n\n private _notifyChange(): void {\n this.onChange()\n }\n\n /**\n * 获取当前 sku 类型,活动 sku 返回活动类型,否则返回商城类型\n */\n private _getSkuType(): number {\n return this.sku?.is_promotion_activity\n ? ORDER_EXTERNAL_SKU_TYPE_MARKETING_PROMOTION_ACTIVITY\n : ORDER_EXTERNAL_SKU_TYPE_MALL\n }\n\n /**\n * 从购物车列表中查找匹配的购物车项\n * 匹配逻辑:\n * 1. 判断购物车商品是否是当前商品(优先使用活动商品 id 比较)\n * 2. 判断 sku_id 是否一样(优先使用活动 sku_id)\n * 3. 比较做法值列表是否相等(数组长度一致,且 id 和 count 一致)\n */\n private _findSkuCartItem(skuId?: number): ICartListItem | undefined {\n const { cartList } = this\n\n if (isEmpty(cartList)) {\n return undefined\n }\n\n const {\n product,\n promotionActivityProduct,\n customizationItemList,\n } = this\n\n const findCartItem = find(cartList, (cartItem: ICartListItem) => {\n const productId = product.id\n const productCode = product.code\n\n const cartItemProduct = cartItem.product\n const cartItemExternalProduct = cartItem.external_product\n\n // 1. 判断购物车商品是否是当前商品\n let isProductFind = false\n // 优先使用活动商品 id 进行比较\n if (cartItemExternalProduct) {\n isProductFind = cartItemExternalProduct.id === promotionActivityProduct?.id\n } else {\n isProductFind = productId\n ? cartItemProduct.id === productId\n : cartItemProduct.code === productCode\n }\n\n if (!isProductFind) {\n return false\n }\n\n // 2. 如果没有 skuId,则匹配到商品即可\n const targetSkuId = skuId || this.skuId\n if (!targetSkuId) {\n return true\n }\n\n const cartItemSku = cartItem.sku\n const cartItemSkuExternal = cartItem.external_sku\n // 3. 判断 sku_id 是否一样,优先使用活动 sku_id\n const isSkuEqual = cartItemSkuExternal\n ? cartItemSkuExternal.id === targetSkuId\n : cartItemSku.id === targetSkuId\n\n if (!isSkuEqual) {\n return false\n }\n\n const cartItemCustomizationItemList = cartItem.product_customization_item_list || []\n // 4. 如果做法值列表为空,则匹配到商品 + sku_id 即可\n if (isEmpty(customizationItemList) && isEmpty(cartItemCustomizationItemList)) {\n return true\n }\n\n const flattenCustomizationItemList = flattenDeep(customizationItemList)\n\n // 5. 比较做法值列表是否相等, 数组长度一致,且 id 和 count 一致\n return checkCustomizationItemListEqual(flattenCustomizationItemList, cartItemCustomizationItemList)\n })\n\n return findCartItem ? cloneDeep(findCartItem) : undefined\n }\n\n /**\n * 更新当前 sku 对应的购物车数据\n */\n private _updateSkuCartItem(): void {\n const skuCartItem = this._findSkuCartItem(this.skuId)\n\n this.cartItem = skuCartItem\n this.cartCount = skuCartItem?.cart?.count || 0\n }\n}\n","import {\n fill,\n find,\n isEqual,\n findIndex,\n flattenDeep,\n} from 'lodash-es'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n MALL_PRODUCT_SPEC_TYPE_SINGLE,\n} from './constant'\n\nimport {\n IImage,\n IProduct,\n ISpecList,\n IFormatSku,\n ISkuCombination,\n IProductSpecGroup,\n IProductCustomizationGroupItemView,\n IProductSelectedCustomizationItem,\n ISkuPopupData,\n ISkuPopupSbumitData,\n} from './type'\n\nimport {\n getSpecImage,\n formatSpecObj,\n formatSpecList,\n formatSkuListAfter,\n\n checkProductOnSale,\n formatProductStatus,\n} from './productUtil'\n\nimport {\n checkCustomizationItemList,\n formatCustomizationGroupList,\n formatInitCustomizationItemList,\n reconstructCustomizationItemList,\n calculateSelectedCustomizationPrice,\n formatSkuNameWithCustomization,\n formatCustomizationCountType,\n} from './customizationUtil'\n\nexport interface IChildCustomSelectorOptions {\n productData: ISkuPopupData\n initSkuId?: number\n customizationItemList?: IProductSelectedCustomizationItem[][]\n exchangeRate?: number\n channel1Type: number\n onChange: () => void\n}\n\n// ────────── 提交校验结果 ──────────\n\nexport interface IChildCustomSubmitResult {\n isValid: boolean\n errMsg?: string\n data?: ISkuPopupSbumitData\n}\n\n// ────────── Selector 视图数据 ──────────\n\nexport interface IChildCustomSelectorView {\n product: IProduct\n specImage: IImage | undefined\n skuListAfter: ISkuCombination[]\n selectedSpecs: string[]\n productSpecGroupList: ISpecList[]\n customizationGroupList: IProductCustomizationGroupItemView[]\n customizationItemList: IProductSelectedCustomizationItem[][]\n count: number\n isScrollable: boolean\n salePrice: number\n}\n\nexport class ChildCustomSelector {\n\n // ────────── 私有状态 ──────────\n\n private product: IProduct = {} as IProduct\n private specImage: IImage | undefined = undefined\n\n private skuId: number = 0\n private sku: IFormatSku | undefined = undefined\n private count: number = 1\n\n private stockCount: number = 0\n private minCount: number = 1\n private maxCount: number = 1\n private perOrderMinLimit: number = -1\n private perOrderMaxLimit: number = -1\n\n private skuList: IFormatSku[] = []\n private skuListAfter: ISkuCombination[] = []\n private selectedSpecs: string[] = []\n private productSpecGroupList: ISpecList[] = []\n private specList: IProductSpecGroup[] = []\n\n private customizationGroupList: IProductCustomizationGroupItemView[] = []\n private customizationItemList: IProductSelectedCustomizationItem[][] = []\n\n private isScrollable: boolean = false\n\n // ────────── 初始化参数保存 ──────────\n\n private exchangeRate: number\n private channel1Type: number\n private onChange: () => void\n\n private _initCustomizationItemList: IProductSelectedCustomizationItem[][] | undefined\n\n constructor(options: IChildCustomSelectorOptions) {\n const {\n productData,\n initSkuId,\n customizationItemList,\n exchangeRate = 10000,\n channel1Type,\n onChange,\n } = options\n\n this.exchangeRate = exchangeRate\n this.channel1Type = channel1Type\n this.onChange = onChange\n this._initCustomizationItemList = customizationItemList\n\n this._initProductData(productData, initSkuId)\n }\n\n // ────────── 视图数据 ──────────\n\n getView(): IChildCustomSelectorView {\n return {\n product: this.product,\n specImage: this.specImage,\n skuListAfter: this.skuListAfter,\n selectedSpecs: this.selectedSpecs,\n productSpecGroupList: this.productSpecGroupList,\n customizationGroupList: this.customizationGroupList,\n customizationItemList: this.customizationItemList,\n count: this.count,\n isScrollable: this.isScrollable,\n salePrice: this._formatSalePrice(),\n }\n }\n\n // ────────── 规格选择 ──────────\n\n handleSelectSpecs(isOption: boolean, value: string, index: number): void {\n const { specList, skuListAfter, selectedSpecs, productSpecGroupList } = this\n\n if (productSpecGroupList.length > 0) {\n if (selectedSpecs[index] === value || !isOption) {\n return\n }\n\n selectedSpecs[index] = selectedSpecs[index] === value ? '' : value\n\n this.selectedSpecs = selectedSpecs.slice()\n }\n\n if (selectedSpecs.indexOf('') < 0) {\n find(skuListAfter, item => {\n const equal = isEqual(item.specs, selectedSpecs)\n\n if (equal) {\n this._updateSkuData(item)\n }\n\n return equal\n })\n\n if (specList[0]?.items[0].image !== undefined) {\n specList[0].items.forEach(item => {\n if (item.name === selectedSpecs[0]) {\n this.specImage = item.image\n }\n })\n }\n }\n\n this._notifyChange()\n }\n\n // ────────── 做法选择 ──────────\n\n handleCustomizationItemListSelect(customizationItemList: IProductSelectedCustomizationItem[][]): void {\n this.customizationItemList = customizationItemList\n this._notifyChange()\n }\n\n // 获取选中规格和做法合并后的数据\n getSelectedSpecAndCustomization(): string {\n let name = this.selectedSpecs.join('、')\n const flattenCustomizationItemList = flattenDeep(this.customizationItemList)\n\n name = formatSkuNameWithCustomization(name, flattenCustomizationItemList)\n const countTypeName = formatCustomizationCountType(flattenCustomizationItemList)\n\n if (isEmpty(name) && isEmpty(countTypeName)) {\n return ''\n }\n\n if (isEmpty(name) || isEmpty(countTypeName)) {\n return name ? name : countTypeName\n }\n\n return `${name}、${countTypeName}`\n }\n\n // ────────── 数量变化 ──────────\n\n handleProductCountChange(count: number, type: string): { isValid: boolean; errMsg?: string } {\n const { selectedSpecs, customizationItemList, customizationGroupList, perOrderMinLimit } = this\n\n if (selectedSpecs.indexOf('') < 0) {\n if (count > 0) {\n if (type === 'CHANGE_TYPE_DECREASE' && perOrderMinLimit !== -1 && count < perOrderMinLimit) {\n return { isValid: false }\n }\n\n const res = checkCustomizationItemList(customizationGroupList || [], customizationItemList || [])\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n\n const countCheck = this._checkProductCount(count)\n if (!countCheck.isValid) {\n return countCheck\n }\n }\n\n return { isValid: true }\n }\n else {\n return { isValid: false, errMsg: '请选择规格' }\n }\n }\n\n // ────────── 提交 ──────────\n\n handleSubmit(): IChildCustomSubmitResult {\n const {\n sku,\n count,\n product,\n skuList,\n selectedSpecs,\n productSpecGroupList,\n customizationItemList,\n customizationGroupList,\n } = this\n\n const selectedSpecsIndex = selectedSpecs.indexOf('')\n const isProductOnSale = checkProductOnSale(product?.status, product?.has_stock)\n const productStatusDesc = formatProductStatus(product?.status, product?.has_stock)\n\n if (skuList[0].item_ids.length === 0 || selectedSpecsIndex < 0) {\n if (!isProductOnSale) {\n return { isValid: false, errMsg: productStatusDesc }\n }\n\n if (!isEmpty(customizationGroupList)) {\n const res = checkCustomizationItemList(customizationGroupList, customizationItemList || [])\n if (!res.isValid) {\n return { isValid: false, errMsg: res.errMsg }\n }\n }\n\n const data: ISkuPopupSbumitData = {\n sku: sku!,\n count,\n customizationItemList,\n }\n\n return { isValid: true, data }\n }\n else {\n return {\n isValid: false,\n errMsg: `请选择${productSpecGroupList[selectedSpecsIndex].title}`,\n }\n }\n }\n\n // ────────── 滚动状态更新 ──────────\n\n setScrollable(isScrollable: boolean): void {\n this.isScrollable = isScrollable\n this._notifyChange()\n }\n\n // ────────── 私有方法 ──────────\n\n private _initProductData(data: ISkuPopupData, initSkuId?: number): void {\n const {\n product,\n skuList,\n productCover,\n productSpecGroupList,\n productCustomizationGroupList,\n } = data\n\n const specObj = formatSpecObj(productSpecGroupList)\n const newProductSpecGroupList = formatSpecList(productSpecGroupList)\n const skuListAfter = formatSkuListAfter(skuList, specObj)\n const specImage = getSpecImage(productSpecGroupList, productCover)\n const customizationGroupList = formatCustomizationGroupList(productCustomizationGroupList || [])\n const initCustomizationItemList = formatInitCustomizationItemList(customizationGroupList)\n\n this.product = product\n this.specImage = specImage\n this.skuList = skuList\n this.skuListAfter = skuListAfter\n this.selectedSpecs = fill(new Array(newProductSpecGroupList.length), '')\n this.productSpecGroupList = newProductSpecGroupList\n this.specList = productSpecGroupList\n this.customizationGroupList = customizationGroupList\n this.customizationItemList = initCustomizationItemList\n\n // 购物车中有做法值,初始化时,需回填做法值列表\n if (!isEmpty(this._initCustomizationItemList)) {\n const res = reconstructCustomizationItemList(\n customizationGroupList,\n flattenDeep(this._initCustomizationItemList)\n )\n this.customizationGroupList = res.customizationGroupList\n this.customizationItemList = res.selectedCustomizationItemList\n }\n\n const specType = product.spec_type\n\n // 单规格商品\n if (specType === MALL_PRODUCT_SPEC_TYPE_SINGLE) {\n this._updateSkuData(skuList[0])\n return\n }\n\n let skuIndex = 0\n if (!isEmpty(initSkuId)) {\n skuIndex = findIndex(skuListAfter, item => item.id === initSkuId)\n if (skuIndex === -1) {\n skuIndex = 0\n }\n }\n\n skuListAfter[skuIndex]?.specs.forEach((item, index) => {\n this.handleSelectSpecs(true, item, index)\n })\n }\n\n private _updateSkuData(sku: IFormatSku): void {\n const skuId = sku.id\n const stockCount = sku.stock_count\n const perOrderMinLimit = sku.per_order_min_limit\n const perOrderMaxLimit = sku.per_order_max_limit\n const minCount = perOrderMinLimit === -1 ? 1 : Math.min(perOrderMinLimit, stockCount)\n const maxCount = perOrderMaxLimit === -1 ? stockCount : Math.min(perOrderMaxLimit, stockCount)\n\n this.sku = sku\n this.skuId = skuId\n this.stockCount = stockCount\n this.minCount = minCount\n this.maxCount = maxCount\n this.perOrderMinLimit = perOrderMinLimit\n this.perOrderMaxLimit = perOrderMaxLimit\n }\n\n private _checkProductCount(count: number): { isValid: boolean; errMsg?: string } {\n const { minCount, maxCount, stockCount, perOrderMinLimit } = this\n\n if (count < minCount || count < perOrderMinLimit) {\n if (perOrderMinLimit !== -1) {\n return { isValid: false, errMsg: `该商品 ${perOrderMinLimit} 件起售哦` }\n }\n else {\n return { isValid: false, errMsg: `购买数量至少 ${minCount} 件` }\n }\n }\n\n if (count > maxCount) {\n if (count > stockCount) {\n return { isValid: false, errMsg: '库存不足' }\n }\n else {\n return { isValid: false, errMsg: `该商品最多购买 ${maxCount} 件哦` }\n }\n }\n\n return { isValid: true }\n }\n\n private _formatSalePrice(): number {\n const { customizationGroupList, customizationItemList } = this\n\n const selectedCustomizationPrice = calculateSelectedCustomizationPrice(\n customizationGroupList || [],\n customizationItemList || []\n )\n\n return selectedCustomizationPrice\n }\n\n private _notifyChange(): void {\n this.onChange()\n }\n}\n","/** 折扣券。对齐 coupon_type = 1,走折扣票面 */\nexport const COUPON_TYPE_DISCOUNT = 1\n/** 满减券。对齐 coupon_type = 2,走金额票面 */\nexport const COUPON_TYPE_AMOUNT = 2\n/** 配送券。对齐 coupon_type = 3,走金额票面 */\nexport const COUPON_TYPE_FREIGHT = 3\n\n/** 使用门槛:按金额。对齐 threshold_type */\nexport const COUPON_THRESHOLD_TYPE_AMOUNT = 1\n/** 使用门槛:按件数。对齐 threshold_type */\nexport const COUPON_THRESHOLD_TYPE_COUNT = 2\n\n/** 生效开始:立即。对齐 effective_start_type */\nexport const COUPON_EFFECTIVE_START_TYPE_NOW = 1\n/** 生效开始:指定时间。对齐 effective_start_type */\nexport const COUPON_EFFECTIVE_START_TYPE_FUTURE = 2\n\n/** 生效结束:永久。对齐 effective_end_type */\nexport const COUPON_EFFECTIVE_END_TYPE_FOREVER = 1\n/** 生效结束:指定时间。对齐 effective_end_type */\nexport const COUPON_EFFECTIVE_END_TYPE_FUTURE = 2\n/** 生效结束:领取后延长 N 天。对齐 effective_end_type */\nexport const COUPON_EFFECTIVE_END_TYPE_EXTEND = 3\n\n/** 可用日期:按天(每天)。对齐 available_repeat_type */\nexport const COUPON_AVAILABLE_REPEAT_TYPE_DAILY = 0\n/** 可用日期:按周。对齐 available_repeat_type */\nexport const COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY = 1\n/** 可用日期:按月。对齐 available_repeat_type */\nexport const COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY = 2\n\n/** 券实例状态:待生效。对齐 coupon.status */\nexport const COUPON_STATUS_PENDING = 1\n/** 券实例状态:已生效。对齐 coupon.status */\nexport const COUPON_STATUS_ENABLED = 2\n/** 券实例状态:已使用。对齐 coupon.status */\nexport const COUPON_STATUS_USED = 3\n/** 券实例状态:已过期。对齐 coupon.status */\nexport const COUPON_STATUS_EXPIRED = 4\n/** 券实例状态:已注销。对齐 coupon.status */\nexport const COUPON_STATUS_CANCELED = 5\n/** 券实例状态:已锁定。对齐 coupon.status */\nexport const COUPON_STATUS_LOCKED = 6\n\n/** 券模板状态:草稿。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_DRAFT = 1\n/** 券模板状态:已上线。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_ONLINE = 2\n/** 券模板状态:已下线。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_OFFLINE = 3\n/** 券模板状态:已过期。对齐 coupon_template.status */\nexport const COUPON_TEMPLATE_STATUS_EXPIRED = 4\n\n/** 接口没给 available_error 时,按已知状态补不可用原因 */\nexport const COUPON_TEMPLATE_STATUS_UNAVAILABLE_ERROR: Record<number, string> = {\n [COUPON_TEMPLATE_STATUS_DRAFT]: '优惠券为草稿状态',\n [COUPON_TEMPLATE_STATUS_OFFLINE]: '优惠券已下线',\n [COUPON_TEMPLATE_STATUS_EXPIRED]: '优惠券已过期',\n}\n\n/** 券实例独有状态:已注销 / 已锁定。数字不与模板冲突 */\nexport const COUPON_STATUS_UNAVAILABLE_ERROR: Record<number, string> = {\n ...COUPON_TEMPLATE_STATUS_UNAVAILABLE_ERROR,\n [COUPON_STATUS_CANCELED]: '优惠券已注销',\n [COUPON_STATUS_LOCKED]: '优惠券已锁定',\n}\n\n/** 可用券展开:使用规则等额外信息 */\nexport const COUPON_EXPAND_TYPE_EXTRA = 'extra'\n/** 不可用券展开:本单不可用原因 */\nexport const COUPON_EXPAND_TYPE_REASON = 'reason'\n/** 没有可展开内容 */\nexport const COUPON_EXPAND_TYPE_NONE = 'none'\n\n/** confirm 未选券时的默认提示 */\nexport const COUPON_CONFIRM_EMPTY_MSG = '请选择优惠券'\n\n/** 实例票面:过期时间展示具体截止日期 */\nexport const COUPON_EXPIRE_MODE_DEADLINE = 'deadline'\n/** 模板票面:有效期,按次卡同一套开始/结束类型拼文案 */\nexport const COUPON_EXPIRE_MODE_VALIDITY = 'validity'\n","import { formatMinuteSegments } from '@yorkjs/hive'\n\nimport {\n COUPON_AVAILABLE_REPEAT_TYPE_DAILY,\n COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY,\n COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY,\n} from './constant'\n\n/**\n * 可用日期 / 时段格式化。\n * 优惠券、次卡共用同一套营销字段(available_repeat_*、available_minute_segments),\n * 文案不走 i18n,与列表页中文规则对齐。\n */\n\n/** 一周顺序:周一 ~ 周日(周日为 0) */\nconst WEEK_ORDER = [1, 2, 3, 4, 5, 6, 0]\n\n/** 连续天数达到该值才用区间展示;2 天仍逐个列出 */\nconst MIN_CONSECUTIVE_RANGE_LENGTH = 3\n\nconst WEEK_SHORT_LABEL_MAP: Record<number, string> = {\n 1: '一',\n 2: '二',\n 3: '三',\n 4: '四',\n 5: '五',\n 6: '六',\n 0: '日',\n}\n\nconst WORKDAYS = [1, 2, 3, 4, 5]\nconst WEEKEND = [6, 0]\n\n/** 文档全天为 [0, 1440];选择器常只能选到 23:59,即 [0, 1439] */\nconst FULL_DAY_START = 0\nconst FULL_DAY_END = 1440\nconst LAST_MINUTE_OF_DAY = 1439\n\nexport interface IFormatAvailableRepeatOptions {\n /** 重复类型:0 每天 / 1 每周 / 2 每月 */\n repeatType?: number\n /** 周几或每月几号;周:0-6,月:1-28。也可传接口 JSON 字符串 */\n repeatValue?: Array<number | string> | string\n /** 日内时段,一维 [start, end, ...],单位分钟 */\n minuteSegments?: Array<number | string> | string\n}\n\n/** 00:00-24:00 或 00:00-23:59 都视为全天 */\nexport function isFullDayMinuteSegment(start: number, end: number) {\n return start === FULL_DAY_START && (end === FULL_DAY_END || end === LAST_MINUTE_OF_DAY)\n}\n\n/**\n * 接口里的周几 / 日期 / 时段可能是 number[] 或 JSON 字符串。\n * formatItem 原样搬运即可,这里统一收成 number[]。\n */\nexport function parseCouponNumberList(value?: Array<number | string> | string): number[] {\n if (Array.isArray(value)) {\n return value\n .map(item => Number(item))\n .filter(item => Number.isFinite(item) && item >= 0)\n }\n\n if (typeof value === 'string' && value) {\n try {\n const parsed = JSON.parse(value)\n if (Array.isArray(parsed)) {\n return parseCouponNumberList(parsed)\n }\n }\n catch (error) {\n return value\n .split(',')\n .map(item => Number(item))\n .filter(item => Number.isFinite(item) && item >= 0)\n }\n }\n\n return []\n}\n\nconst isSameNumberSet = (source: number[], target: number[]) => {\n if (source.length !== target.length) {\n return false\n }\n const targetSet = new Set(target)\n return source.every(item => targetSet.has(item))\n}\n\n/** 已排序序列切成连续段。周几不绕回:周六、周日、周一不算连续 */\nconst splitConsecutiveGroups = (\n items: number[],\n isConsecutivePair: (prev: number, curr: number) => boolean = (prev, curr) => curr === prev + 1,\n) => {\n if (!items.length) {\n return [] as number[][]\n }\n\n const groups: number[][] = [[items[0]]]\n\n for (let i = 1; i < items.length; i++) {\n const prev = items[i - 1]\n const curr = items[i]\n if (isConsecutivePair(prev, curr)) {\n groups[groups.length - 1].push(curr)\n continue\n }\n groups.push([curr])\n }\n\n return groups\n}\n\nconst isConsecutiveWeekDayPair = (prev: number, curr: number) => {\n const prevIndex = WEEK_ORDER.indexOf(prev)\n const currIndex = WEEK_ORDER.indexOf(curr)\n return prevIndex >= 0 && currIndex === prevIndex + 1\n}\n\nconst formatConsecutiveGroupParts = (\n groups: number[][],\n formatRange: (start: number, end: number) => string,\n formatSingle: (item: number) => string,\n) => {\n const parts: string[] = []\n\n groups.forEach((group) => {\n if (group.length >= MIN_CONSECUTIVE_RANGE_LENGTH) {\n parts.push(formatRange(group[0], group[group.length - 1]))\n return\n }\n group.forEach((item) => {\n parts.push(formatSingle(item))\n })\n })\n\n return parts\n}\n\n/**\n * 每周:工作日 / 周六日 / 周一到周三 / 每周一、二、三\n */\nconst formatWeeklyRepeatDateText = (repeatValue: number[]) => {\n if (!repeatValue.length) {\n return ''\n }\n\n if (isSameNumberSet(repeatValue, WORKDAYS)) {\n return '工作日'\n }\n\n if (isSameNumberSet(repeatValue, WEEKEND)) {\n return '周六日'\n }\n\n const orderedDays = WEEK_ORDER.filter(day => repeatValue.includes(day))\n const groups = splitConsecutiveGroups(orderedDays, isConsecutiveWeekDayPair)\n const hasRange = groups.some(group => group.length >= MIN_CONSECUTIVE_RANGE_LENGTH)\n\n if (!hasRange) {\n const labels = orderedDays.map(day => WEEK_SHORT_LABEL_MAP[day])\n return `每周${labels.join('、')}`\n }\n\n const parts = formatConsecutiveGroupParts(\n groups,\n (start, end) => `周${WEEK_SHORT_LABEL_MAP[start]}到周${WEEK_SHORT_LABEL_MAP[end]}`,\n day => `周${WEEK_SHORT_LABEL_MAP[day]}`,\n )\n\n return parts.join('、')\n}\n\n/**\n * 每月:连续 >=3 用 1-20号;否则 每月4, 6号\n */\nconst formatMonthlyRepeatDateText = (repeatValue: number[]) => {\n if (!repeatValue.length) {\n return ''\n }\n\n const sortedDays = [...new Set(repeatValue)].sort((a, b) => a - b)\n const groups = splitConsecutiveGroups(sortedDays)\n const hasRange = groups.some(group => group.length >= MIN_CONSECUTIVE_RANGE_LENGTH)\n\n if (!hasRange) {\n return `每月${sortedDays.join(', ')}号`\n }\n\n const parts = formatConsecutiveGroupParts(\n groups,\n (start, end) => `${start} - ${end}号`,\n day => `${day}号`,\n )\n\n return parts.join('、')\n}\n\n/** 仅日期部分,不含时段。按天且未选具体日时返回空,由调用方补「每天」 */\nexport function formatAvailableRepeatDateText(options: IFormatAvailableRepeatOptions = {}) {\n const {\n repeatType = COUPON_AVAILABLE_REPEAT_TYPE_DAILY,\n repeatValue = [],\n } = options\n\n const days = parseCouponNumberList(repeatValue)\n\n if (repeatType === COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY) {\n return formatWeeklyRepeatDateText(days)\n }\n\n if (repeatType === COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY) {\n return formatMonthlyRepeatDateText(days)\n }\n\n return ''\n}\n\n/**\n * 日期 + 时段拼成一句,次卡列表等场景用。\n * 例:工作日08:00-11:00;都空时「全天」\n */\nexport function formatAvailableRepeatText(options: IFormatAvailableRepeatOptions = {}) {\n const {\n repeatType = COUPON_AVAILABLE_REPEAT_TYPE_DAILY,\n repeatValue = [],\n minuteSegments = [],\n } = options\n\n const dateText = formatAvailableRepeatDateText({\n repeatType,\n repeatValue,\n })\n const timeText = formatMinuteSegments(parseCouponNumberList(minuteSegments))\n\n return `${dateText}${timeText}` || '全天'\n}\n\n/**\n * 使用次数限制。例:每日2次、每周3次、每月5次;都没有则「不限制」\n */\nexport function formatUseLimitText(options: {\n daily?: number | string\n weekly?: number | string\n monthly?: number | string\n} = {}) {\n const parts: string[] = []\n const dailyNum = Number(options.daily) || 0\n const weeklyNum = Number(options.weekly) || 0\n const monthlyNum = Number(options.monthly) || 0\n\n if (dailyNum > 0) {\n parts.push(`每日${dailyNum}次`)\n }\n if (weeklyNum > 0) {\n parts.push(`每周${weeklyNum}次`)\n }\n if (monthlyNum > 0) {\n parts.push(`每月${monthlyNum}次`)\n }\n\n return parts.length ? parts.join('、') : '不限制'\n}\n","import * as hive from '@yorkjs/hive'\n\nimport { isEmpty } from '../util/dataType'\n\nimport {\n formatAvailableRepeatDateText,\n formatUseLimitText,\n parseCouponNumberList,\n} from './availableRepeat'\n\nimport {\n COUPON_EXPAND_TYPE_EXTRA,\n COUPON_EXPAND_TYPE_NONE,\n COUPON_EXPAND_TYPE_REASON,\n COUPON_EXPIRE_MODE_DEADLINE,\n COUPON_EXPIRE_MODE_VALIDITY,\n COUPON_EFFECTIVE_END_TYPE_EXTEND,\n COUPON_EFFECTIVE_END_TYPE_FOREVER,\n COUPON_EFFECTIVE_END_TYPE_FUTURE,\n COUPON_EFFECTIVE_START_TYPE_FUTURE,\n COUPON_EFFECTIVE_START_TYPE_NOW,\n COUPON_THRESHOLD_TYPE_AMOUNT,\n COUPON_THRESHOLD_TYPE_COUNT,\n COUPON_TEMPLATE_STATUS_ONLINE,\n COUPON_STATUS_UNAVAILABLE_ERROR,\n COUPON_TYPE_DISCOUNT,\n} from './constant'\n\nimport {\n CouponExpandType,\n CouponExpireMode,\n CouponFormatItem,\n ICoupon,\n ICouponKvLine,\n ICouponViewItem,\n} from './type'\n\n/** id 统一转字符串再比,避免 number / string 回显对不上 */\nexport function isSameCouponId(a?: string | number, b?: string | number) {\n if (a == null || b == null) {\n return false\n }\n return String(a) === String(b)\n}\n\n/**\n * 接口是否给了不可用原因。\n * 0 / false / 空字符串视为没返回原因,避免把占位值当成 available_error。\n */\nfunction hasCouponApiAvailableError(error: unknown) {\n if (error == null || error === false || error === 0) {\n return false\n }\n if (typeof error === 'string') {\n return error.trim().length > 0\n }\n return !isEmpty(error)\n}\n\n/**\n * 可用态。\n * 1. availableError 有值:一定不可用\n * 2. 带了 status 则只有 2(已上线 / 已生效)可用\n * 3. 没带 status:没有 availableError 则可用(兼容列表只筛 status、项上不回传该字段)\n */\nexport function resolveCouponAvailable(coupon: Pick<ICoupon, 'availableError' | 'status'>) {\n if (hasCouponApiAvailableError(coupon.availableError)) {\n return false\n }\n if (coupon.status == null || coupon.status === ('' as any)) {\n return true\n }\n return Number(coupon.status) === COUPON_TEMPLATE_STATUS_ONLINE\n}\n\n/**\n * 展开用的不可用原因。\n * 接口 availableError 优先;没有时按已知状态补文案(草稿/下线/过期/注销/锁定),其它灰态不展开。\n */\nexport function resolveCouponAvailableError(coupon: Pick<ICoupon, 'availableError' | 'status'>) {\n if (hasCouponApiAvailableError(coupon.availableError)) {\n return String(coupon.availableError)\n }\n return COUPON_STATUS_UNAVAILABLE_ERROR[Number(coupon.status)] || ''\n}\n\n/**\n * 原始列表 → 标准 ICoupon。\n * 有 formatItem 就逐项转换(返回空则跳过);没有则把项当作已是 ICoupon。\n * 未带 original 时自动挂上原始 item。可用券排在不可用前面,组内保持原相对顺序。\n */\nexport function formatCouponList(rawList?: any[], formatItem?: CouponFormatItem): ICoupon[] {\n const source = Array.isArray(rawList) ? rawList : []\n const result: ICoupon[] = []\n\n source.forEach((item) => {\n const coupon = formatItem ? formatItem(item) : (item as ICoupon)\n if (!coupon || coupon.id == null) {\n return\n }\n const next: ICoupon = {\n ...coupon,\n original: coupon.original !== undefined ? coupon.original : item,\n }\n result.push(next)\n })\n\n return result.sort((a, b) => Number(resolveCouponAvailable(b)) - Number(resolveCouponAvailable(a)))\n}\n\nconst DISCOUNT_UNIT = '折'\n\n/**\n * 是否走折扣票面(折)。\n * couponType === 1 为折扣;2/3 为金额。\n */\nexport function isCouponDiscountBenefit(coupon: ICoupon): boolean {\n return Number(coupon.couponType) === COUPON_TYPE_DISCOUNT\n}\n\n/** 票面数字。满减走 formatAmount;折扣走 formatDiscount,只返回数字部分 */\nexport function formatCouponAmountValue(coupon: ICoupon): string {\n if (isEmpty(coupon.couponValue)) {\n return ''\n }\n if (isCouponDiscountBenefit(coupon)) {\n const formatted = hive.formatDiscount(Number(coupon.couponValue))\n if (!formatted || formatted === 'NaN折') {\n return ''\n }\n return formatted.endsWith(DISCOUNT_UNIT)\n ? formatted.slice(0, -DISCOUNT_UNIT.length)\n : formatted\n }\n\n // 票面大字用 5 而不是 5.00\n return stripAmountZero(hive.formatAmount(coupon.couponValue, ''))\n}\n\n/** 票面左侧前缀。满减 / 配送为 ¥,折扣为空 */\nexport function formatCouponAmountPrefix(coupon: ICoupon): string {\n if (!isCouponDiscountBenefit(coupon) && !isEmpty(coupon.couponValue)) {\n return '¥'\n }\n return ''\n}\n\n/** 票面右侧单位。折扣为「折」,满减 / 配送为空 */\nexport function formatCouponAmountSuffix(coupon: ICoupon): string {\n if (isCouponDiscountBenefit(coupon) && !isEmpty(coupon.couponValue)) {\n return DISCOUNT_UNIT\n }\n return ''\n}\n\n/**\n * 门槛展示值(不含「使用门槛:」)。\n * 由 thresholdType + thresholdValue 生成;0 为无门槛。\n */\nexport function formatCouponThreshold(coupon: ICoupon): string {\n const thresholdType = Number(coupon.thresholdType)\n const thresholdValue = Number(coupon.thresholdValue) || 0\n if (!thresholdValue) {\n return '无门槛'\n }\n if (thresholdType === COUPON_THRESHOLD_TYPE_COUNT) {\n return `满${thresholdValue}件`\n }\n if (thresholdType === COUPON_THRESHOLD_TYPE_AMOUNT) {\n return `满${stripAmountZero(hive.formatAmount(thresholdValue, ''))}元`\n }\n return '无门槛'\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000\n\nfunction formatExpireDate(timestamp?: number) {\n if (!timestamp) {\n return ''\n }\n return hive.formatDateTime(Number(timestamp))\n}\n\n/**\n * 算出券的截止时间戳。\n * 优惠券票面只要具体日期,和次卡「开始至结束 / 领取后 N 天」文案不是一套。\n * 有 effectiveEndTime 直接用;领取后 N 天则用开始时间(没有则当前时间)加上天数。\n */\nfunction resolveCouponExpireTimestamp(coupon: ICoupon): number | undefined {\n const endTime = Number(coupon.effectiveEndTime)\n if (Number.isFinite(endTime) && endTime > 0) {\n return endTime\n }\n\n const days = Number(coupon.effectiveEndDays)\n if (!Number.isFinite(days) || days <= 0) {\n return undefined\n }\n\n const startType = Number(coupon.effectiveStartType)\n const startTime = Number(coupon.effectiveStartTime)\n if (\n startType === COUPON_EFFECTIVE_START_TYPE_FUTURE\n && Number.isFinite(startTime)\n && startTime > 0\n ) {\n return startTime + days * DAY_MS\n }\n\n return Date.now() + days * DAY_MS\n}\n\n/**\n * 过期时间展示值(不含「过期时间:」)。\n * 给已发出的券实例用,只展示截止日期年月日时分,或永久有效。\n */\nexport function formatCouponExpireText(coupon: ICoupon): string {\n if (Number(coupon.effectiveEndType) === COUPON_EFFECTIVE_END_TYPE_FOREVER) {\n return '长期有效'\n }\n\n const expireDate = formatExpireDate(resolveCouponExpireTimestamp(coupon))\n if (expireDate) {\n return expireDate\n }\n\n return '长期有效'\n}\n\n/**\n * 有效期展示值(不含「有效期:」)。\n * 给发券选模板用,字段和次卡同一套开始/结束类型,不把「领取后 N 天」折成当前时间。\n */\nexport function formatCouponValidityText(coupon: ICoupon): string {\n const startType = Number(coupon.effectiveStartType) || COUPON_EFFECTIVE_START_TYPE_NOW\n const endType = Number(coupon.effectiveEndType)\n const startDate = formatExpireDate(coupon.effectiveStartTime)\n const endDate = formatExpireDate(coupon.effectiveEndTime)\n const days = coupon.effectiveEndDays\n\n if (startType === COUPON_EFFECTIVE_START_TYPE_NOW) {\n if (endType === COUPON_EFFECTIVE_END_TYPE_FOREVER) {\n return '自获取后永久有效'\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_FUTURE) {\n return endDate ? `自获取后截止${endDate}期间有效` : ''\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_EXTEND) {\n return days ? `自获取后${days}天内有效` : ''\n }\n }\n\n if (startType === COUPON_EFFECTIVE_START_TYPE_FUTURE) {\n if (endType === COUPON_EFFECTIVE_END_TYPE_FOREVER) {\n return startDate ? `${startDate}起永久有效` : ''\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_FUTURE) {\n return startDate && endDate ? `${startDate}至${endDate}有效` : ''\n }\n if (endType === COUPON_EFFECTIVE_END_TYPE_EXTEND) {\n return startDate && days ? `${startDate}起${days}天内有效` : ''\n }\n }\n\n return ''\n}\n\nfunction resolveExpireMode(expireMode?: CouponExpireMode) {\n return expireMode === COUPON_EXPIRE_MODE_VALIDITY\n ? COUPON_EXPIRE_MODE_VALIDITY\n : COUPON_EXPIRE_MODE_DEADLINE\n}\n\n/** 可用日期。按天未选具体日时为「每天」 */\nexport function formatCouponAvailableDateText(coupon: ICoupon): string {\n const dateText = formatAvailableRepeatDateText({\n repeatType: coupon.availableRepeatType,\n repeatValue: coupon.availableRepeatValue,\n })\n return dateText || '每天'\n}\n\n/** 可用时段。空或全天时段走 hive formatMinuteSegments,空数组为「全天」 */\nexport function formatCouponAvailableTimeText(coupon: ICoupon): string {\n const segments = parseCouponNumberList(coupon.availableMinuteSegments)\n if (!segments.length) {\n return '全天'\n }\n return hive.formatMinuteSegments(segments) || '全天'\n}\n\n/** 使用限制展示值(不含「使用限制:」)。无限制时为「不限制」 */\nexport function formatCouponUseLimitText(coupon: ICoupon): string {\n return formatUseLimitText({\n daily: coupon.useLimitCountDaily,\n weekly: coupon.useLimitCountWeekly,\n monthly: coupon.useLimitCountMonthly,\n })\n}\n\nfunction stripAmountZero(text: string) {\n return String(text).replace(/\\.00$/, '')\n}\n\n/** 把键值行拼成「键:值」;label 为空时只返回 value */\nexport function formatCouponKvText(line: ICouponKvLine): string {\n if (!line.label) {\n return line.value\n }\n return `${line.label}:${line.value}`\n}\n\n/** 票面信息区:使用门槛、过期时间 / 有效期 */\nexport function getCouponContentLines(\n coupon: ICoupon,\n expireMode?: CouponExpireMode,\n): ICouponKvLine[] {\n const lines: ICouponKvLine[] = []\n const threshold = formatCouponThreshold(coupon)\n if (threshold) {\n lines.push({ label: '使用门槛', value: threshold })\n }\n\n const mode = resolveExpireMode(expireMode)\n if (mode === COUPON_EXPIRE_MODE_VALIDITY) {\n const validityText = formatCouponValidityText(coupon)\n if (validityText) {\n lines.push({ label: '有效期', value: validityText })\n }\n return lines\n }\n\n const expireText = formatCouponExpireText(coupon)\n if (expireText) {\n lines.push({ label: '过期时间', value: expireText })\n }\n return lines\n}\n\nfunction isPresentNumber(value: unknown) {\n return value != null && value !== '' && !Number.isNaN(Number(value))\n}\n\n/** 是否带了可用日期 / 时段,用来决定要不要生成展开行 */\nexport function hasCouponAvailableRepeat(coupon: ICoupon) {\n return isPresentNumber(coupon.availableRepeatType)\n || !isEmpty(parseCouponNumberList(coupon.availableRepeatValue))\n || !isEmpty(parseCouponNumberList(coupon.availableMinuteSegments))\n}\n\n/** 是否带了使用限制字段(含 0,表示明确「不限制」也要展示) */\nexport function hasCouponUseLimit(coupon: ICoupon) {\n return coupon.useLimitCountDaily != null\n || coupon.useLimitCountWeekly != null\n || coupon.useLimitCountMonthly != null\n}\n\nfunction getCouponGeneratedExtraLines(coupon: ICoupon): ICouponKvLine[] {\n const lines: ICouponKvLine[] = []\n if (hasCouponAvailableRepeat(coupon)) {\n lines.push({ label: '可用日期', value: formatCouponAvailableDateText(coupon) })\n lines.push({ label: '可用时间', value: formatCouponAvailableTimeText(coupon) })\n }\n if (hasCouponUseLimit(coupon)) {\n lines.push({ label: '使用限制', value: formatCouponUseLimitText(coupon) })\n }\n return lines\n}\n\n/** 把「键:值」拆回键值行;没有分隔符则整句当 value */\nexport function parseCouponKvLine(text: string): ICouponKvLine {\n const match = String(text).match(/^(.+?)[::](.*)$/)\n if (match && match[1] && match[2] !== '') {\n return {\n label: match[1].trim(),\n value: match[2].trim(),\n }\n }\n return {\n label: '',\n value: String(text),\n }\n}\n\n/** 展开区键值行。extra 走 extraLines 或生成规则,reason 为本单不可用原因 */\nexport function getCouponExpandKvLines(coupon: ICoupon): ICouponKvLine[] {\n const expandType = getCouponExpandType(coupon)\n if (expandType === COUPON_EXPAND_TYPE_EXTRA) {\n if (coupon.extraLines && coupon.extraLines.length > 0) {\n return coupon.extraLines.map(parseCouponKvLine)\n }\n return getCouponGeneratedExtraLines(coupon)\n }\n if (expandType === COUPON_EXPAND_TYPE_REASON) {\n const reason = resolveCouponAvailableError(coupon)\n if (reason) {\n return [{\n label: '本单不可用原因',\n value: reason,\n }]\n }\n }\n return []\n}\n\n/** 当前券应展示的展开类型:extra / reason / none */\nexport function getCouponExpandType(coupon: ICoupon): CouponExpandType {\n if (resolveCouponAvailable(coupon)) {\n const hasExtraLines = !!(coupon.extraLines && coupon.extraLines.length > 0)\n const hasGeneratedExtra = hasCouponAvailableRepeat(coupon) || hasCouponUseLimit(coupon)\n return hasExtraLines || hasGeneratedExtra\n ? COUPON_EXPAND_TYPE_EXTRA\n : COUPON_EXPAND_TYPE_NONE\n }\n return isEmpty(resolveCouponAvailableError(coupon))\n ? COUPON_EXPAND_TYPE_NONE\n : COUPON_EXPAND_TYPE_REASON\n}\n\n/** 展开区展示文案。reason 只出原因正文,extra 为「键:值」 */\nexport function getCouponExpandLines(coupon: ICoupon): string[] {\n return getCouponExpandKvLines(coupon).map((line) => {\n if (getCouponExpandType(coupon) === COUPON_EXPAND_TYPE_REASON) {\n return line.value\n }\n return formatCouponKvText(line)\n })\n}\n\n/**\n * ICoupon → 票面数据。选券弹层和单独挂 CouponCard 共用。\n * selected / expanded 由调用方控制,available 由 availableError + status 推出。\n */\nexport function formatCouponViewItem(\n coupon: ICoupon,\n state: {\n selected?: boolean\n expanded?: boolean\n expireMode?: CouponExpireMode\n } = {},\n): ICouponViewItem {\n const expireMode = resolveExpireMode(state.expireMode)\n return {\n coupon,\n selected: !!state.selected,\n expanded: !!state.expanded,\n available: resolveCouponAvailable(coupon),\n amountPrefix: formatCouponAmountPrefix(coupon),\n amountValue: formatCouponAmountValue(coupon),\n amountSuffix: formatCouponAmountSuffix(coupon),\n title: coupon.title || '',\n contentLines: getCouponContentLines(coupon, expireMode).map(formatCouponKvText),\n expandType: getCouponExpandType(coupon),\n expandLines: getCouponExpandLines(coupon),\n }\n}\n\n/**\n * 原始项或 ICoupon → 票面。\n * 有 formatItem 时先映射;没有则把 source 当 ICoupon。\n * formatItem 跳过该项时返回 undefined。\n */\nexport function toCouponViewItem(\n source: any,\n state: {\n selected?: boolean\n expanded?: boolean\n formatItem?: CouponFormatItem\n expireMode?: CouponExpireMode\n } = {},\n): ICouponViewItem | undefined {\n const coupon = formatCouponList([source], state.formatItem)[0]\n if (!coupon) {\n return undefined\n }\n return formatCouponViewItem(coupon, {\n selected: state.selected,\n expanded: state.expanded,\n expireMode: state.expireMode,\n })\n}\n","import {\n COUPON_CONFIRM_EMPTY_MSG,\n COUPON_EXPAND_TYPE_REASON,\n} from './constant'\n\nimport {\n ICoupon,\n ICouponConfirmResult,\n ICouponSelectorOptions,\n ICouponSelectorView,\n ICouponViewItem,\n} from './type'\n\nimport {\n formatCouponList,\n formatCouponViewItem,\n getCouponExpandType,\n isSameCouponId,\n resolveCouponAvailable,\n} from './couponUtil'\n\n/**\n * 优惠券选择器(无 UI、不发请求)。\n *\n * 列表来源由调用方决定:静态 list 或接口拉完后 setList / appendList。\n * formatItem 只把后端字段收到 ICoupon(数字 / 枚举即可);\n * 门槛、过期、可用日期/时间、使用限制由 couponUtil 格式化,getView 产出 contentLines / expandLines。\n */\nexport class CouponSelector {\n private list: ICoupon[] = []\n private selectedId?: string | number\n /**\n * 调用方传入的回显 id。\n * 接口列表异步到达前不要丢掉;分页补齐后继续用它匹配。\n */\n private preferredSelectedId?: string | number\n private expandedIds: Array<string | number> = []\n private formatItem?: ICouponSelectorOptions['formatItem']\n private exclusiveExpand = false\n private expireMode?: ICouponSelectorOptions['expireMode']\n private onChange: () => void = () => {}\n\n constructor(options: ICouponSelectorOptions) {\n this.formatItem = options.formatItem\n this.exclusiveExpand = !!options.exclusiveExpand\n this.expireMode = options.expireMode\n this.onChange = options.onChange\n this.preferredSelectedId = this._normalizeSelectedId(options.value)\n if (options.list) {\n this.list = formatCouponList(options.list, this.formatItem)\n this._dedupeList()\n }\n this.selectedId = this._pickValidSelectedId(this.preferredSelectedId)\n }\n\n /** 全量替换列表,并清掉已不存在的选中 / 展开 */\n setList(list: any[]) {\n this.list = formatCouponList(list, this.formatItem)\n this._dedupeList()\n this._syncSelectedId()\n this.expandedIds = this.expandedIds.filter(id => this._findCoupon(id))\n this._notifyChange()\n }\n\n /** 分页追加。追加后仍按可用在前重排 */\n appendList(list: any[]) {\n const next = formatCouponList(list, this.formatItem)\n this.list = formatCouponList([\n ...this.list,\n ...next,\n ])\n this._dedupeList()\n this._syncSelectedId()\n this._notifyChange()\n }\n\n /** 当前列表票面快照,给 CouponCard 渲染 */\n getView(): ICouponSelectorView {\n const selectedCoupon = this._findCoupon(this.selectedId)\n return {\n items: this.list.map(coupon => this._toViewItem(coupon)),\n selectedId: this.selectedId,\n selectedCoupon,\n }\n }\n\n /**\n * 点票面。\n * 可用:选中,再点取消;不可用:不选中,只展开原因。\n */\n select(id: string | number) {\n const coupon = this._findCoupon(id)\n if (!coupon) {\n return\n }\n if (!resolveCouponAvailable(coupon)) {\n // 有不可用原因才展开;已知状态会补原因,其它灰态不展开\n if (getCouponExpandType(coupon) === COUPON_EXPAND_TYPE_REASON) {\n this._setExpanded(id, true)\n }\n this._notifyChange()\n return\n }\n this.selectedId = isSameCouponId(this.selectedId, id) ? undefined : coupon.id\n this.preferredSelectedId = this.selectedId\n this._notifyChange()\n }\n\n /** 点箭头,只切换展开,不改变选中 */\n toggleExpand(id: string | number) {\n const coupon = this._findCoupon(id)\n if (!coupon) {\n return\n }\n const expanded = this._isExpanded(id)\n this._setExpanded(id, !expanded)\n this._notifyChange()\n }\n\n /** 确认选中。未选可用券时 isValid 为 false */\n confirm(): ICouponConfirmResult {\n const coupon = this._findCoupon(this.selectedId)\n if (!coupon || !resolveCouponAvailable(coupon)) {\n return {\n isValid: false,\n errMsg: COUPON_CONFIRM_EMPTY_MSG,\n }\n }\n return {\n isValid: true,\n coupon,\n }\n }\n\n private _toViewItem(coupon: ICoupon): ICouponViewItem {\n return formatCouponViewItem(coupon, {\n selected: isSameCouponId(coupon.id, this.selectedId),\n expanded: this._isExpanded(coupon.id),\n expireMode: this.expireMode,\n })\n }\n\n /**\n * 同一 id 只保留第一次出现的项。\n * 置顶回显 / 分页重叠会出现两张相同券,选中态会同时亮。\n */\n private _dedupeList() {\n const seen = new Set<string>()\n this.list = this.list.filter((coupon) => {\n const key = String(coupon.id)\n if (seen.has(key)) {\n return false\n }\n seen.add(key)\n return true\n })\n }\n\n private _findCoupon(id?: string | number) {\n const selectedId = this._normalizeSelectedId(id)\n if (selectedId == null) {\n return undefined\n }\n return this.list.find(item => isSameCouponId(item.id, selectedId))\n }\n\n /** 0 / 空字符串视为未选 */\n private _normalizeSelectedId(id?: string | number) {\n if (id == null || id === '' || id === 0 || id === '0') {\n return undefined\n }\n return id\n }\n\n /** 列表尚未包含该券时先留着 preferred,等 setList / appendList 再匹配 */\n private _syncSelectedId() {\n this.selectedId = this._pickValidSelectedId(\n this._normalizeSelectedId(this.selectedId) ?? this.preferredSelectedId,\n )\n }\n\n /** 回显只认当前列表里的可用券 */\n private _pickValidSelectedId(id?: string | number) {\n const coupon = this._findCoupon(id)\n if (!coupon || !resolveCouponAvailable(coupon)) {\n return undefined\n }\n return coupon.id\n }\n\n private _isExpanded(id: string | number) {\n return this.expandedIds.some(item => isSameCouponId(item, id))\n }\n\n private _setExpanded(id: string | number, expanded: boolean) {\n if (expanded) {\n if (this.exclusiveExpand) {\n this.expandedIds = [id]\n return\n }\n if (!this._isExpanded(id)) {\n this.expandedIds = this.expandedIds.concat(id)\n }\n return\n }\n this.expandedIds = this.expandedIds.filter(item => !isSameCouponId(item, id))\n }\n\n private _notifyChange() {\n this.onChange()\n }\n}\n"],"names":["isEmpty","value","isNaN","isEmptyValue","Object","prototype","toString","call","keys","length","trim","AdjoinMatrix","_createClass","vertx","_classCallCheck","_defineProperty","this","vertex","quantity","adjoinArray","init","key","fill","Array","id","sides","weight","_this","pIndex","indexOf","forEach","item","i","index","cur","push","_this2","col","params","_this3","paramsVertex","map","getVertexCol","collections","some","_this4","unions","type","row","filter","t","isItemEqual","includes","isArrayUnions","every","_t","SpecAdjoinMatrix","specList","specCombinationList","vertices","group","gi","list","concat","_callSuper","initSpec","initSameLevel","_inherits","specs","spec","fillInSpec","specsOption","getCollection","vertexId","specOptionCanchoose","Boolean","mappedParams","val","getUnions","param","setAdjoinVertexs","SpecSelector","options","productSpecGroupList","skuListAfter","_options$activitySpec","activitySpecList","specAdjoinMatrix","listIndex","find","name","selectedSpecs","optionSpecs","getSpecsOptions","_ref","title","items","isEnabled","isActive","isActivitySpec","groupIndex","_this$productSpecGrou","_this$productSpecGrou2","newSelectedSpecs","_toConsumableArray","currentGroupList","idx","validSelected","groupCount","sku","SKU_STOCK_COUNT_UNLIMITED","CHAGNE_TYPE_DECREASE","formatSkuWithPromotionActivitySaleInfoItem","promotionActivitySaleInfoItem","newSku","_objectSpread","activity_sku_id","origin_sku_id","is_promotion_activity","is_set_activity_price","sale_price","original_price","stock_count","formatProductComboChildrenSkuList","skuList","children","newSkuList","childItem","combo_sku","min_count","max_count","skuItem","newItem","per_order_min_limit","per_order_max_limit","formatProductSku","formatProductSkuList","promotionActivitySaleInfoList","isSelfActivity","mall_sku_id","saleInfoItem","formatProductActivitySkuList","formatProductSpecGroupList","useActivityFlag","newProductSpecGroupList","groupItem","newGroup","itemIds","item_ids","findItemIndex","findIndex","specValueItem","formatSpecList","formatSkuListAfter","specObj","negativeStockSaleEnabled","formatSpecObj","getSpecImage","productCover","_productSpecGroupList","specImage","undefined","image","getActivitySpecList","activitySpecItemList","formatProductBuyText","product","combo_type","select_type","checkProductOnSale","productStatus","hasStock","checkUseReducePlusBtn","formatProductStatus","arguments","formatSkuPrice","salePriceArr","minPrice","Math","min","apply","maxPrice","max","moneyToDisplay","formatPriceRange","priceRange","end_price","start_price","formatSkuListStockCount","sum","findProductCartList","cartList","activityProductId","findCartList","cartCount","productId","productCode","code","cartItem","cartItemProduct","cartItemExternalProduct","external_product","error","cart","count","formatWithExternalSku","externalSku","getSubmitCustomizationItemList","customizationItemList","pick","pickSubmitCustomizationItem","getSubmitCustomizationItemListArr","flattenDeep","calculateSelectedCustomizationPrice","customizationGroupList","price","selectedCustomizationItemList","customization_item","increase_type","increase_sale_price","selectedItem","timesNumber","formatCustomizationPrice","selectedCustomizationPrice","plusNumber","checkCustomizationItemListEqual","selectCustomizationItemList","cartCustomizationItemList","cartCustomizationItem","formatCustomizationGroupList","selected","selected_count","formatInitCustomizationItemList","formatSelectedCustomizationItemList","customizationGroupItem","customizationItems","customization","count_type","reconstructCustomizationItemList","newSelectedCustomizationItemList","newCustomizationGroupList","cloneDeep","groupItems","selectedItems","selectable","isValid","checkCustomizationItemList","errMsg","countTypeUnit","formatCountTypeUnit","customizationCount","countType","checkCustomizationItemIsUseSelectCount","customizationItem","checkCustomizationItemCanPlusCount","selectCount","checkCustomizationItemIsFixedSelected","checkCustomizationItemIsDisabledSelected","findCustomizationSkuCartItem","skuId","promotionActivityProduct","findCartItem","cartItemSku","cartItemSkuExternal","external_sku","cartItemCustomizationItemList","product_customization_item_list","genereateCartProductCustomizationItemList","submitSelectedCustomizationItemList","productCustomizationGroupList","orderSkuCustomizationItemList","customizationSalePrice","formatCustomizationGroupItemSelectTips","selectTips","selectedCount","join","handleCustomizationGroupItemSelectedChange","itemSelected","itemIndex","onChange","isSingleSelect","handleCustomizationGroupItemCountChange","handleCustomizationItemCountChange","newCount","onCountChange","itemMinCount","itemMaxCount","groupMaxCount","handleCustomizationItemToggleSelected","onSelectedChange","formatSkuNameWithCustomization","skuName","kindItemList","kindItemName","formatCustomizationCountType","itemList","formatCustomizationInfo","customizationInfos","isCountTypeQuantity","getSubmitComboItemList","skuComboItemList","comboProductCustomizationItemList","combo_product_customization_item_list","pickSubmitComboItem","getSubmitComboItemListArr","calculateSelectedComboPrice","skuComboGroupList","selectedComboItemList","hive","formatComboPrice","checkSkuComboItemListEqual","cartItemSkuComboItemList","cartItemComboItem","combo_sku_id","formatSkuComboItemName","combo_sku_name","comboSkuName","countTypeName","formatSkuComboItemList","checkComboGroupItemCanPlusCount","comboGroupItem","checkComboGroupItemIsCanChangeSelectCheckbox","_","checkComboItemIsFixedSelect","comboItem","checkComboItemIsUseSelectCheckbox","checkHasChildren","checkComboItemIsUseSelectCount","checkComboItemIsUseSelectSkuDialog","combo_product","formatComboSkuAndCustomizationName","combo_customization_item_list","checkItemCanPlusCount","canGroupPlus","formatIncreaseSalePrice","formatAmount","checkItemCanMinusCount","isFixedItem","canGroupMinus","checkGroupCanMinusCount","checkIsFixedSelectNeedSelectSku","checkIsUseSelectSkuBtn","getSkuComboItemGroup","groupMap","skuComboItem","combo_group_name","comboGroupName","reconstructComboGroupList","comboGroupList","newItems","findComboItem","child","_item$combo_sku$stock","_item$combo_sku","formatSelectSkuComboItemList","skuComboItems","combo_sku_type","selectItem","c","validateComboGroupList","_skuComboItemList$gro","skuComboCount","formatComboGroupItemSelectTips","repeatable","generateCartSkuComboItemList","handleSelectComboSkuSubmit","data","isComboChild","onComboChildChange","onComboSkuChange","setComboItemCountChange","handleComboItemCountChange","newComboGroupItem","handleComboGroupItemChildChange","comboGroupItem1","handleComboGroupItemSelected","handleComboGroupItemComboSkuChange","_comboItem$combo_sku$","_comboItem$combo_sku","isUseSelectCount","setToggleComboItemSelecte","toggleSelected","ComboSpecSelector","productData","channel1Type","_validateComboGroupList","_initProductData","_initSkuId","skuDetailData","_initCartItem$cart","_skuListAfter$skuInde","specType","_initSpecType","_initSkuListAfter","initCartItem","_findSkuCartItem","skuIndex","initSkuId","_initSkuDetail","_updateSkuData","isComponentLoading","_notifyChange","specValue","_selectSpec","_refreshCartItem","salePrice","getSalePrice","originalPrice","getOriginalPrice","memberPrice","getMemberPrice","maxCount","visibleComboInfo","isOption","_this$specList$","needFetchSkuDetail","matchedSku","isEqual","perOrderMinLimit","comboErrMsg","_validateCombo","countCheckResult","_checkProductCount","promotionActivityProductId","selectedSpecsIndex","isProductOnSale","status","has_stock","productStatusDesc","submitSkuComboItemList","channel1_type","checked","sku_id","sku_type","sku_combo_item_list","JSON","stringify","spec_type","_ref4","_skuListAfter$0$id","_skuListAfter$","_skuList$2","_ref3","_skuListAfter$skuInde2","_skuListAfter$skuInde3","_skuList$","_ref2","_skuList$0$id","_skuList$3","skuData","_this$cartItem","sku_combo_group_list","_skuCartItem$cart","stockCount","perOrderMaxLimit","minCount","skuCartItem","slice","_skuCartItem$cart2","CustomSpecSelector","_updateSkuCartItem","res","changed","emptyCartParams","buildCartCountParams","needFetchCart","cartParams","result","productCustomizationItemList","flattenCustomizationItemList","_getSkuType","_this$sku","targetSkuId","ChildCustomSelector","_options$exchangeRate","exchangeRate","_initCustomizationItemList","isScrollable","_formatSalePrice","_specList$","equal","countCheck","initCustomizationItemList","handleSelectSpecs","COUPON_TYPE_DISCOUNT","COUPON_TYPE_AMOUNT","COUPON_TYPE_FREIGHT","COUPON_THRESHOLD_TYPE_AMOUNT","COUPON_THRESHOLD_TYPE_COUNT","COUPON_EFFECTIVE_START_TYPE_NOW","COUPON_EFFECTIVE_START_TYPE_FUTURE","COUPON_EFFECTIVE_END_TYPE_FOREVER","COUPON_EFFECTIVE_END_TYPE_FUTURE","COUPON_EFFECTIVE_END_TYPE_EXTEND","COUPON_AVAILABLE_REPEAT_TYPE_DAILY","COUPON_AVAILABLE_REPEAT_TYPE_WEEKLY","COUPON_AVAILABLE_REPEAT_TYPE_MONTHLY","COUPON_STATUS_PENDING","COUPON_STATUS_ENABLED","COUPON_STATUS_USED","COUPON_STATUS_EXPIRED","COUPON_STATUS_CANCELED","COUPON_STATUS_LOCKED","COUPON_TEMPLATE_STATUS_DRAFT","COUPON_TEMPLATE_STATUS_ONLINE","COUPON_TEMPLATE_STATUS_OFFLINE","COUPON_TEMPLATE_STATUS_EXPIRED","COUPON_TEMPLATE_STATUS_UNAVAILABLE_ERROR","COUPON_STATUS_UNAVAILABLE_ERROR","COUPON_EXPAND_TYPE_EXTRA","COUPON_EXPAND_TYPE_REASON","COUPON_EXPAND_TYPE_NONE","COUPON_CONFIRM_EMPTY_MSG","COUPON_EXPIRE_MODE_DEADLINE","COUPON_EXPIRE_MODE_VALIDITY","WEEK_ORDER","WEEK_SHORT_LABEL_MAP","WORKDAYS","WEEKEND","isFullDayMinuteSegment","start","end","parseCouponNumberList","isArray","Number","isFinite","parsed","parse","split","isSameNumberSet","source","target","targetSet","Set","has","splitConsecutiveGroups","isConsecutivePair","prev","curr","groups","isConsecutiveWeekDayPair","prevIndex","currIndex","formatConsecutiveGroupParts","formatRange","formatSingle","parts","formatAvailableRepeatDateText","_options$repeatType","repeatType","_options$repeatValue","repeatValue","days","orderedDays","day","labels","formatWeeklyRepeatDateText","sortedDays","sort","a","b","formatMonthlyRepeatDateText","formatAvailableRepeatText","_options$repeatType2","_options$repeatValue2","_options$minuteSegmen","minuteSegments","dateText","timeText","formatMinuteSegments","formatUseLimitText","dailyNum","daily","weeklyNum","weekly","monthlyNum","monthly","isSameCouponId","String","hasCouponApiAvailableError","resolveCouponAvailable","coupon","availableError","resolveCouponAvailableError","formatCouponList","rawList","formatItem","next","original","isCouponDiscountBenefit","couponType","formatCouponAmountValue","couponValue","formatted","formatDiscount","endsWith","DISCOUNT_UNIT","stripAmountZero","formatCouponAmountPrefix","formatCouponAmountSuffix","formatCouponThreshold","thresholdType","thresholdValue","DAY_MS","formatExpireDate","timestamp","formatDateTime","formatCouponExpireText","effectiveEndType","expireDate","endTime","effectiveEndTime","effectiveEndDays","startType","effectiveStartType","startTime","effectiveStartTime","Date","now","resolveCouponExpireTimestamp","formatCouponValidityText","endType","startDate","endDate","resolveExpireMode","expireMode","formatCouponAvailableDateText","availableRepeatType","availableRepeatValue","formatCouponAvailableTimeText","segments","availableMinuteSegments","formatCouponUseLimitText","useLimitCountDaily","useLimitCountWeekly","useLimitCountMonthly","text","replace","formatCouponKvText","line","label","getCouponContentLines","lines","threshold","validityText","expireText","hasCouponAvailableRepeat","hasCouponUseLimit","parseCouponKvLine","match","getCouponExpandKvLines","expandType","getCouponExpandType","extraLines","getCouponGeneratedExtraLines","reason","hasExtraLines","hasGeneratedExtra","getCouponExpandLines","formatCouponViewItem","state","expanded","available","amountPrefix","amountValue","amountSuffix","contentLines","expandLines","toCouponViewItem","CouponSelector","exclusiveExpand","preferredSelectedId","_normalizeSelectedId","_dedupeList","selectedId","_pickValidSelectedId","_syncSelectedId","expandedIds","_findCoupon","selectedCoupon","_toViewItem","_setExpanded","_isExpanded","seen","add","_this$_normalizeSelec"],"mappings":"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"}
|