@pisell/pisellos
Version:
一个可扩展的前端模块化SDK框架,支持插件系统
1,414 lines (1,412 loc) • 115 kB
JavaScript
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) {
const cartItems = this.store.cart.getItems();
const newCartItems = (0, import_lodash_es.cloneDeep)(cartItems);
newCartItems.forEach((item) => {
var _a;
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 (!((_a = item._origin) == null ? void 0 : _a.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,
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;
(_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();
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.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) {
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 };
}
// 从购物车中获取已经分配好第一步资源的所有时间片
getTimeSlotByAllResources(resources_code) {
var _a, _b, _c, _d, _e, _f, _g, _h;
let dateRange = this.store.date.getDateRange();
const resources = [];
const cartItems = this.store.cart.getItems().filter((n) => !(0, import_utils5.isNormalProduct)(n._productOrigin));
const resourceIds = [];
let resourcesTypeId = void 0;
let isSingleResource = false;