@yorkjs/hive-biz 0.1.2 → 0.1.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/dist/hive-biz.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hive-biz.esm.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"],"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 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 // sku 变化后旧会员价失效,等待 UI 层重新请求回填\n this.memberPrice = undefined\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 (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 // sku 变化后旧会员价失效,等待 UI 层重新请求回填\n this.memberPrice = undefined\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\nimport { formatAmount } from '@yorkjs/hive'\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"],"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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hive-biz.esm.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"],"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"],"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"],"mappings":"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"}
|