@pisell/private-materials 6.12.160 → 6.12.161
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/build/lowcode/assets-daily.json +11 -11
- package/build/lowcode/assets-dev.json +2 -2
- package/build/lowcode/assets-prod.json +11 -11
- package/build/lowcode/meta.js +1 -1
- package/build/lowcode/preview.js +1 -1
- package/build/lowcode/render/default/view.js +18 -18
- package/build/lowcode/view.js +18 -18
- package/es/components/bigSale/components/BookingFloatingPanel/useBookingPanelController.js +1 -0
- package/es/components/bigSale/components/TimeBar/index.js +1 -0
- package/es/components/bigSale/dialog.js +1 -0
- package/es/components/bigSale/hooks/useBigSaleContext.js +1 -0
- package/es/components/bigSale/hooks/useSelectFloorMapResourceForBigSale.js +1 -0
- package/es/components/bigSale/index.js +3 -2
- package/es/components/bigSale/templates/Kiosk/index.js +1 -0
- package/es/components/sharedSecondaryBigSale/SharedSecondaryBigSaleReceiver.js +1 -0
- package/es/index.js +2 -0
- package/es/plus/pisellReservation/data/bookingToReservationTables.js +1 -1
- package/es/plus/pisellReservation/floorMap/floorPlanApi.js +1 -1
- package/es/plus/pisellReservation/floorMap/reservationMock.js +1 -1
- package/es/plus/pisellReservation/index.js +17 -0
- package/es/plus/saleDetail/Base.js +1 -0
- package/es/plus/saleDetail/components/CartItems/Editable/index.js +1 -0
- package/es/plus/saleDetail/components/Client/hooks/useClientSelectorProps.js +1 -0
- package/es/plus/saleDetail/components/DetailActions/index.js +1 -0
- package/es/plus/saleDetail/components/SummaryFinancialSections/index.js +1 -0
- package/es/plus/saleDetail/index.js +1 -0
- package/es/plus/saleDetail/tmpl/B/components/Dish/index.js +1 -0
- package/es/plus/saleDetail/tmpl/B/index.js +1 -0
- package/es/plus/salesSdk/context/SalesSdkCartContext.js +25 -12
- package/es/plus/salesSdk/context/SalesSdkProvider.js +9 -5
- package/es/plus/salesSdk/hosts/BookingEditHostRenderer.js +12 -7
- package/es/plus/salesSdk/index.js +51 -0
- package/es/plus/salesSdk/utils/addProductWithFlowDebounced.js +1 -1
- package/es/plus/salesSdk/utils/bookingDate.js +1 -1
- package/es/plus/salesSdk/utils/customerAuthGate.js +1 -1
- package/es/plus/salesSdk/utils/enrichCartLineHolderDisplay.js +1 -1
- package/es/plus/salesSdk/utils/resolvePreviousService.js +28 -0
- package/es/plus/skuOptionsSelection/components/NormalCard/index.js +18 -12
- package/es/plus/skuOptionsSelection/docs/skuOptionsSelection.$tab-dev.md +66 -2
- package/es/plus/skuOptionsSelection/types.d.ts +50 -1
- package/es/plus/skuOptionsSelection/utils/normalizers.js +17 -0
- package/es/plus/skuOptionsSelection/utils/transformOptionGroup.js +17 -7
- package/es/plus/skuOptionsSelection/utils/transformSelectorValueToValue.js +89 -15
- package/es/plus/skuOptionsSelection/utils/transformValueToSelectorValue.js +31 -19
- package/es/pro/Login2.0/AuthModal.d.ts +1 -1
- package/es/pro/Login2.0/index.d.ts +2 -1
- package/es/pro/Login2.0/shared/types.d.ts +1 -1
- package/es/pro/Selector/Selector.js +11 -6
- package/es/pro/Selector/hooks/useSelectionController.js +54 -61
- package/es/pro/Selector/locales.js +10 -0
- package/es/pro/Selector/types.d.ts +5 -0
- package/es/pro/skuDetailModal/types.d.ts +1 -0
- package/lib/components/bigSale/index.js +2 -2
- package/lib/plus/saleDetail/components/CartItems/Editable/index.js +1 -0
- package/lib/plus/salesSdk/context/SalesSdkCartContext.js +25 -12
- package/lib/plus/salesSdk/context/SalesSdkProvider.js +9 -5
- package/lib/plus/salesSdk/hosts/BookingEditHostRenderer.js +12 -7
- package/lib/plus/salesSdk/utils/resolvePreviousService.js +30 -0
- package/lib/plus/skuOptionsSelection/components/NormalCard/index.js +18 -12
- package/lib/plus/skuOptionsSelection/docs/skuOptionsSelection.$tab-dev.md +66 -2
- package/lib/plus/skuOptionsSelection/types.d.ts +50 -1
- package/lib/plus/skuOptionsSelection/utils/normalizers.js +19 -0
- package/lib/plus/skuOptionsSelection/utils/transformOptionGroup.js +17 -7
- package/lib/plus/skuOptionsSelection/utils/transformSelectorValueToValue.js +89 -15
- package/lib/plus/skuOptionsSelection/utils/transformValueToSelectorValue.js +31 -19
- package/lib/pro/Selector/Selector.js +11 -6
- package/lib/pro/Selector/hooks/useSelectionController.js +54 -61
- package/lib/pro/Selector/locales.js +10 -0
- package/lib/pro/Selector/types.d.ts +5 -0
- package/lib/pro/skuDetailModal/types.d.ts +1 -0
- package/package.json +4 -4
- package/es/private-materials/lowcode/authmodal/meta.d.ts +0 -1
|
@@ -151,7 +151,7 @@ function runAfterNextPaint(task) {
|
|
|
151
151
|
* - 新建态:按 OS persist 开关走 createNew 或 restore → initBookingContext
|
|
152
152
|
* 须位于 SalesSdkSummaryProvider 内,以便 summaryProviderRef 已通过 useImperativeHandle 注入。
|
|
153
153
|
*/
|
|
154
|
-
function SalesSdkBootstrap({
|
|
154
|
+
function SalesSdkBootstrap({ autoRestoreOnInit, autoBootstrap, autoInitBookingContext, orderId, preloadedSalesDetail, initBookingContext, prepareModule, prepareCatalog, catalogKey, lifecycleOwner }) {
|
|
155
155
|
const sales = (0, react.useContext)(require_SalesSdkContext.SalesSdkContext);
|
|
156
156
|
const cart = require_useSalesSdkCart.useSalesSdkCart();
|
|
157
157
|
(0, react.useEffect)(() => {
|
|
@@ -185,7 +185,7 @@ function SalesSdkBootstrap({ solution, autoRestoreOnInit, autoBootstrap, autoIni
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
-
if (cancelled || !autoInitBookingContext
|
|
188
|
+
if (cancelled || !autoInitBookingContext) return;
|
|
189
189
|
const bookingIds = require_buildDefaultLoadProductsParams.collectBookingIdsFromTempOrder((_sales$bookingTicket$2 = (_sales$bookingTicket2 = sales.bookingTicket) === null || _sales$bookingTicket2 === void 0 || (_sales$bookingTicket3 = _sales$bookingTicket2.getTempOrder) === null || _sales$bookingTicket3 === void 0 ? void 0 : _sales$bookingTicket3.call(_sales$bookingTicket2)) !== null && _sales$bookingTicket$2 !== void 0 ? _sales$bookingTicket$2 : null);
|
|
190
190
|
yield initBookingContext(bookingIds.length ? bookingIds : void 0, { loadResources: !(autoBootstrap && orderId) });
|
|
191
191
|
} catch (e) {
|
|
@@ -212,7 +212,6 @@ function SalesSdkBootstrap({ solution, autoRestoreOnInit, autoBootstrap, autoIni
|
|
|
212
212
|
autoRestoreOnInit,
|
|
213
213
|
autoBootstrap,
|
|
214
214
|
autoInitBookingContext,
|
|
215
|
-
solution,
|
|
216
215
|
orderId,
|
|
217
216
|
preloadedSalesDetail,
|
|
218
217
|
initBookingContext,
|
|
@@ -651,7 +650,13 @@ const SalesSdkProvider = ({ osKey, solution = "bookingTicket", moduleAccess = "e
|
|
|
651
650
|
*/
|
|
652
651
|
const initBookingContext = (0, ahooks.useMemoizedFn)(function() {
|
|
653
652
|
var _ref2 = require_asyncToGenerator._asyncToGenerator(function* (bookingIds, options) {
|
|
654
|
-
if (!
|
|
653
|
+
if (!bookingTicket) return;
|
|
654
|
+
if (String((otherParams === null || otherParams === void 0 ? void 0 : otherParams.platform) || "").trim().toLowerCase() === "h5") {
|
|
655
|
+
var _bookingTicket$loadBo;
|
|
656
|
+
yield (_bookingTicket$loadBo = bookingTicket.loadBookingConfig) === null || _bookingTicket$loadBo === void 0 ? void 0 : _bookingTicket$loadBo.call(bookingTicket, bookingConfigParams);
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
if (!bookingTicket.initBookingContext) return;
|
|
655
660
|
yield bookingTicket.initBookingContext(require_buildDefaultLoadProductsParams.buildInitBookingContextParams(bookingConfigParams, {
|
|
656
661
|
bookingIds,
|
|
657
662
|
loadResources: options === null || options === void 0 ? void 0 : options.loadResources
|
|
@@ -1343,7 +1348,6 @@ const SalesSdkProvider = ({ osKey, solution = "bookingTicket", moduleAccess = "e
|
|
|
1343
1348
|
onPromotionScanComplete: handlePromotionScanComplete,
|
|
1344
1349
|
promotionScanSuccessMessageKey: promotionItemIncreaseMessageKey ? void 0 : promotionScanSuccessMessageKey
|
|
1345
1350
|
}), /* @__PURE__ */ react.default.createElement(SalesSdkBootstrap, {
|
|
1346
|
-
solution,
|
|
1347
1351
|
autoRestoreOnInit,
|
|
1348
1352
|
autoBootstrap,
|
|
1349
1353
|
autoInitBookingContext,
|
|
@@ -6,6 +6,7 @@ const require_buildDefaultLoadProductsParams = require("../utils/buildDefaultLoa
|
|
|
6
6
|
const require_buildBookingEditDrawerState = require("../bookingEditService/buildBookingEditDrawerState.js");
|
|
7
7
|
const require_resolveIsMultiDayProduct = require("../utils/resolveIsMultiDayProduct.js");
|
|
8
8
|
const require_multiDayPriceCache = require("../utils/multiDayPriceCache.js");
|
|
9
|
+
const require_resolvePreviousService = require("../utils/resolvePreviousService.js");
|
|
9
10
|
const require_prepareCacheItemForBookingEdit = require("../bookingEditService/prepareCacheItemForBookingEdit.js");
|
|
10
11
|
const require_useSalesSdk = require("../hooks/useSalesSdk.js");
|
|
11
12
|
const require_useSyncExternalStoreCompat = require("../hooks/useSyncExternalStoreCompat.js");
|
|
@@ -20,11 +21,15 @@ let _pisell_utils = require("@pisell/utils");
|
|
|
20
21
|
/**
|
|
21
22
|
* 将 Host payload 的 cacheItem 补齐展示字段并写入 state。
|
|
22
23
|
*/
|
|
23
|
-
function normalizeCacheItemForDrawer(rawItem, bookingTicket, forceOpen) {
|
|
24
|
+
function normalizeCacheItemForDrawer(rawItem, bookingTicket, tempOrder, forceOpen) {
|
|
24
25
|
let item = rawItem;
|
|
25
26
|
if (require_multiDayPriceCache.isMultiDayQuotationExpanded(item)) item = require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, item), {}, { new: 0 });
|
|
26
27
|
if (typeof bookingTicket.getProductExtend === "function") try {
|
|
27
|
-
|
|
28
|
+
var _bookingTicket$getBoo, _bookingTicket$getBoo2;
|
|
29
|
+
item = bookingTicket.getProductExtend(item, {
|
|
30
|
+
bookingConfig: (_bookingTicket$getBoo = (_bookingTicket$getBoo2 = bookingTicket.getBookingConfig) === null || _bookingTicket$getBoo2 === void 0 ? void 0 : _bookingTicket$getBoo2.call(bookingTicket)) !== null && _bookingTicket$getBoo !== void 0 ? _bookingTicket$getBoo : void 0,
|
|
31
|
+
previousService: require_resolvePreviousService.resolvePreviousService(tempOrder)
|
|
32
|
+
});
|
|
28
33
|
} catch (e) {
|
|
29
34
|
console.warn("[SalesSdk] getProductExtend 失败,使用原始 cacheItem", e);
|
|
30
35
|
}
|
|
@@ -81,7 +86,7 @@ const BookingEditHostRenderer = () => {
|
|
|
81
86
|
var _ref = require_asyncToGenerator._asyncToGenerator(function* () {
|
|
82
87
|
yield ensureBookingContextForDrawer(bookingTicket, payload, tempOrder, bookingConfigParams);
|
|
83
88
|
if (cancelled) return;
|
|
84
|
-
const item = normalizeCacheItemForDrawer(payload.cacheItem, bookingTicket, payload.forceOpen);
|
|
89
|
+
const item = normalizeCacheItemForDrawer(payload.cacheItem, bookingTicket, tempOrder, payload.forceOpen);
|
|
85
90
|
if (item.autoClose && !payload.forceOpen) {
|
|
86
91
|
bridge.complete(item);
|
|
87
92
|
return;
|
|
@@ -93,7 +98,7 @@ const BookingEditHostRenderer = () => {
|
|
|
93
98
|
};
|
|
94
99
|
})()().catch((err) => {
|
|
95
100
|
console.warn("[SalesSdk] openBookingEdit 初始化资源上下文失败", err);
|
|
96
|
-
if (!cancelled) setCacheItem(normalizeCacheItemForDrawer(payload.cacheItem, bookingTicket, payload.forceOpen));
|
|
101
|
+
if (!cancelled) setCacheItem(normalizeCacheItemForDrawer(payload.cacheItem, bookingTicket, tempOrder, payload.forceOpen));
|
|
97
102
|
});
|
|
98
103
|
return () => {
|
|
99
104
|
cancelled = true;
|
|
@@ -179,10 +184,10 @@ const BookingEditHostRenderer = () => {
|
|
|
179
184
|
cacheItem === null || cacheItem === void 0 || (_cacheItem$_data = cacheItem._data) === null || _cacheItem$_data === void 0 || (_cacheItem$_data = _cacheItem$_data.resources) === null || _cacheItem$_data === void 0 ? void 0 : _cacheItem$_data.length
|
|
180
185
|
]);
|
|
181
186
|
const bookingState = (0, react.useMemo)(() => {
|
|
182
|
-
var _bookingTicket$
|
|
187
|
+
var _bookingTicket$getBoo3, _bookingTicket$getBoo4, _ref3, _payload$date2, _bookingTicket$getBoo5, _bookingTicket$getTem3, _bookingTicket$getTem4, _bookingTicket$getOrd, _bookingTicket$getOth;
|
|
183
188
|
if (!cacheItem) return null;
|
|
184
|
-
const bookingConfig = (_bookingTicket$
|
|
185
|
-
const date = (_ref3 = (_payload$date2 = payload === null || payload === void 0 ? void 0 : payload.date) !== null && _payload$date2 !== void 0 ? _payload$date2 : bookingTicket === null || bookingTicket === void 0 || (_bookingTicket$
|
|
189
|
+
const bookingConfig = (_bookingTicket$getBoo3 = bookingTicket === null || bookingTicket === void 0 || (_bookingTicket$getBoo4 = bookingTicket.getBookingConfig) === null || _bookingTicket$getBoo4 === void 0 ? void 0 : _bookingTicket$getBoo4.call(bookingTicket)) !== null && _bookingTicket$getBoo3 !== void 0 ? _bookingTicket$getBoo3 : null;
|
|
190
|
+
const date = (_ref3 = (_payload$date2 = payload === null || payload === void 0 ? void 0 : payload.date) !== null && _payload$date2 !== void 0 ? _payload$date2 : bookingTicket === null || bookingTicket === void 0 || (_bookingTicket$getBoo5 = bookingTicket.getBookingDate) === null || _bookingTicket$getBoo5 === void 0 ? void 0 : _bookingTicket$getBoo5.call(bookingTicket)) !== null && _ref3 !== void 0 ? _ref3 : (0, dayjs.default)().format("YYYY-MM-DD");
|
|
186
191
|
const liveTempOrder = (_bookingTicket$getTem3 = bookingTicket === null || bookingTicket === void 0 || (_bookingTicket$getTem4 = bookingTicket.getTempOrder) === null || _bookingTicket$getTem4 === void 0 ? void 0 : _bookingTicket$getTem4.call(bookingTicket)) !== null && _bookingTicket$getTem3 !== void 0 ? _bookingTicket$getTem3 : tempOrder;
|
|
187
192
|
return require_buildBookingEditDrawerState.buildBookingEditDrawerState({
|
|
188
193
|
cacheItem,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const require_runtime = require("../../../_virtual/_rolldown/runtime.js");
|
|
2
|
+
let dayjs = require("dayjs");
|
|
3
|
+
dayjs = require_runtime.__toESM(dayjs);
|
|
4
|
+
//#region src/plus/salesSdk/utils/resolvePreviousService.ts
|
|
5
|
+
/**
|
|
6
|
+
* 取得下一预约计算开始时间时所需的“上一服务”。
|
|
7
|
+
*
|
|
8
|
+
* 对齐 info2:它会过滤自定义/普通商品后,通过 getLastServer 取 service.value[0]。
|
|
9
|
+
* SalesSdk 的 tempOrder.bookings 按加入顺序追加,因此从后向前取最后一条
|
|
10
|
+
* 时间完整的商品预约,转换为 OS BookingCalcContext 所需结构。
|
|
11
|
+
* `parent_id === 0` 是订单级 root booking,不对应商品行,需要跳过;
|
|
12
|
+
* 新建本地预约的 parent_id 可能尚未生成(null/undefined),仍属于有效候选。
|
|
13
|
+
*/
|
|
14
|
+
function resolvePreviousService(tempOrder) {
|
|
15
|
+
const bookings = Array.isArray(tempOrder === null || tempOrder === void 0 ? void 0 : tempOrder.bookings) ? tempOrder.bookings : [];
|
|
16
|
+
for (let index = bookings.length - 1; index >= 0; index -= 1) {
|
|
17
|
+
const booking = bookings[index];
|
|
18
|
+
if ((booking === null || booking === void 0 ? void 0 : booking.parent_id) != null && Number(booking.parent_id) === 0) continue;
|
|
19
|
+
if (!(booking === null || booking === void 0 ? void 0 : booking.start_date) || !(booking === null || booking === void 0 ? void 0 : booking.start_time) || !(booking === null || booking === void 0 ? void 0 : booking.end_date) || !(booking === null || booking === void 0 ? void 0 : booking.end_time)) continue;
|
|
20
|
+
const startDate = (0, dayjs.default)(`${booking.start_date} ${booking.start_time}`);
|
|
21
|
+
const endDate = (0, dayjs.default)(`${booking.end_date} ${booking.end_time}`);
|
|
22
|
+
if (!startDate.isValid() || !endDate.isValid()) continue;
|
|
23
|
+
return { _extend: {
|
|
24
|
+
startDate,
|
|
25
|
+
endDate
|
|
26
|
+
} };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
exports.resolvePreviousService = resolvePreviousService;
|
|
@@ -9,7 +9,7 @@ let decimal_js = require("decimal.js");
|
|
|
9
9
|
decimal_js = require_runtime.__toESM(decimal_js);
|
|
10
10
|
//#region src/plus/skuOptionsSelection/components/NormalCard/index.tsx
|
|
11
11
|
const NormalCard = (props) => {
|
|
12
|
-
var _props$
|
|
12
|
+
var _props$dataSource2;
|
|
13
13
|
const { _key: uniqueKey, ruleConfig, _original, disabled, selected } = (props === null || props === void 0 ? void 0 : props.dataSource) || {};
|
|
14
14
|
const { cover, title, name, product_subtitle, price, price_type, add_price } = _original || {};
|
|
15
15
|
const symbol = require_useStore.default((s) => s.symbol);
|
|
@@ -25,20 +25,25 @@ const NormalCard = (props) => {
|
|
|
25
25
|
};
|
|
26
26
|
const renderNumberSelector = () => {
|
|
27
27
|
if (!(props === null || props === void 0 ? void 0 : props.numberSelector) || typeof (props === null || props === void 0 ? void 0 : props.numberSelector) !== "object") return null;
|
|
28
|
-
return react.default.cloneElement(props === null || props === void 0 ? void 0 : props.numberSelector, { onChange: (v) => {
|
|
29
|
-
var _props$actions;
|
|
28
|
+
return react.default.cloneElement(props === null || props === void 0 ? void 0 : props.numberSelector, { onChange: (v, meta) => {
|
|
29
|
+
var _props$dataSource, _props$actions;
|
|
30
|
+
const itemMin = Math.max(1, Number((ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.min) || 0));
|
|
31
|
+
const currentQuantity = Number((props === null || props === void 0 || (_props$dataSource = props.dataSource) === null || _props$dataSource === void 0 ? void 0 : _props$dataSource.quantity) || 0);
|
|
32
|
+
let nextQuantity = v;
|
|
33
|
+
if ((meta === null || meta === void 0 ? void 0 : meta.action) === "increase" && currentQuantity <= 0) nextQuantity = itemMin;
|
|
34
|
+
else if ((meta === null || meta === void 0 ? void 0 : meta.action) === "decrease" && itemMin > 1 && currentQuantity === itemMin && v < itemMin) nextQuantity = 0;
|
|
30
35
|
const _price = add_price !== void 0 && add_price !== null ? add_price : price;
|
|
31
36
|
const priceType = price_type === "markdown" ? -1 : 1;
|
|
32
|
-
const totalPrice = new decimal_js.default(_price).times(new decimal_js.default(
|
|
37
|
+
const totalPrice = new decimal_js.default(_price).times(new decimal_js.default(nextQuantity)).times(priceType).toNumber();
|
|
33
38
|
const newOriginal = require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, _original), {}, {
|
|
34
|
-
quantity:
|
|
35
|
-
num:
|
|
39
|
+
quantity: nextQuantity,
|
|
40
|
+
num: nextQuantity,
|
|
36
41
|
price: _price,
|
|
37
42
|
original_price: _price,
|
|
38
43
|
original_total: _price
|
|
39
44
|
});
|
|
40
45
|
props === null || props === void 0 || (_props$actions = props.actions) === null || _props$actions === void 0 || _props$actions.update(uniqueKey, {
|
|
41
|
-
quantity:
|
|
46
|
+
quantity: nextQuantity,
|
|
42
47
|
data: newOriginal,
|
|
43
48
|
totalPrice
|
|
44
49
|
});
|
|
@@ -65,17 +70,18 @@ const NormalCard = (props) => {
|
|
|
65
70
|
var _props$actions3;
|
|
66
71
|
const _price = add_price !== void 0 && add_price !== null ? add_price : price;
|
|
67
72
|
const priceType = price_type === "markdown" ? -1 : 1;
|
|
73
|
+
const initialQuantity = Math.max(1, Number((ruleConfig === null || ruleConfig === void 0 ? void 0 : ruleConfig.min) || 0));
|
|
68
74
|
const newOriginal = require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, _original), {}, {
|
|
69
|
-
quantity:
|
|
70
|
-
num:
|
|
75
|
+
quantity: initialQuantity,
|
|
76
|
+
num: initialQuantity,
|
|
71
77
|
price: _price,
|
|
72
78
|
original_price: _price,
|
|
73
79
|
original_total: _price
|
|
74
80
|
});
|
|
75
81
|
props === null || props === void 0 || (_props$actions3 = props.actions) === null || _props$actions3 === void 0 || _props$actions3.update(uniqueKey, {
|
|
76
|
-
quantity:
|
|
82
|
+
quantity: initialQuantity,
|
|
77
83
|
data: newOriginal,
|
|
78
|
-
totalPrice: new decimal_js.default(_price).times(priceType).toNumber()
|
|
84
|
+
totalPrice: new decimal_js.default(_price).times(initialQuantity).times(priceType).toNumber()
|
|
79
85
|
});
|
|
80
86
|
}
|
|
81
87
|
};
|
|
@@ -102,7 +108,7 @@ const NormalCard = (props) => {
|
|
|
102
108
|
} }))),
|
|
103
109
|
onClick: handleChange,
|
|
104
110
|
skuCardConfig,
|
|
105
|
-
skuDisabled: (props === null || props === void 0 || (_props$
|
|
111
|
+
skuDisabled: (props === null || props === void 0 || (_props$dataSource2 = props.dataSource) === null || _props$dataSource2 === void 0 || (_props$dataSource2 = _props$dataSource2._extra) === null || _props$dataSource2 === void 0 ? void 0 : _props$dataSource2.disabled) === true
|
|
106
112
|
});
|
|
107
113
|
};
|
|
108
114
|
//#endregion
|
|
@@ -15,7 +15,7 @@ category: plus
|
|
|
15
15
|
## 2. 版本
|
|
16
16
|
|
|
17
17
|
**当前版本**: `1.0.0`
|
|
18
|
-
**最后更新**:
|
|
18
|
+
**最后更新**: 2026-08-12
|
|
19
19
|
|
|
20
20
|
## 3. 相关文档
|
|
21
21
|
|
|
@@ -51,6 +51,10 @@ SKUOptionsSelection
|
|
|
51
51
|
|
|
52
52
|
```typescript
|
|
53
53
|
export interface DataSource {
|
|
54
|
+
/** 商品id */
|
|
55
|
+
id?: number;
|
|
56
|
+
/** 生产编码 */
|
|
57
|
+
production_code?: string;
|
|
54
58
|
/** 单规格组数据 */
|
|
55
59
|
option_group?: Array<OptionGroupItem>;
|
|
56
60
|
/** 组合规格组装后的数据 */
|
|
@@ -58,7 +62,17 @@ export interface DataSource {
|
|
|
58
62
|
/** 组合规格组数据 */
|
|
59
63
|
variant_group?: Array<VariantGroupItem>;
|
|
60
64
|
/** 套餐商品组数据 */
|
|
61
|
-
bundle_group?: Array<
|
|
65
|
+
bundle_group?: Array<BundleGroupItem>;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface OptionGroupMetadata {
|
|
69
|
+
advanced_settings_enabled?: 0 | 1;
|
|
70
|
+
option_types_config?: {
|
|
71
|
+
min?: number;
|
|
72
|
+
max?: number;
|
|
73
|
+
[key: string]: unknown;
|
|
74
|
+
};
|
|
75
|
+
[key: string]: unknown;
|
|
62
76
|
}
|
|
63
77
|
|
|
64
78
|
/**
|
|
@@ -88,6 +102,8 @@ export interface OptionGroupItem {
|
|
|
88
102
|
max_quantity?: number;
|
|
89
103
|
/** 最小选择数量 */
|
|
90
104
|
min_quantity?: number;
|
|
105
|
+
/** 高级设置元数据 */
|
|
106
|
+
metadata?: OptionGroupMetadata;
|
|
91
107
|
/** 单规格组名称 */
|
|
92
108
|
name?: string;
|
|
93
109
|
/** 单规格组下规格数据 */
|
|
@@ -133,6 +149,8 @@ export interface OptionItem {
|
|
|
133
149
|
is_enabled?: 0 | 1;
|
|
134
150
|
/** 最大选择数量 */
|
|
135
151
|
max_quantity?: number;
|
|
152
|
+
/** 最小选择数量 */
|
|
153
|
+
min_quantity?: number;
|
|
136
154
|
/** 规格名称 */
|
|
137
155
|
name?: string;
|
|
138
156
|
/** 规格组id */
|
|
@@ -141,6 +159,8 @@ export interface OptionItem {
|
|
|
141
159
|
original_price?: string;
|
|
142
160
|
/** 商品id */
|
|
143
161
|
product_id?: number;
|
|
162
|
+
/** 生产编码 */
|
|
163
|
+
production_code?: string;
|
|
144
164
|
/** 店铺id */
|
|
145
165
|
shop_id?: number;
|
|
146
166
|
/** 排序 */
|
|
@@ -268,6 +288,8 @@ export interface VariantProductItem {
|
|
|
268
288
|
price?: string;
|
|
269
289
|
/** 商品id */
|
|
270
290
|
product_id?: number;
|
|
291
|
+
/** 生产编码 */
|
|
292
|
+
production_code?: string;
|
|
271
293
|
/** 折扣类型 */
|
|
272
294
|
rebate_type?: string;
|
|
273
295
|
/** 折扣值 */
|
|
@@ -350,6 +372,8 @@ export interface BundleItem {
|
|
|
350
372
|
price_type_ext?: '' | 'product_price';
|
|
351
373
|
/** 商品id */
|
|
352
374
|
product_id?: number;
|
|
375
|
+
/** 生产编码 */
|
|
376
|
+
production_code?: string;
|
|
353
377
|
/** 商品价格 */
|
|
354
378
|
product_price?: string;
|
|
355
379
|
/** 商品副标题 */
|
|
@@ -370,6 +394,8 @@ export interface SkuValue {
|
|
|
370
394
|
product_variant_id: number;
|
|
371
395
|
/** 多规格商品选项字符串 */
|
|
372
396
|
product_option_string?: string;
|
|
397
|
+
/** 当前商品或组合规格商品的生产编码 */
|
|
398
|
+
production_code?: string;
|
|
373
399
|
/** 套餐商品组数据 */
|
|
374
400
|
bundle: Array<any>;
|
|
375
401
|
/** 单规格组数据 */
|
|
@@ -666,6 +692,44 @@ const App = () => {
|
|
|
666
692
|
/>
|
|
667
693
|
```
|
|
668
694
|
|
|
695
|
+
### 6.7 Option 高级限制与 Production Code
|
|
696
|
+
|
|
697
|
+
多选 Option Group 在 `metadata.advanced_settings_enabled=1` 时支持种类数限制:
|
|
698
|
+
|
|
699
|
+
```typescript
|
|
700
|
+
{
|
|
701
|
+
is_multiple: 1,
|
|
702
|
+
min_quantity: 1, // 总份数下限
|
|
703
|
+
max_quantity: 4, // 总份数上限,0 表示不限
|
|
704
|
+
metadata: {
|
|
705
|
+
advanced_settings_enabled: 1,
|
|
706
|
+
option_types_config: {
|
|
707
|
+
min: 1, // 最少种类数,0 表示不限
|
|
708
|
+
max: 2, // 最多种类数,0 表示不限
|
|
709
|
+
},
|
|
710
|
+
},
|
|
711
|
+
option_item: [
|
|
712
|
+
{
|
|
713
|
+
id: 1,
|
|
714
|
+
min_quantity: 2, // 选择该项后的最少份数
|
|
715
|
+
max_quantity: 0, // 单项份数不限
|
|
716
|
+
production_code: 'OPTION-1',
|
|
717
|
+
},
|
|
718
|
+
],
|
|
719
|
+
}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
达到最多种类数后,组件只禁用尚未选择的 Option Item;已选项仍可在总份数和单项规则允许的范围内调整。Item `min_quantity` 仅对已选项生效,首次选择会从该最小数量开始。
|
|
723
|
+
|
|
724
|
+
`getTransformValues()` 和 `onChange` 输出会明确携带以下编码:
|
|
725
|
+
|
|
726
|
+
- `production_code`:Product 或当前 Variant 编码。
|
|
727
|
+
- `option[*].production_code`:Option Item 编码。
|
|
728
|
+
- `bundle[*].production_code`:Bundle Item 编码。
|
|
729
|
+
- `bundle[*].option[*].production_code`:套餐嵌套 Option Item 编码。
|
|
730
|
+
|
|
731
|
+
显式空字符串表示“无编码”,不会回退到 Product 或其他节点编码。
|
|
732
|
+
|
|
669
733
|
## 7. 注意事项
|
|
670
734
|
|
|
671
735
|
1. **数据格式**:确保传入的 `dataSource` 和 `value` 格式正确,否则可能导致组件渲染异常
|
|
@@ -90,6 +90,10 @@ interface IProps {
|
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
interface DataSource {
|
|
93
|
+
/** 商品id */
|
|
94
|
+
id?: number;
|
|
95
|
+
/** 生产编码 */
|
|
96
|
+
production_code?: string;
|
|
93
97
|
/** 单规格组数据 */
|
|
94
98
|
option_group?: Array<OptionGroupItem>;
|
|
95
99
|
/** 组合规格组装后的数据 */
|
|
@@ -97,7 +101,19 @@ interface DataSource {
|
|
|
97
101
|
/** 组合规格组数据 */
|
|
98
102
|
variant_group?: Array<VariantGroupItem>;
|
|
99
103
|
/** 套餐商品组数据 */
|
|
100
|
-
bundle_group?: Array<
|
|
104
|
+
bundle_group?: Array<BundleGroupItem>;
|
|
105
|
+
}
|
|
106
|
+
interface OptionGroupMetadata {
|
|
107
|
+
/** 是否启用高级设置 */
|
|
108
|
+
advanced_settings_enabled?: 0 | 1;
|
|
109
|
+
/** Option 种类数限制 */
|
|
110
|
+
option_types_config?: {
|
|
111
|
+
min?: number;
|
|
112
|
+
max?: number;
|
|
113
|
+
[key: string]: unknown;
|
|
114
|
+
};
|
|
115
|
+
/** 保留后端返回的其他元数据 */
|
|
116
|
+
[key: string]: unknown;
|
|
101
117
|
}
|
|
102
118
|
/**
|
|
103
119
|
* 单规格组数据
|
|
@@ -125,6 +141,8 @@ interface OptionGroupItem {
|
|
|
125
141
|
max_quantity?: number;
|
|
126
142
|
/** 最小选择数量 */
|
|
127
143
|
min_quantity?: number;
|
|
144
|
+
/** 高级设置元数据 */
|
|
145
|
+
metadata?: OptionGroupMetadata;
|
|
128
146
|
/** 单规格组名称 */
|
|
129
147
|
name?: string;
|
|
130
148
|
/** 单规格组下规格数据 */
|
|
@@ -168,6 +186,8 @@ interface OptionItem {
|
|
|
168
186
|
is_enabled?: 0 | 1;
|
|
169
187
|
/** 最大选择数量 */
|
|
170
188
|
max_quantity?: number;
|
|
189
|
+
/** 最小选择数量 */
|
|
190
|
+
min_quantity?: number;
|
|
171
191
|
/** 规格名称 */
|
|
172
192
|
name?: string;
|
|
173
193
|
/** 规格组id */
|
|
@@ -176,6 +196,8 @@ interface OptionItem {
|
|
|
176
196
|
original_price?: string;
|
|
177
197
|
/** 商品id */
|
|
178
198
|
product_id?: number;
|
|
199
|
+
/** 生产编码 */
|
|
200
|
+
production_code?: string;
|
|
179
201
|
/** 店铺id */
|
|
180
202
|
shop_id?: number;
|
|
181
203
|
/** 排序 */
|
|
@@ -297,6 +319,8 @@ interface VariantProductItem {
|
|
|
297
319
|
price?: string;
|
|
298
320
|
/** 商品id */
|
|
299
321
|
product_id?: number;
|
|
322
|
+
/** 生产编码 */
|
|
323
|
+
production_code?: string;
|
|
300
324
|
/** 折扣类型 */
|
|
301
325
|
rebate_type?: string;
|
|
302
326
|
/** 折扣值 */
|
|
@@ -312,6 +336,27 @@ interface VariantProductItem {
|
|
|
312
336
|
/** 重量值 */
|
|
313
337
|
weight_value?: string;
|
|
314
338
|
}
|
|
339
|
+
/**
|
|
340
|
+
* 套餐商品组数据
|
|
341
|
+
*/
|
|
342
|
+
interface BundleGroupItem {
|
|
343
|
+
/** 店铺id */
|
|
344
|
+
shop_id?: number;
|
|
345
|
+
/** 排序 */
|
|
346
|
+
sort?: number;
|
|
347
|
+
/** 套餐id */
|
|
348
|
+
id?: number;
|
|
349
|
+
/** 最大选择数量 */
|
|
350
|
+
max_quantity?: number;
|
|
351
|
+
/** 最小选择数量 */
|
|
352
|
+
min_quantity?: number;
|
|
353
|
+
/** 套餐名称 */
|
|
354
|
+
name?: string;
|
|
355
|
+
/** 商品id */
|
|
356
|
+
product_id?: number;
|
|
357
|
+
/** 套餐商品组数据 */
|
|
358
|
+
bundle_item?: Array<BundleItem>;
|
|
359
|
+
}
|
|
315
360
|
/**
|
|
316
361
|
* 套餐商品组下选项数据
|
|
317
362
|
*/
|
|
@@ -354,6 +399,8 @@ interface BundleItem {
|
|
|
354
399
|
price_type_ext?: '' | 'product_price';
|
|
355
400
|
/** 商品id */
|
|
356
401
|
product_id?: number;
|
|
402
|
+
/** 生产编码 */
|
|
403
|
+
production_code?: string;
|
|
357
404
|
/** 商品价格 */
|
|
358
405
|
product_price?: string;
|
|
359
406
|
/** 商品副标题 */
|
|
@@ -373,6 +420,8 @@ interface SkuValue {
|
|
|
373
420
|
product_variant_id: number;
|
|
374
421
|
/** 多规格商品选项字符串 */
|
|
375
422
|
product_option_string?: string;
|
|
423
|
+
/** 当前商品或组合规格商品的生产编码 */
|
|
424
|
+
production_code?: string;
|
|
376
425
|
/** 套餐商品组数据 */
|
|
377
426
|
bundle: Array<any>;
|
|
378
427
|
/** 价格 */
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/plus/skuOptionsSelection/utils/normalizers.ts
|
|
2
|
+
const normalizeNonNegativeInteger = (value, fallback = 0) => {
|
|
3
|
+
const normalizedFallback = Math.max(0, Math.trunc(Number(fallback) || 0));
|
|
4
|
+
if (value === null || value === void 0 || typeof value === "string" && value.trim() === "") return normalizedFallback;
|
|
5
|
+
const normalizedValue = Number(value);
|
|
6
|
+
if (!Number.isFinite(normalizedValue)) return normalizedFallback;
|
|
7
|
+
return Math.max(0, Math.trunc(normalizedValue));
|
|
8
|
+
};
|
|
9
|
+
const hasOwnProductionCode = (value) => !!value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, "production_code");
|
|
10
|
+
const normalizeProductionCode = (value) => value === null || value === void 0 ? "" : String(value).trim();
|
|
11
|
+
const resolveProductionCode = (snapshotValue, currentValue) => {
|
|
12
|
+
if (hasOwnProductionCode(snapshotValue)) return normalizeProductionCode(snapshotValue.production_code);
|
|
13
|
+
if (hasOwnProductionCode(currentValue)) return normalizeProductionCode(currentValue.production_code);
|
|
14
|
+
return "";
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
exports.hasOwnProductionCode = hasOwnProductionCode;
|
|
18
|
+
exports.normalizeNonNegativeInteger = normalizeNonNegativeInteger;
|
|
19
|
+
exports.resolveProductionCode = resolveProductionCode;
|
|
@@ -4,6 +4,7 @@ const require_store = require("../store/store.js");
|
|
|
4
4
|
const require_index = require("../components/NormalCard/index.js");
|
|
5
5
|
const require_index$1 = require("../components/TitleExtra/index.js");
|
|
6
6
|
const require_checkSkuStatus = require("./checkSkuStatus.js");
|
|
7
|
+
const require_normalizers = require("./normalizers.js");
|
|
7
8
|
let react = require("react");
|
|
8
9
|
react = require_runtime.__toESM(react);
|
|
9
10
|
//#region src/plus/skuOptionsSelection/utils/transformOptionGroup.tsx
|
|
@@ -13,11 +14,19 @@ const transformOptionGroup = (optionGroup, translationOriginal) => {
|
|
|
13
14
|
const getDisplayText = (value) => typeof value === "string" ? value : (translationOriginal === null || translationOriginal === void 0 ? void 0 : translationOriginal(value)) || "";
|
|
14
15
|
const selectorLayout = ((_store$getState$custo = require_store.default.getState().customConfig) === null || _store$getState$custo === void 0 ? void 0 : _store$getState$custo.selectorLayout) || null;
|
|
15
16
|
return optionGroup.map((item) => {
|
|
16
|
-
var _item$option_item, _item$name;
|
|
17
|
+
var _item$metadata, _item$metadata2, _item$metadata3, _item$option_item, _item$name;
|
|
18
|
+
const isMultiple = (item === null || item === void 0 ? void 0 : item.is_multiple) == 1;
|
|
19
|
+
const groupMin = require_normalizers.normalizeNonNegativeInteger(item === null || item === void 0 ? void 0 : item.min_quantity, 0);
|
|
20
|
+
const groupMax = require_normalizers.normalizeNonNegativeInteger(item === null || item === void 0 ? void 0 : item.max_quantity, 0);
|
|
21
|
+
const advancedEnabled = isMultiple && (item === null || item === void 0 || (_item$metadata = item.metadata) === null || _item$metadata === void 0 ? void 0 : _item$metadata.advanced_settings_enabled) === 1;
|
|
22
|
+
const minTypes = advancedEnabled ? require_normalizers.normalizeNonNegativeInteger(item === null || item === void 0 || (_item$metadata2 = item.metadata) === null || _item$metadata2 === void 0 || (_item$metadata2 = _item$metadata2.option_types_config) === null || _item$metadata2 === void 0 ? void 0 : _item$metadata2.min, 0) : 0;
|
|
23
|
+
const maxTypes = advancedEnabled ? require_normalizers.normalizeNonNegativeInteger(item === null || item === void 0 || (_item$metadata3 = item.metadata) === null || _item$metadata3 === void 0 || (_item$metadata3 = _item$metadata3.option_types_config) === null || _item$metadata3 === void 0 ? void 0 : _item$metadata3.max, 0) : 0;
|
|
17
24
|
const selectorOptionsDataSource = item === null || item === void 0 || (_item$option_item = item.option_item) === null || _item$option_item === void 0 ? void 0 : _item$option_item.map((optionItem) => {
|
|
18
25
|
var _optionItem$name;
|
|
19
26
|
const { canSell, hasStock } = require_checkSkuStatus.checkSkuStockCanSell(optionItem);
|
|
20
27
|
const disabled = require_checkSkuStatus.checkSkuDisabled(optionItem, canSell);
|
|
28
|
+
const itemMin = require_normalizers.normalizeNonNegativeInteger(optionItem === null || optionItem === void 0 ? void 0 : optionItem.min_quantity, 0);
|
|
29
|
+
const itemMax = require_normalizers.normalizeNonNegativeInteger(optionItem === null || optionItem === void 0 ? void 0 : optionItem.max_quantity, 1);
|
|
21
30
|
return {
|
|
22
31
|
_original: require_objectSpread2._objectSpread2(require_objectSpread2._objectSpread2({}, optionItem || {}), {}, { product_option_item_id: optionItem === null || optionItem === void 0 ? void 0 : optionItem.id }),
|
|
23
32
|
id: optionItem === null || optionItem === void 0 ? void 0 : optionItem.id,
|
|
@@ -25,8 +34,8 @@ const transformOptionGroup = (optionGroup, translationOriginal) => {
|
|
|
25
34
|
value: optionItem === null || optionItem === void 0 ? void 0 : optionItem.id,
|
|
26
35
|
disabled,
|
|
27
36
|
ruleConfig: {
|
|
28
|
-
min:
|
|
29
|
-
max:
|
|
37
|
+
min: itemMin,
|
|
38
|
+
max: itemMax,
|
|
30
39
|
autoValidate: true
|
|
31
40
|
},
|
|
32
41
|
_extra: {
|
|
@@ -36,7 +45,6 @@ const transformOptionGroup = (optionGroup, translationOriginal) => {
|
|
|
36
45
|
}
|
|
37
46
|
};
|
|
38
47
|
});
|
|
39
|
-
const isMultiple = (item === null || item === void 0 ? void 0 : item.is_multiple) == 1;
|
|
40
48
|
const selectorDataSource = {
|
|
41
49
|
id: item.id,
|
|
42
50
|
title: getDisplayText((_item$name = item === null || item === void 0 ? void 0 : item.name) !== null && _item$name !== void 0 ? _item$name : item === null || item === void 0 ? void 0 : item.title),
|
|
@@ -49,10 +57,12 @@ const transformOptionGroup = (optionGroup, translationOriginal) => {
|
|
|
49
57
|
dataSource: selectorOptionsDataSource || [],
|
|
50
58
|
disabled: (item === null || item === void 0 ? void 0 : item.is_enabled) === 0,
|
|
51
59
|
ruleConfig: {
|
|
52
|
-
min: isMultiple ?
|
|
53
|
-
max: isMultiple
|
|
60
|
+
min: isMultiple ? groupMin : void 0,
|
|
61
|
+
max: isMultiple && groupMax > 0 ? groupMax : void 0,
|
|
62
|
+
minTypes: isMultiple && minTypes > 0 ? minTypes : void 0,
|
|
63
|
+
maxTypes: isMultiple && maxTypes > 0 ? maxTypes : void 0,
|
|
54
64
|
autoValidate: true,
|
|
55
|
-
required: isMultiple ?
|
|
65
|
+
required: isMultiple ? groupMin > 0 || minTypes > 0 : (item === null || item === void 0 ? void 0 : item.required) === 1
|
|
56
66
|
},
|
|
57
67
|
headerProps: { renderExtra: (props) => {
|
|
58
68
|
return /* @__PURE__ */ react.default.createElement(require_index$1.default, props || {});
|