UNPKG

@pisell/pisellos

Version:

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

1,411 lines (1,410 loc) 132 kB
var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/solution/BookingByStep/index.ts var BookingByStep_exports = {}; __export(BookingByStep_exports, { BookingByStepImpl: () => BookingByStepImpl }); module.exports = __toCommonJS(BookingByStep_exports); var import_BaseModule = require("../../modules/BaseModule"); var import_types = require("./types"); var import_utils = require("../../modules/Cart/utils"); var import_products = require("./utils/products"); var import_resources = require("./utils/resources"); var import_dayjs = __toESM(require("dayjs")); var import_isSameOrBefore = __toESM(require("dayjs/plugin/isSameOrBefore")); var import_isSameOrAfter = __toESM(require("dayjs/plugin/isSameOrAfter")); var import_utils2 = require("../../modules/Resource/utils"); var import_lodash_es = require("lodash-es"); var import_utils3 = require("../../modules/Schedule/utils"); var import_utils4 = require("../../modules/Date/utils"); var import_utils5 = require("../../modules/Product/utils"); var import_timeslots = require("./utils/timeslots"); var import_changePrice = require("../../modules/Cart/utils/changePrice"); var import_capacity = require("./utils/capacity"); var import_stock = require("./utils/stock"); import_dayjs.default.extend(import_isSameOrBefore.default); import_dayjs.default.extend(import_isSameOrAfter.default); var BookingByStepImpl = class extends import_BaseModule.BaseModule { constructor() { super(...arguments); this.defaultName = "bookingByStep"; this.defaultVersion = "1.0.0"; this.isSolution = true; this.otherParams = {}; this.otherData = {}; } // 平台类型,用于判断是 PC / H5 async initialize(core, options) { var _a, _b, _c, _d, _e; this.core = core; this.store = options.store || {}; this.otherParams = options.otherParams || {}; console.log("[BookingByStep] 初始化完成"); this.request = core.getPlugin("request"); this.window = core.getPlugin("window"); this.shopStore = core.getPlugin("shopStore"); if (!this.request) { throw new Error("bookingByStep解决方案需要 request 插件支持"); } if (!this.shopStore) { throw new Error("SummaryModule 需要 shopStore 插件支持"); } let targetCacheData = {}; this.cacheId = (_a = this.otherParams) == null ? void 0 : _a.cacheId; this.platform = (_b = this.otherParams) == null ? void 0 : _b.platform; if ((_c = this.otherParams) == null ? void 0 : _c.cacheId) { const sessionData = this.window.sessionStorage.getItem(this.name); if (sessionData) { const data = JSON.parse(sessionData); targetCacheData = data[this.otherParams.cacheId]; this.otherData = ((_e = (_d = data[this.otherParams.cacheId]) == null ? void 0 : _d[this.name]) == null ? void 0 : _e["otherData"]) || {}; } } const moduleArr = [ "accountList", "cart", "schedule", "summary", "step", "products", "date", "order" ]; moduleArr.forEach((step) => { var _a2, _b2; const targetModule = (0, import_types.createModule)(step, this.name); if (targetModule) { this.store[step] = targetModule; this.core.registerModule(targetModule, { initialState: targetCacheData == null ? void 0 : targetCacheData[targetModule.name], otherParams: { ...this.otherParams, fatherModule: this.name, openCache: ((_a2 = this.otherParams) == null ? void 0 : _a2.cacheId) ? true : false, cacheId: (_b2 = this.otherParams) == null ? void 0 : _b2.cacheId } }); } else { throw new Error(`模块 ${step} 不存在`); } }); this.store.schedule.loadAllSchedule(); this.core.effects.emit(`${this.name}:onInited`, {}); } // 初始化step initStep(stepList) { this.store.step.init(stepList); } getCurrentStep() { return { index: this.store.step.getCurrentStepIndex(), step: this.store.step.getCurrentStep() }; } // step: 下一个 next() { this.store.step.nextStep(); } // step: 上一个 back() { this.store.step.prevStep(); } // 跳转到指定步骤 gotoStep(index) { this.store.step.gotoStep(index); } // 获取所有step getStepList() { return this.store.step.getStepList(); } /** * 添加step */ addStep(step, key) { this.store.step.addStep(step, key); } /** * 删除step */ removeStep(key) { this.store.step.removeStep(key); } /** * 更新step */ updateStep(key, step) { this.store.step.updateStep(key, step); } /** * * 加载商品,然后导到商品列表里去 * @param {({ * category_ids?: number[]; * product_ids?: number[]; * collection?: number | string[]; * schedule_date?: string; * })} { * category_ids = [], * product_ids = [], * collection = [], * schedule_date, * } * @return {*} * @memberof BookingByStepImpl */ async loadProducts({ category_ids = [], product_ids = [], collection = [], schedule_date }) { const res = await this.store.products.loadProducts({ category_ids, product_ids, collection, schedule_date, cacheId: this.cacheId }); this.getAvailableDate({ startDate: schedule_date || (0, import_dayjs.default)().format("YYYY-MM-DD"), endDate: schedule_date || (0, import_dayjs.default)().format("YYYY-MM-DD"), products: [...res] }); return res; } /** * 通过 schedule 来读取商品,适用于 session 类商品 * * @param {{ * date: string; * product_ids?: number[]; * category_ids?: number[]; * }} { * date, * product_ids = [], * category_ids = [], * } * @return {*} * @memberof BookingByStepImpl */ async loadProductByScheduleDate({ date, product_ids = [], category_ids = [] }) { var _a; const scheduleList = this.store.schedule.getAvailabilityScheduleDateList(); this.setDateRange([ { date, status: "available", week: "", weekNum: 0 }, { date, status: "available", week: "", weekNum: 0 } ]); let newProductIds = []; const schedule = scheduleList.find((n) => n.date === date); if (schedule && ((_a = schedule.product_ids) == null ? void 0 : _a.length)) { newProductIds = schedule.product_ids; } const otherProductsIds = this.store.schedule.getOtherProductsIds() || []; const allProductIds = [...newProductIds, ...otherProductsIds].filter( (n, index, self) => self.indexOf(n) === index ); const res = await this.loadProducts({ product_ids: allProductIds, category_ids, schedule_date: date }); return res; } /** * 更新完商品数据、切换日期、或者在较后的流程里登录了,检测当前购物车里是否有商品,如果有,则需要更新购物车里的商品价格 * * @param {string} date * @memberof BookingByStepImpl */ async updateQuotationPriceAndCart(date) { var _a; const cartItems = this.store.cart.getItems(); if (cartItems.length) { let userPlugin = this.core.getPlugin("user"); let customer_id = void 0; try { customer_id = (_a = userPlugin == null ? void 0 : userPlugin.get()) == null ? void 0 : _a.id; } catch (error) { console.error(error); } const res = await this.store.products.loadProductsPrice({ ids: cartItems.map((n) => n.id), schedule_date: date, customer_id }); await (0, import_changePrice.updateAllCartItemPrice)( cartItems, res, (id) => this.store.products.getProduct(id), (params) => this.store.cart.updateItem(params), (params) => this.store.cart.updateItemInitInfo(params) ); this.core.effects.emit( `${this.store.cart.name}:onUpdateQuotationPrice`, {} ); } } /** * ui 层提供日期的起始范围,返回一个起始范围内日期的可用情况 * 适用于先选日期的流程,确定日期是否可用 * 已知问题:如果挂接的商品的资源不可用,后端是不会计算的 * * @param {LoadScheduleAvailableDateParams} { * startDate, * endDate, * custom_page_id, * channel, * } * @memberof BookingByStepImpl */ async loadScheduleAvailableDate({ startDate, endDate, custom_page_id, channel }) { return await this.store.schedule.loadScheduleAvailableDate({ startDate, endDate, custom_page_id, channel }); } // 添加单个账户或者 guest async addAccount(account, extra) { if ((extra == null ? void 0 : extra.type) === "holder") { const accountModules = await this.store.accountList.addHolderAccounts({ holders: [account], customerId: extra.customerId, type: "unshift" }); return accountModules[0].getAccount(); } const newAccount = await this.store.accountList.addAccount( account ); return newAccount.getAccount(); } // 添加账户或者 guest async addAccounts(accounts, extra) { if ((extra == null ? void 0 : extra.type) === "holder") { this.store.accountList.addHolderAccounts({ holders: accounts, customerId: extra.customerId, type: "unshift" }); return; } const res = []; for (const account of accounts) { const accountModule = await this.store.accountList.addAccount( account ); const accountData = accountModule.getAccount(); if (accountData) { res.push(accountData); } } return res; } // 获取所有账户 async getAccounts() { const accounts = this.store.accountList.getAccounts(); return accounts.map((account) => account.getAccount()); } checkHasLoginAccount() { const accounts = this.store.accountList.getAccounts(); return accounts.some((account) => account.getLoginStatus()); } setActiveAccount(id) { this.store.accountList.setActiveAccount(id); } getActiveAccount() { const activeAccount = this.store.accountList.getActiveAccount(); const account = activeAccount == null ? void 0 : activeAccount.getAccount(); return account === null ? void 0 : account; } removeAccount(id) { this.store.accountList.removeAccount(id); this.clearCartByAccount(id); } /** * 获取holder类型账户列表 * @param params */ async fetchHolderAccountsAsync(params) { var _a, _b; const cartItems = this.store.cart.getItems(); if (cartItems.length) { let date = (_b = (_a = this.store.date.getDateRange()) == null ? void 0 : _a[0]) == null ? void 0 : _b.date; if (!date) { const normalProductCartItem = cartItems.find( (n) => !(0, import_utils5.isNormalProduct)(n._productOrigin) ); date = (normalProductCartItem == null ? void 0 : normalProductCartItem.start_date) || ""; } this.updateQuotationPriceAndCart(date); } return this.store.accountList.fetchHolderAccounts(params); } // 设置日期范围,注入到日期模块中 async setDateRange(dateRange) { this.store.date.setDateRange(dateRange); if (dateRange.length && this.store.cart.getItems().length) { this.updateQuotationPriceAndCart(dateRange[0].date); } } clearDateRange() { this.store.date.clearDateRange(); } // 获取日期模块里选中的日期 async getDateRange() { return this.store.date.getDateRange(); } getCart() { return this.store.cart.getItems(); } // 获取商品/服务的可用日期 async getAvailableDate(params = {}) { var _a, _b, _c, _d; let { products, startDate, endDate, type, useCache = true } = params; if ((0, import_dayjs.default)(startDate).isBefore((0, import_dayjs.default)(), "day") && ((0, import_dayjs.default)(endDate).isAfter((0, import_dayjs.default)(), "day") || (0, import_dayjs.default)(endDate).isSame((0, import_dayjs.default)(), "day"))) { startDate = (0, import_dayjs.default)().format("YYYY-MM-DD"); } let tempProducts = products || this.store.cart.getItems().map((p) => p._productOrigin); if (tempProducts.length) { tempProducts.forEach((p) => { if (p == null ? void 0 : p["schedule.ids"]) { const scheduleData = this.getScheduleDataByIds(p["schedule.ids"]); p["_schedule"] = scheduleData; } }); } if (this.store.currentProduct) { tempProducts = [ { ...this.store.currentProduct, _schedule: (_a = this.store.currentProductMeta) == null ? void 0 : _a["schedule"] } ]; } let dateRange = this.store.date.getDateRange(); const tempStartDate = startDate || ((_b = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _b.date); const tempEndDate = endDate || ((_c = dateRange == null ? void 0 : dateRange[1]) == null ? void 0 : _c.date) || ((_d = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _d.date); if (!tempProducts.length) { return []; } const { resourceIds, rules, resourcesMap } = (0, import_products.getAvailableProductResources)(tempProducts) || {}; this.otherParams.currentResourcesMap = resourcesMap; const res = await this.store.date.getResourceDates({ url: params.url, query: { start_date: tempStartDate, end_date: tempEndDate, resource_ids: resourceIds }, rules, type, useCache }); return res; } /** * 获取购物车汇总信息 */ async getSummary() { const cartItems = this.store.cart.getItems(); const summary = await this.store.summary.getSummary(cartItems); return summary; } /** * 获取协议 */ async getProtocol(protocolId) { return this.store.summary.getProtocol(protocolId); } // 获取可选择的商品、服务列表 async getProducts() { return this.store.products.getProducts(); } // 如果用户登录 async setLoginAccount(accountId, accountInfo) { var _a, _b; const account = this.store.accountList.getAccount(accountId); if (account) { let stateAccountId = account.getId(); accountInfo.isLogin = true; account.setAccountInfo(accountInfo); const cartItems = this.store.cart.getItems(); cartItems.forEach((item) => { if (item.holder_id === accountId) { this.store.cart.updateItem({ _id: item._id, account: accountInfo }); } }); this.store.accountList.updateAccountListById(stateAccountId, accountInfo); if (cartItems.length) { let date = (_b = (_a = this.store.date.getDateRange()) == null ? void 0 : _a[0]) == null ? void 0 : _b.date; if (!date) { const normalProductCartItem = cartItems.find( (n) => !(0, import_utils5.isNormalProduct)(n._productOrigin) ); date = (normalProductCartItem == null ? void 0 : normalProductCartItem.start_date) || ""; } this.updateQuotationPriceAndCart(date); } } else { throw new Error(`没有找到${accountId}账户`); } } // 生成购物车的正规数据 async generateCartData() { } // 免费领取商品相关逻辑,上线了来不及加了,先放在这,后面要做到 payment 里面的 async getFreeProduct(id) { const res = await this.request.post(`/pay/order/free-pay/${id}`); return res; } /** * 检查购物车提交订单前是否符合条件 * @param type 类型 "holder" | "account" * @returns boolean */ checkBeforeSubmitOrder(type) { return this.store.order.checkBeforeSubmitOrder({ type, cartItems: this.store.cart.getItems() }); } // 购物车提交订单 async submitOrder(extraData) { var _a; const cartItems = this.store.cart.getItems(); const newCartItems = (0, import_lodash_es.cloneDeep)(cartItems); newCartItems.forEach((item) => { var _a2; if (item._origin.resources && item._origin.resources.length) { item._origin.resources = item._origin.resources.map((n) => { const newResourcesItem = (0, import_lodash_es.cloneDeep)(n); delete newResourcesItem.id; delete newResourcesItem.main_field; delete newResourcesItem.resourceType; return { ...newResourcesItem }; }); const { currentCapacity, formatCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item); if (!((_a2 = item._origin) == null ? void 0 : _a2.metadata)) { item._origin.metadata = {}; } item._origin.metadata.capacity = formatCapacity; item._origin.number = currentCapacity; } }); let type = this.otherParams.isRetailTemplate ? "virtual" : "appointment_booking"; if ((0, import_utils5.areAllNormalProducts)( newCartItems.map((n) => n._productOrigin) )) { type = "virtual"; } return this.store.order.submitOrder({ query: { cartItems: newCartItems, type, platform: this.platform, business_code: (_a = this.otherParams) == null ? void 0 : _a.business_code, extraData } }); } // 拉起支付模块 async pay() { } // 获取支付信息 async getPayInfo() { } async setOtherParams(params, { cover = false } = {}) { if (cover) { this.otherParams = params; } else { this.otherParams = { ...this.otherParams, ...params }; } } async getOtherParams() { return this.otherParams; } /** * 往购物车加商品数据(duration 类、普通商品) * 老接口,先不删,怕 UI 有问题,直接桥接到新接口addProductToCart上 * * @param {ProductData} productData * @memberof BookingByStepImpl */ storeProduct(productData) { const activeAccount = this.getActiveAccount(); return this.addProductToCart({ product: productData, account: activeAccount }); } /** * 往购物车加商品数据 * * @param {({ * product: ProductData; * date?: { startTime: string; endTime: string } | null; * account?: Account | null; * })} { * product, * date, * account, * } * @return {*} * @memberof BookingByStepImpl */ addProductToCart({ product, date, account }) { const { bundle, options, origin, product_variant_id, rowKey, quantity = 1 } = product || {}; const productData = { ...origin, product_variant_id }; if ((0, import_products.isSessionProduct)(productData)) { if (!date || !date.startTime || !date.endTime) { return { success: false, errorCode: "date_or_time_required" }; } } const currentCartItems = this.store.cart.getItems(); const stockCheckResult = (0, import_stock.checkProductStock)({ productData, product_variant_id, quantity, bundle, currentCartItems }); if (!stockCheckResult.success) { return stockCheckResult; } if (!account) { const activeAccount = this.getActiveAccount(); if (activeAccount) { account = activeAccount; } } const flag = this.store.cart.mergeCartItemByRowKey({ rowKey, quantity, account: account || void 0 }); if (flag) { return { success: true }; } const addItemParams = { product: productData, bundle, options, quantity }; if (date) { addItemParams.date = date; } if (account) { addItemParams.account = account; } this.addProductCheck({ date }); if (addItemParams.quantity > 1 && !(0, import_utils5.isNormalProduct)(productData)) { for (let i = 0; i < addItemParams.quantity; i++) { const newAddItemParams = (0, import_lodash_es.cloneDeep)(addItemParams); newAddItemParams.quantity = 1; this.store.cart.addItem(newAddItemParams); } } else { this.store.cart.addItem(addItemParams); } return { success: true }; } /** * 添加完购物车以后做的一些检测,比如日期是否在同一天 * * @param {({ date?: { startTime: string; endTime: string } | null })} { date } * @memberof BookingByStepImpl */ addProductCheck({ date }) { if (date) { const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin)); const cartItemsByDate = cartItems.filter( (n) => !(0, import_dayjs.default)(n.start_date).isSame((0, import_dayjs.default)(date.startTime), "day") ); if (cartItemsByDate.length) { cartItemsByDate.forEach((n) => { this.store.cart.removeItem(n._id); }); } } } beforeUpdateCart(params, targetCartItem) { if (params.resources) { const { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(targetCartItem); params.resources = params.resources.map((n) => { n.capacity = currentCapacity || 1; (0, import_capacity.checkSubResourcesCapacity)(n); return n; }); } } // 更新购物车 updateCart(params) { const targetCartItem = this.store.cart.getItem(params._id); if (!targetCartItem) { throw new Error(`没有找到${params._id}购物车商品`); } this.beforeUpdateCart(params, targetCartItem); this.store.cart.updateItem(params); this.updateCartCheck(params, targetCartItem); } /** * 更新购物车以后的一些操作,比如检测资源是否重复,检测资源容量是否足够 * * @param {IUpdateItemParams} params * @param {CartItem} targetCartItem * @return {*} * @memberof BookingByStepImpl */ updateCartCheck(params, targetCartItem) { var _a; if (this.otherParams.isRetailTemplate) { return; } let currentResourcesCapacityMap = {}; (_a = params.resources) == null ? void 0 : _a.forEach((n) => { currentResourcesCapacityMap[n.id] = n.capacity; }); const allOriginResources = []; const dateRange = this.store.date.getDateRange(); if (dateRange == null ? void 0 : dateRange.length) { dateRange.forEach((n) => { if (n.resource) allOriginResources.push(...n.resource); }); } if (!allOriginResources.length) { const dateList = this.store.date.getDateList(); dateList == null ? void 0 : dateList.forEach((n) => { if (n.resource) allOriginResources.push(...n.resource); }); } if (params.resources) { const cartItems = this.store.cart.getItems(); cartItems.forEach((item) => { var _a2; if (item._id !== targetCartItem._id) { const { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item); const resources = (_a2 = item._origin.resources) == null ? void 0 : _a2.filter((m) => { const sameFormIdResources = (0, import_resources.filterResourcesByFormItem)( targetCartItem._origin.resources, m.form_id ); if (!(sameFormIdResources == null ? void 0 : sameFormIdResources.length)) { return true; } return !sameFormIdResources.some((targetRes) => { if (targetRes.resourceType !== "single") { const originResource = allOriginResources.find( (n) => n.id === targetRes.id ); const canUse = (0, import_capacity.checkResourceCanUseByCapacity)( currentResourcesCapacityMap[m.id] || 0, currentCapacity, originResource == null ? void 0 : originResource.capacity ); if (canUse) currentResourcesCapacityMap[m.id] += currentCapacity; return !canUse; } if (item.holder_id !== (targetCartItem == null ? void 0 : targetCartItem.holder_id)) { return (0, import_resources.checkTwoResourcesIntersection)(targetRes, m); } return false; }); }); if (item.start_time) { const start_time = item.start_time; const end_time = item.end_time; const start_date = item.start_date; const end_date = item.end_date; this.store.cart.updateItem({ _id: item._id, resources, date: { startTime: (0, import_dayjs.default)(`${start_date} ${start_time}`).format( "YYYY-MM-DD HH:mm" ), endTime: (0, import_dayjs.default)(`${end_date} ${end_time}`).format( "YYYY-MM-DD HH:mm" ) } }); } else { this.store.cart.updateItem({ _id: item._id, resources }); } } }); } } // 删除购物车里某个商品 deleteCart(cartItemId) { this.store.cart.removeItem(cartItemId); } // 清空购物车 clearCart() { this.store.cart.clear(); } // 基于账户清空购物车 clearCartByAccount(account_id) { this.store.cart.clearCartByAccount(account_id); } /** * 批量更新购物车 */ batchUpdateCart(paramsList) { const cartItems = []; paramsList.forEach((params) => { const cartItem = this.store.cart.formatCartItem(params); cartItems.push(cartItem); }); this.store.cart.batchSetItems(cartItems); } /** * 从购物车中按类别删除信息 */ deleteCartItemInfo(type, _id) { this.store.cart.deleteCartItemInfo(type, _id); } checkCartItemByType(cartItem, type) { return this.store.cart.checkCartItemByType(cartItem, type); } /** * 检查购物车商品是否符合条件 * @param type 类型 * @returns 不符合条件的购物车商品ID列表 */ checkCartItems(type) { const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin)); const errorCartItemIds = []; cartItems.forEach((cartItem) => { const result = this.store.cart.checkCartItemByType(cartItem, type); if (!result) { errorCartItemIds.push(cartItem._id); } }); return errorCartItemIds; } destroy() { var _a, _b, _c, _d, _e, _f, _g, _h, _i; (_a = this.store.cart) == null ? void 0 : _a.destroy(); (_b = this.store.step) == null ? void 0 : _b.destroy(); (_c = this.store.products) == null ? void 0 : _c.destroy(); (_d = this.store.guests) == null ? void 0 : _d.destroy(); (_e = this.store.date) == null ? void 0 : _e.destroy(); (_f = this.store.accountList) == null ? void 0 : _f.destroy(); (_g = this.store.schedule) == null ? void 0 : _g.destroy(); (_h = this.store.summary) == null ? void 0 : _h.destroy(); (_i = this.store.order) == null ? void 0 : _i.destroy(); this.core.effects.offByModuleDestroy(this.name); this.core.unregisterModule(this); } // 获取当前购物车内所有关联的资源列表,拼装数据格式 getResourcesList() { const dateRange = this.store.date.getDateRange(); const resources = []; if (dateRange == null ? void 0 : dateRange.length) { dateRange.forEach((n) => { if (n.resource) resources.push(...n.resource); }); } const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin)); if (!resources.length) { const firstDateCartItem = cartItems == null ? void 0 : cartItems.find((n) => n.start_date); if (firstDateCartItem == null ? void 0 : firstDateCartItem.start_date) { const dateResources = this.store.date.getResourcesListByDate( firstDateCartItem.start_date ); resources.push(...dateResources || []); } else { const dateList = this.store.date.getDateList(); dateList == null ? void 0 : dateList.forEach((n) => { if (n.resource) resources.push(...n.resource); }); } } const resourcesMap = (0, import_utils2.getResourcesMap)((0, import_lodash_es.cloneDeep)(resources)); const arr = []; cartItems.forEach((cartItem) => { var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l; let selectedResources = []; const { currentCapacity, formatCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(cartItem); cartItem._origin.metadata.capacity = formatCapacity; if (cartItem.holder_id) { selectedResources = (0, import_resources.getOthersSelectedResources)( cartItems, cartItem.holder_id, resourcesMap ); } else { selectedResources = (0, import_resources.getOthersCartSelectedResources)( cartItems, cartItem._id, resourcesMap ); } const productResources = (0, import_resources.getResourcesByProduct)( resourcesMap, ((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [], selectedResources, currentCapacity ); if (cartItem._origin.start_time) { const startTime = (0, import_dayjs.default)( `${cartItem._origin.start_date} ${cartItem._origin.start_time}` ); const endTime = (0, import_dayjs.default)( `${cartItem._origin.end_date} ${cartItem._origin.end_time}` ); const resourcesUseableMap = {}; productResources.forEach((n) => { n.renderList = (0, import_resources.sortCombinedResources)(n.renderList); n.renderList = n.renderList.filter((m) => { const mTimes = (0, import_timeslots.filterConditionTimeSlots)( m.times, startTime, endTime ); if (mTimes.length === 0) { return false; } const canUseArr = mTimes.map((item) => { var _a2; const res = (0, import_resources.getIsUsableByTimeItem)({ timeSlice: { start_time: startTime.format("HH:mm"), end_time: endTime.format("HH:mm"), start_at: startTime, end_at: endTime }, time: item, resource: m, currentCount: currentCapacity || 0, resourcesUseableMap, cut_off_time: (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.cut_off_time }); if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[m.id]) !== false && res.reason !== "capacityOnly") { resourcesUseableMap[m.id] = res.usable; } return res.usable; }); if (m.onlyComputed) return false; return !canUseArr.some((n2) => n2 === false); }); }); } else { const hasFlexibleDuration = ((_d = (_c = cartItem._productOrigin) == null ? void 0 : _c.duration) == null ? void 0 : _d.type) === "flexible"; const operating_day_boundary = (_f = (_e = this.shopStore.get("core")) == null ? void 0 : _e.core) == null ? void 0 : _f.operating_day_boundary; const maxBlockThreshold = ((_i = (_h = (_g = cartItem._productOrigin) == null ? void 0 : _g.duration) == null ? void 0 : _h.flexible_config) == null ? void 0 : _i.is_enable_minimum_duration) ? ((_l = (_k = (_j = cartItem._productOrigin) == null ? void 0 : _j.duration) == null ? void 0 : _k.flexible_config) == null ? void 0 : _l.block_threshold) || 0 : 0; productResources.forEach((item) => { item.renderList = item.renderList.filter((n) => { var _a2, _b2, _c2; const recordCount = n.capacity || 0; if (n.onlyComputed) return false; const timeSlots = (0, import_resources.getTimeSlicesByResource)({ resource: n, duration: ((_b2 = (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10, split: 10, currentDate: dateRange[0].date, hasFlexibleDuration, cut_off_time: (_c2 = cartItem._productOrigin) == null ? void 0 : _c2.cut_off_time, operating_day_boundary, maxBlockThreshold }); return recordCount >= currentCapacity && timeSlots.length > 0; }); }); } arr.push({ id: cartItem.id, // 这里返回的是购物车 id ,后面提交的时候要用的,用这个 id 绑定资源和时间 _id: cartItem._id, // 这里返回的是购物车 id ,后面提交的时候要用的,用这个 id 绑定资源和时间 product: cartItem._productOrigin, resources: productResources, holder_id: cartItem.holder_id, holder_name: cartItem.holder_title }); }); return arr; } /** * 在日期那边点击下一步的时候,检查这一天购物车里的商品是不是都有资源可以用 * * @return {*} * @memberof BookingByStepImpl */ checkResourceListForDate() { const resourcesList = this.getResourcesList(); const hasResource = resourcesList.every( (item) => item.resources.every((resource) => resource.renderList.length > 0) ); return hasResource; } /** * 给单个购物车里的商品获取资源列表,给 UI 用的 * * @param {(string | number)} id * @return {*} * @memberof BookingByStepImpl */ getResourcesListByCartItem(id) { var _a, _b; const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin)); const dateRange = this.store.date.getDateRange(); const resources = []; dateRange.forEach((n) => { if (n.resource) resources.push(...n.resource); }); const resourcesMap = (0, import_utils2.getResourcesMap)(resources); const targetCartItem = cartItems.find((n) => n._id === id); if (!targetCartItem) { throw new Error(`没有找到${id}购物车商品`); } let selectedResources = []; const { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(targetCartItem); if (targetCartItem.holder_id) { selectedResources = (0, import_resources.getOthersSelectedResources)( cartItems, targetCartItem.holder_id, resourcesMap ); } else { selectedResources = (0, import_resources.getOthersCartSelectedResources)( cartItems, targetCartItem._id, resourcesMap ); } const productResources = (0, import_resources.getResourcesByProduct)( resourcesMap, ((_b = (_a = targetCartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [], selectedResources, currentCapacity ); productResources.forEach((item) => { item.renderList = item.renderList.filter((n) => { const recordCount = n.capacity || 0; if (n.onlyComputed) return false; return recordCount >= currentCapacity; }); }); if (productResources) { return { id: targetCartItem.id, // 这里返回的是购物车 id ,后面提交的时候要用的,用这个 id 绑定资源和时间 _id: targetCartItem._id, // 这里返回的是购物车 id ,后面提交的时候要用的,用这个 id 绑定资源和时间 product: targetCartItem._productOrigin, resources: productResources, holder_id: targetCartItem.holder_id, holder_name: targetCartItem.holder_title }; } } // 自动分派可用资源-pro 版,ui 传递某个账号,自动给某个账号下所有商品分配第一种资源 autoSelectAccountResources({ cartItem, holder_id, resources_code, timeSlots, countMap, capacity }) { var _a, _b, _c; if ((0, import_utils5.isNormalProduct)(cartItem._productOrigin)) { return {}; } const dateRange = this.store.date.getDateRange(); const cartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems()); let accountCartItems = cartItems.filter((n) => n.holder_id === holder_id) || []; if (!accountCartItems.length) { accountCartItems = cartItems; } let duration = accountCartItems.reduce((acc, n) => { var _a2, _b2; return acc + (((_b2 = (_a2 = n._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b2.value) || 10); }, 0); let AllResources = []; if (dateRange == null ? void 0 : dateRange.length) { dateRange.forEach((n) => { if (n.resource) AllResources.push(...n.resource); }); } if (!AllResources.length) { const firstDateCartItem = cartItems == null ? void 0 : cartItems.find((n) => n.start_date); if (firstDateCartItem == null ? void 0 : firstDateCartItem.start_date) { const dateResources = this.store.date.getResourcesListByDate( firstDateCartItem.start_date ); AllResources.push(...dateResources || []); } else { const dateList = this.store.date.getDateList(); dateList.forEach((n) => { if (n.resource) AllResources.push(...n.resource); }); } } const resourcesMap = (0, import_utils2.getResourcesMap)((0, import_lodash_es.cloneDeep)(AllResources)); const allCartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems()); const selectedResources = (0, import_resources.getOthersSelectedResources)( allCartItems, holder_id, resourcesMap ); let allProductResources = (0, import_resources.getResourcesByProduct)( resourcesMap, ((_b = (_a = cartItem._productOrigin) == null ? void 0 : _a.product_resource) == null ? void 0 : _b.resources) || [], selectedResources, 1 ); const resources = ((_c = allProductResources.find((n) => n.code === resources_code)) == null ? void 0 : _c.renderList) || []; resources.sort((a, b) => { var _a2, _b2, _c2, _d; const aIsCombined = ((_b2 = (_a2 = a.metadata) == null ? void 0 : _a2.combined_resource) == null ? void 0 : _b2.status) === 1; const bIsCombined = ((_d = (_c2 = b.metadata) == null ? void 0 : _c2.combined_resource) == null ? void 0 : _d.status) === 1; if (aIsCombined && !bIsCombined) return 1; if (!aIsCombined && bIsCombined) return -1; return 0; }); const resourcesUseableMap = [ ...selectedResources ].reduce((acc, n) => { var _a2; acc[n] = ((_a2 = resourcesMap[n]) == null ? void 0 : _a2.resourceType) === "single" ? false : true; return acc; }, {}); if (timeSlots) { let targetResource = null; let targetResourceTime = 0; for (const n of resources) { const mTimes = n.times.filter((n2) => { return !(0, import_dayjs.default)(n2.start_at).isAfter((0, import_dayjs.default)(timeSlots.start_at)) && !(0, import_dayjs.default)(n2.end_at).isBefore((0, import_dayjs.default)(timeSlots.end_at)); }); if (mTimes.length === 0) { continue; } const totalCapacity = (countMap[n.id] || []).reduce( (sum, item) => { const hasOverlap = !(0, import_dayjs.default)(item.time.start_at).isAfter((0, import_dayjs.default)(timeSlots.start_at)) && !(0, import_dayjs.default)(item.time.end_at).isBefore((0, import_dayjs.default)(timeSlots.end_at)); return hasOverlap ? sum + item.pax : sum; }, 0 ); if (n.resourceType === "single" && totalCapacity > 0) { continue; } const canUseTime = mTimes.find((item) => { var _a2; const res = (0, import_resources.getIsUsableByTimeItem)({ timeSlice: timeSlots, time: item, resource: n, currentCount: totalCapacity + (capacity || 0), resourcesUseableMap, cut_off_time: (_a2 = cartItem._productOrigin) == null ? void 0 : _a2.cut_off_time }); if ((resourcesUseableMap == null ? void 0 : resourcesUseableMap[n.id]) !== false && res.reason !== "capacityOnly") { resourcesUseableMap[n.id] = res.usable; } return res.usable; }); const currentResourceIdleTime = (0, import_timeslots.calculateResourceAvailableTime)({ resource: n, timeSlots, currentCapacity: totalCapacity + (capacity || 0) }); if (canUseTime && !n.onlyComputed && currentResourceIdleTime > targetResourceTime && n.capacity >= (capacity || 0)) { targetResource = n; targetResourceTime = currentResourceIdleTime; break; } } return { selectedResource: targetResource }; } else { const resourcesMap2 = (0, import_utils2.getResourcesMap)(resources); const resourceIds = resources.map((n) => n.id); const timeSlots2 = (0, import_resources.getTimeSlicesByResources)({ resourceIds, resourcesMap: resourcesMap2, duration, currentDate: dateRange[0].date, split: 10, capacity, resourcesUseableMap }); if (!timeSlots2) { return; } return { timeSlots: timeSlots2, selectedResource: resources[0] }; } } // 给所有购物车里的商品先分配一个资源 autoSelectAllProductResources(resources_code, timeSlots) { var _a; const dateRange = this.store.date.getDateRange(); const resources = []; if ((_a = dateRange == null ? void 0 : dateRange[0]) == null ? void 0 : _a.date) { dateRange.forEach((n) => { if (n.resource) resources.push(...n.resource); }); } const errorList = []; const selectResourcesMap = {}; const selectResourcesWithTimeSlots = {}; const accountList = this.store.accountList.getAccounts(); const selectForCartResources = (cartItems2) => { let recordTimeSlots = (0, import_lodash_es.cloneDeep)(timeSlots); const hasFlexibleProduct = cartItems2.some( (item) => { var _a2, _b; return ((_b = (_a2 = item._productOrigin) == null ? void 0 : _a2.duration) == null ? void 0 : _b.type) === "flexible"; } ); cartItems2.forEach((item, index) => { var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l; const { currentCapacity } = (0, import_capacity.getCapacityInfoByCartItem)(item); if (item._origin.start_time && !(timeSlots == null ? void 0 : timeSlots.start_time)) { recordTimeSlots = { start_time: item._origin.start_time, end_time: item._origin.end_time, start_at: (0, import_dayjs.default)(`${item.start_date} ${item._origin.start_time}`), end_at: (0, import_dayjs.default)(`${item.end_date} ${item._origin.end_time}`) }; } if (recordTimeSlots) { const currentResourceConfig = (_c = (_b = (_a2 = item._productOrigin) == null ? void 0 : _a2.product_resource) == null ? void 0 : _b.resources) == null ? void 0 : _c.find( (n) => n.code === resources_code ); if (index !== 0 && recordTimeSlots && (currentResourceConfig == null ? void 0 : currentResourceConfig.type) === "single" && ((_d = item._productOrigin) == null ? void 0 : _d.duration) && !hasFlexibleProduct) { let start_at = (0, import_dayjs.default)(recordTimeSlots.end_time).add( ((_f = (_e = item._productOrigin) == null ? void 0 : _e.duration) == null ? void 0 : _f.value) || 10, "minutes" ); let end_at = start_at.add( ((_h = (_g = item._productOrigin) == null ? void 0 : _g.duration) == null ? void 0 : _h.value) || 10, "minutes" ); recordTimeSlots = { start_time: start_at.format("HH:mm"), end_time: end_at.format("HH:mm"), start_at, end_at }; } const res = this.autoSelectAccountResources({ cartItem: item, holder_id: item.holder_id, resources_code, timeSlots: recordTimeSlots, countMap: selectResourcesWithTimeSlots, capacity: currentCapacity }); if (res == null ? void 0 : res.selectedResource) { if (!selectResourcesWithTimeSlots[res.selectedResource.id]) { selectResourcesWithTimeSlots[res.selectedResource.id] = [ { pax: currentCapacity, time: recordTimeSlots } ]; } else { selectResourcesWithTimeSlots[res.selectedResource.id].push({ pax: currentCapacity, time: recordTimeSlots }); } res.selectedResource.capacity = currentCapacity; (0, import_capacity.checkSubResourcesCapacity)(res.selectedResource); this.store.cart.updateItem({ _id: item._id, // 这里要做去重,避免出现同样类型的资源被塞进同一个商品 resources: [ ...(item._origin.resources || []).filter( (existingRes) => { var _a3; return existingRes.form_id !== ((_a3 = res.selectedResource) == null ? void 0 : _a3.form_id); } ), res.selectedResource ] }); } else { errorList.push(item._id); } } else { const allCartItems = (0, import_lodash_es.cloneDeep)(this.store.cart.getItems()); let selectedResources = []; const resources2 = (0, import_lodash_es.cloneDeep)( ((_j = (_i = item._productOrigin) == null ? void 0 : _i.product_resource) == null ? void 0 : _j.resources) || [] ); const currentResourcesRenderList = []; resources2.forEach((n) => { var _a3; if ((_a3 = n.renderList) == null ? void 0 : _a3.length) { n.renderList = n.renderList.filter((m) => { var _a4; const recordCount = (m.capacity || 0) - (selectResourcesMap[m.id] || 0); const timeSlots2 = (0, import_resources.getTimeSlicesByResource)({ resource: m, duration: ((_a4 = item == null ? void 0 : item.duration) == null ? void 0 : _a4.value) || 10, split: 10, currentDate: dateRange[0].date }); return recordCount >= currentCapacity && timeSlots2.length > 0; }); currentResourcesRenderList.push(...n.renderList || []); } }); const resourcesMap = (0, import_utils2.getResourcesMap)(currentResourcesRenderList); if (item.holder_id) { selectedResources = (0, import_resources.getOthersSelectedResources)( allCartItems, item.holder_id, resourcesMap ); } else { selectedResources = (0, import_resources.getOthersCartSelectedResources)( allCartItems, item._id, resourcesMap ); } const productResources = (0, import_resources.getResourcesByProduct)( resourcesMap, (0, import_lodash_es.cloneDeep)(resources2), selectedResources, currentCapacity ); productResources.forEach((item2) => { item2.renderList = item2.renderList.filter((n) => { const recordCount = (n.capacity || 0) - (selectResourcesMap[n.id] || 0); if (n.onlyComputed) return false; return recordCount >= currentCapacity; }); }); const targetRenderList = (_k = productResources.find( (n) => n.code === resources_code )) == null ? void 0 : _k.renderList; if (targetRenderList && targetRenderList.length > 0) { if ((_l = item._origin.resources) == null ? void 0 : _l.some( (n) => n.form_id === targetRenderList[0].form_id )) { return; } const fastestResource = (0, import_timeslots.findFastestAvailableResource)({ resources: targetRenderList, currentCapacity, countMap: selectResourcesMap }); const targetResource = fastestResource || targetRenderList[0]; targetResource.capacity = currentCapacity; (0, import_capacity.checkSubResourcesCapacity)(targetResource); if (!selectResourcesMap[targetResource.id]) { selectResourcesMap[targetResource.id] = currentCapacity; } else { selectResourcesMap[targetResource.id] += currentCapacity; } this.store.cart.updateItem({ _id: item._id, resources: [ ...(item._origin.resources || []).filter( (existingRes) => existingRes.resourceType !== targetRenderList[0].resourceType ), targetResource ] }); } else { errorList.push(item._id); } } }); }; const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin)); if (cartItems == null ? void 0 : cartItems[0].holder_id) { accountList.forEach((account) => { const cartItems2 = this.store.cart.getCartByAccount(account.getId()); selectForCartResources(cartItems2); }); } else { selectForCartResources(cartItems); } return { errorList }; } // 从购物车中获取已经分配好第一步资源的所有时间片 getTimeSlotByAllRe