pb-sxp-ui 1.20.27 → 1.20.29

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.
Files changed (35) hide show
  1. package/dist/index.cjs +353 -39
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +353 -39
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.min.cjs +9 -9
  6. package/dist/index.min.cjs.map +1 -1
  7. package/dist/index.min.js +9 -9
  8. package/dist/index.min.js.map +1 -1
  9. package/dist/pb-ui.js +353 -39
  10. package/dist/pb-ui.js.map +1 -1
  11. package/dist/pb-ui.min.js +9 -9
  12. package/dist/pb-ui.min.js.map +1 -1
  13. package/es/core/context/SxpDataSourceProvider.d.ts +1 -1
  14. package/es/core/index.d.ts +6 -0
  15. package/es/core/index.js +10 -0
  16. package/es/core/utils/materials.js +30 -7
  17. package/es/core/utils/tool.d.ts +1 -0
  18. package/es/core/utils/tool.js +43 -0
  19. package/es/materials/sxp/popup/AddToCart/index.js +27 -8
  20. package/es/materials/sxp/popup/AddToCart/index.new.js +27 -6
  21. package/es/materials/sxp/popup/AddToCart/index.old.js +13 -2
  22. package/es/materials/sxp/popup/CommodityDetail/index.js +21 -16
  23. package/es/materials/sxp/popup/CommodityDetailDiroNew/index.js +25 -0
  24. package/lib/core/context/SxpDataSourceProvider.d.ts +1 -1
  25. package/lib/core/index.d.ts +6 -0
  26. package/lib/core/index.js +10 -5
  27. package/lib/core/utils/materials.js +29 -6
  28. package/lib/core/utils/tool.d.ts +1 -0
  29. package/lib/core/utils/tool.js +45 -1
  30. package/lib/materials/sxp/popup/AddToCart/index.js +27 -8
  31. package/lib/materials/sxp/popup/AddToCart/index.new.js +27 -6
  32. package/lib/materials/sxp/popup/AddToCart/index.old.js +12 -1
  33. package/lib/materials/sxp/popup/CommodityDetail/index.js +21 -16
  34. package/lib/materials/sxp/popup/CommodityDetailDiroNew/index.js +25 -0
  35. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -165,6 +165,14 @@ function uuid(len, radix) {
165
165
  }
166
166
  return uuid.join('');
167
167
  }
168
+ const getIndexByblockType = (type, index) => {
169
+ if (type === 'CommodityCarouselBlock' || type === 'CopyBlock') {
170
+ return 'initial';
171
+ }
172
+ else {
173
+ return index;
174
+ }
175
+ };
168
176
  const generateRandomString = (length) => {
169
177
  let result = '';
170
178
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
@@ -224,6 +232,70 @@ const setFontForText = (textContent, style) => {
224
232
  }
225
233
  return content;
226
234
  };
235
+ function getBrowserInfo() {
236
+ var _a, _b, _c, _d, _e, _f, _g;
237
+ const userAgent = self.navigator.userAgent;
238
+ if (!userAgent)
239
+ return null;
240
+ if (/edge\/([\d\.]+)/i.exec(userAgent))
241
+ return `Edge ${(_a = /edge\/([\d\.]+)/i.exec(userAgent)) === null || _a === void 0 ? void 0 : _a[1]}`;
242
+ if (/edg\/([\d\.]+)/i.exec(userAgent))
243
+ return `Edge(Chromium) ${(_b = /edge\/([\d\.]+)/i.exec(userAgent)) === null || _b === void 0 ? void 0 : _b[1]}`;
244
+ if (/msie/i.test(userAgent))
245
+ return `Internet Explorer ${(_c = /msie ([\d\.]+)/i.exec(userAgent)) === null || _c === void 0 ? void 0 : _c[1]}`;
246
+ if (/Trident/i.test(userAgent))
247
+ return `Internet Explorer ${(_d = /rv:([\d\.]+)/i.exec(userAgent)) === null || _d === void 0 ? void 0 : _d[1]}`;
248
+ if (/chrome/i.test(userAgent))
249
+ return `Chrome ${(_e = /chrome\/([\d\.]+)/i.exec(userAgent)) === null || _e === void 0 ? void 0 : _e[1]}`;
250
+ if (/firefox/i.test(userAgent))
251
+ return `Firefox ${(_f = /firefox\/([\d\.]+)/i.exec(userAgent)) === null || _f === void 0 ? void 0 : _f[1]}`;
252
+ if (/safari/i.test(userAgent))
253
+ return `Safari ${(_g = /version\/([\d\.]+)/i.exec(userAgent)) === null || _g === void 0 ? void 0 : _g[1]}`;
254
+ return null;
255
+ }
256
+ function getSystem() {
257
+ var _a, _b, _c;
258
+ const userAgent = self.navigator.userAgent;
259
+ if (!userAgent)
260
+ return null;
261
+ if (/iphone/i.test(userAgent))
262
+ return `IOS ${(_a = userAgent.match(/OS\s(.*?)\slike/)) === null || _a === void 0 ? void 0 : _a[1]}`;
263
+ if (/android/i.test(userAgent))
264
+ return `Android ${(_b = userAgent.match(/Android\s(.*?)\;/)) === null || _b === void 0 ? void 0 : _b[1]}`;
265
+ if (/windows/i.test(userAgent))
266
+ return `Windows ${(_c = userAgent.match(/Windows\s(.*?)\;/)) === null || _c === void 0 ? void 0 : _c[1]}`;
267
+ if (/mac/i.test(userAgent))
268
+ return 'Mac OS';
269
+ return null;
270
+ }
271
+ function getDevice$1() {
272
+ const userAgent = self.navigator.userAgent;
273
+ if (!userAgent)
274
+ return null;
275
+ if (/iphone/i.test(userAgent))
276
+ return 'iPhone';
277
+ if (/android/i.test(userAgent)) {
278
+ // var index1 = userAgent.indexOf(';');
279
+ // var index2 = userAgent.indexOf(';', index1 + 1);
280
+ // var index3 = userAgent.indexOf(';', index2 + 1);
281
+ // var index4 = userAgent.indexOf(';', index3 + 1);
282
+ // if (index2 !== -1 && index3 !== -1) {
283
+ // var value1 = userAgent.substring(index3 + 1, index4);
284
+ // return `${value1}`;
285
+ // }
286
+ const index1 = userAgent.indexOf('(');
287
+ const index2 = userAgent.indexOf(')');
288
+ if (index1 !== -1 && index2 !== -1) {
289
+ const value = userAgent.substring(index1 + 1, index2);
290
+ return `${value}`;
291
+ }
292
+ }
293
+ if (/windows/i.test(userAgent))
294
+ return 'Windows';
295
+ if (/mac/i.test(userAgent))
296
+ return 'Mac';
297
+ return null;
298
+ }
227
299
  function getCookie(val) {
228
300
  // const expirationDate = new Date();
229
301
  // expirationDate.setDate(expirationDate.getDate() + 100);
@@ -285,6 +357,33 @@ function deleteCookie(name, path = '/', domain = '') {
285
357
  document.cookie = `${name}=; ${expiration}${pathPart}${domainPart}`;
286
358
  console.log(`已尝试删除Cookie: ${name}`);
287
359
  }
360
+ function setCookie(name, value, days = 0, path = '/', domain = '', secure = false, sameSite = 'Lax') {
361
+ let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
362
+ // 设置过期时间
363
+ if (days) {
364
+ const date = new Date();
365
+ date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
366
+ cookieString += `; expires=${date.toUTCString()}`;
367
+ }
368
+ // 设置路径
369
+ if (path) {
370
+ cookieString += `; path=${path}`;
371
+ }
372
+ // 设置域名
373
+ if (domain) {
374
+ cookieString += `; domain=${domain}`;
375
+ }
376
+ // 设置Secure标志
377
+ if (secure) {
378
+ cookieString += '; secure';
379
+ }
380
+ // 设置SameSite属性
381
+ if (sameSite) {
382
+ cookieString += `; samesite=${sameSite}`;
383
+ }
384
+ // 设置Cookie
385
+ document.cookie = cookieString;
386
+ }
288
387
  function getUrlParamByKey(key) {
289
388
  var _a, _b;
290
389
  const queryString = location.search.slice(1);
@@ -299,6 +398,73 @@ function getUrlParamByKey(key) {
299
398
  }
300
399
  return (_b = params[key]) !== null && _b !== void 0 ? _b : '';
301
400
  }
401
+ /**
402
+ * 货币代码到货币符号的映射
403
+ * 根据 Shopify 返回的 currencyCode 获取对应的货币符号
404
+ */
405
+ function getCurrencySymbol(currencyCode) {
406
+ const currencySymbolMap = {
407
+ // 主要货币
408
+ USD: '$', // 美元
409
+ EUR: '€', // 欧元
410
+ GBP: '£', // 英镑
411
+ JPY: '¥', // 日元
412
+ CNY: '¥', // 人民币
413
+ KRW: '₩', // 韩元
414
+ INR: '₹', // 印度卢比
415
+ RUB: '₽', // 俄罗斯卢布
416
+ BRL: 'R$', // 巴西雷亚尔
417
+ CAD: 'CA$', // 加拿大元
418
+ AUD: 'A$', // 澳元
419
+ CHF: 'CHF', // 瑞士法郎
420
+ SEK: 'kr', // 瑞典克朗
421
+ NOK: 'kr', // 挪威克朗
422
+ DKK: 'kr', // 丹麦克朗
423
+ PLN: 'zł', // 波兰兹罗提
424
+ THB: '฿', // 泰铢
425
+ IDR: 'Rp', // 印尼盾
426
+ MYR: 'RM', // 马来西亚林吉特
427
+ PHP: '₱', // 菲律宾比索
428
+ SGD: 'S$', // 新加坡元
429
+ HKD: 'HK$', // 港币
430
+ TWD: 'NT$', // 新台币
431
+ NZD: 'NZ$', // 新西兰元
432
+ MXN: 'MX$', // 墨西哥比索
433
+ ZAR: 'R', // 南非兰特
434
+ TRY: '₺', // 土耳其里拉
435
+ AED: 'AED', // 阿联酋迪拉姆
436
+ SAR: 'SAR', // 沙特里亚尔
437
+ ILS: '₪', // 以色列新谢克尔
438
+ ARS: 'AR$', // 阿根廷比索
439
+ CLP: 'CL$', // 智利比索
440
+ COP: 'CO$', // 哥伦比亚比索
441
+ VND: '₫', // 越南盾
442
+ EGP: 'E£', // 埃及镑
443
+ NGN: '₦', // 尼日利亚奈拉
444
+ PKR: '₨', // 巴基斯坦卢比
445
+ BDT: '৳', // 孟加拉塔卡
446
+ };
447
+ return currencySymbolMap[currencyCode.toUpperCase()] || currencyCode;
448
+ }
449
+
450
+ var tool = /*#__PURE__*/Object.freeze({
451
+ __proto__: null,
452
+ deleteCookie: deleteCookie,
453
+ generateRandomString: generateRandomString,
454
+ getBrowserInfo: getBrowserInfo,
455
+ getCookie: getCookie,
456
+ getCurrencySymbol: getCurrencySymbol,
457
+ getDevice: getDevice$1,
458
+ getIndexByblockType: getIndexByblockType,
459
+ getScreenReader: getScreenReader,
460
+ getSystem: getSystem,
461
+ getUid: getUid,
462
+ getUrlParamByKey: getUrlParamByKey,
463
+ setCookie: setCookie,
464
+ setFontForText: setFontForText,
465
+ splitUrlParams: splitUrlParams,
466
+ uuid: uuid
467
+ });
302
468
 
303
469
  function unzip(b64Data) {
304
470
  const strData = atob(b64Data);
@@ -484,6 +650,18 @@ const refreshFeSessionId = () => {
484
650
  const getFeSessionId = () => {
485
651
  return window.localStorage.getItem(feRealSessionIdKey);
486
652
  };
653
+ // 删除sessionID
654
+ const removeFeSessionId = () => {
655
+ window.localStorage.removeItem(feRealSessionIdKey);
656
+ };
657
+
658
+ var sessionStore = /*#__PURE__*/Object.freeze({
659
+ __proto__: null,
660
+ getFeSessionId: getFeSessionId,
661
+ refreshFeSessionId: refreshFeSessionId,
662
+ removeFeSessionId: removeFeSessionId,
663
+ storeAndLoadFeSessionId: storeAndLoadFeSessionId
664
+ });
487
665
 
488
666
  /*
489
667
  * @Author: binruan@chatlabs.com
@@ -507,6 +685,9 @@ const storeAndLoadFeUserId = () => {
507
685
  }
508
686
  return fakeUserId;
509
687
  };
688
+ const removeFeUserId = () => {
689
+ window.localStorage.removeItem(FAKE_USER_KEY);
690
+ };
510
691
  const getFeUserState = () => {
511
692
  const fakeUserState = window.localStorage.getItem(FAKE_USER_STATE);
512
693
  if (isEmpty(fakeUserState)) {
@@ -536,6 +717,24 @@ const setUserConsentResult = () => {
536
717
  window.localStorage.setItem(USER_CONSENT_RESULT_KEY, 'true');
537
718
  };
538
719
 
720
+ var localStore = /*#__PURE__*/Object.freeze({
721
+ __proto__: null,
722
+ AGREE_POLICY: AGREE_POLICY,
723
+ CCONTSENT_STATE: CCONTSENT_STATE,
724
+ FAKE_USER_KEY: FAKE_USER_KEY,
725
+ FAKE_USER_STATE: FAKE_USER_STATE,
726
+ SLIDE_SKIP_STATE: SLIDE_SKIP_STATE,
727
+ USER_CONSENT_RESULT_KEY: USER_CONSENT_RESULT_KEY,
728
+ getContsentState: getContsentState,
729
+ getFeUserState: getFeUserState,
730
+ getSlideSkipState: getSlideSkipState,
731
+ getUserConsentResult: getUserConsentResult,
732
+ removeFeUserId: removeFeUserId,
733
+ setSlideSkipState: setSlideSkipState,
734
+ setUserConsentResult: setUserConsentResult,
735
+ storeAndLoadFeUserId: storeAndLoadFeUserId
736
+ });
737
+
539
738
  /*
540
739
  * @Author: binruan@chatlabs.com
541
740
  * @Date: 2024-03-20 10:27:31
@@ -1744,6 +1943,23 @@ var DATA_TYPE;
1744
1943
  DATA_TYPE["ARRAY_NUMBER"] = "array-number";
1745
1944
  })(DATA_TYPE || (DATA_TYPE = {}));
1746
1945
 
1946
+ /*
1947
+ * @Author: binruan@chatlabs.com
1948
+ * @Date: 2024-03-20 10:27:31
1949
+ * @LastEditors: binruan@chatlabs.com
1950
+ * @LastEditTime: 2024-03-20 13:56:49
1951
+ * @FilePath: \pb-sxp-ui\src\core\hooks\index.ts
1952
+ *
1953
+ */
1954
+
1955
+ var index$4 = /*#__PURE__*/Object.freeze({
1956
+ __proto__: null,
1957
+ get DATA_TYPE () { return DATA_TYPE; },
1958
+ useDataSource: useDataSource,
1959
+ useEditor: useEditor,
1960
+ useSxpDataSource: useSxpDataSource
1961
+ });
1962
+
1747
1963
  const DataSourceContext = createContext({ $store: {}, options: [], configs: [] });
1748
1964
  const DataSourceProvider = ({ children, isSsr, enable }) => {
1749
1965
  const [options, setOptions] = useState([]);
@@ -10815,7 +11031,7 @@ const getBgStyle = (imgSrc) => {
10815
11031
  : '';
10816
11032
  };
10817
11033
  const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef, style }) => {
10818
- var _a, _b, _c, _d, _e, _f, _g, _h;
11034
+ var _a, _b, _c, _d, _e;
10819
11035
  let text = '';
10820
11036
  if ((!(product === null || product === void 0 ? void 0 : product.currency) || !(product === null || product === void 0 ? void 0 : product.price)) && isHiddenDef)
10821
11037
  return null;
@@ -10823,18 +11039,51 @@ const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef
10823
11039
  if (typeof price !== 'number')
10824
11040
  return text;
10825
11041
  let priceSymbol = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol;
10826
- let currency = (product === null || product === void 0 ? void 0 : product.currency) ? (_c = (_b = (_a = product === null || product === void 0 ? void 0 : product.currency) === null || _a === void 0 ? void 0 : _a.split('-')[1]) === null || _b === void 0 ? void 0 : _b.toUpperCase()) !== null && _c !== void 0 ? _c : '' : '$';
11042
+ // product.currency 中提取货币代码
11043
+ // 支持多种格式:
11044
+ // 1. "EUR" - 直接是货币代码
11045
+ // 2. "USD-$" - 货币代码-货币符号
11046
+ // 3. "$-USD" - 货币符号-货币代码 (不常见)
11047
+ let currencyCode = '';
11048
+ if (product === null || product === void 0 ? void 0 : product.currency) {
11049
+ const parts = product.currency.split('-');
11050
+ if (parts.length > 1) {
11051
+ // 判断哪一部分是货币代码(通常是3个大写字母)
11052
+ // 货币代码通常是3个字母,如 USD, EUR, GBP
11053
+ const firstPart = parts[0].toUpperCase();
11054
+ const secondPart = parts[1].toUpperCase();
11055
+ // 如果第一部分是3个字母,则认为是货币代码
11056
+ if (/^[A-Z]{3}$/.test(firstPart)) {
11057
+ currencyCode = firstPart;
11058
+ }
11059
+ else if (/^[A-Z]{3}$/.test(secondPart)) {
11060
+ currencyCode = secondPart;
11061
+ }
11062
+ else {
11063
+ // 都不是标准格式,取第一部分
11064
+ currencyCode = firstPart;
11065
+ }
11066
+ }
11067
+ else {
11068
+ currencyCode = parts[0].toUpperCase();
11069
+ }
11070
+ }
11071
+ else {
11072
+ currencyCode = 'USD'; // 默认美元
11073
+ }
11074
+ // 使用货币代码映射获取货币符号
11075
+ let currency = getCurrencySymbol(currencyCode);
10827
11076
  const isToLocStr = enableFormattedPrice === undefined || enableFormattedPrice;
10828
11077
  let decPic = price === null || price === void 0 ? void 0 : price.toString();
10829
11078
  if (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) {
10830
11079
  decPic = price === null || price === void 0 ? void 0 : price.toFixed(2);
10831
11080
  }
10832
- let decInd = (_d = decPic === null || decPic === void 0 ? void 0 : decPic.indexOf('.')) !== null && _d !== void 0 ? _d : -1;
11081
+ let decInd = (_a = decPic === null || decPic === void 0 ? void 0 : decPic.indexOf('.')) !== null && _a !== void 0 ? _a : -1;
10833
11082
  if (isToLocStr) {
10834
11083
  text =
10835
- (_e = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
11084
+ (_b = price === null || price === void 0 ? void 0 : price.toLocaleString('zh', {
10836
11085
  minimumFractionDigits: (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.showTwoDecimalPoint) ? 2 : 0
10837
- })) !== null && _e !== void 0 ? _e : '';
11086
+ })) !== null && _b !== void 0 ? _b : '';
10838
11087
  let startIndex = 0;
10839
11088
  let endIndex = decInd !== null && decInd !== void 0 ? decInd : text === null || text === void 0 ? void 0 : text.length;
10840
11089
  if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.millesimalSymbol) === '.') {
@@ -10865,7 +11114,7 @@ const getPriceText = ({ product, enableFormattedPrice, globalConfig, isHiddenDef
10865
11114
  }
10866
11115
  });
10867
11116
  }
10868
- currency = `<span style="font-family:${(_h = (_g = (_f = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol) === null || _f === void 0 ? void 0 : _f.fontFamily) !== null && _g !== void 0 ? _g : style === null || style === void 0 ? void 0 : style['fontFamily-en']) !== null && _h !== void 0 ? _h : 'inherit'}">${currency}</span>`;
11117
+ currency = `<span style="font-family:${(_e = (_d = (_c = globalConfig === null || globalConfig === void 0 ? void 0 : globalConfig.priceSymbol) === null || _c === void 0 ? void 0 : _c.fontFamily) !== null && _d !== void 0 ? _d : style === null || style === void 0 ? void 0 : style['fontFamily-en']) !== null && _e !== void 0 ? _e : 'inherit'}">${currency}</span>`;
10869
11118
  text = setFontForText(text, style);
10870
11119
  if ((priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) && (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) !== 'none') {
10871
11120
  text = (priceSymbol === null || priceSymbol === void 0 ? void 0 : priceSymbol.currencyPosition) === 'left' ? currency + text : text + currency;
@@ -10901,30 +11150,37 @@ const CommodityDetail$1 = (_a) => {
10901
11150
  cta = p === null || p === void 0 ? void 0 : p.bindCta;
10902
11151
  }
10903
11152
  const handleLink = (e) => {
10904
- // 如果启用了加购功能且配置了加购弹窗ID,则打开加购弹窗
11153
+ // 如果启用了加购功能且配置了加购弹窗ID,检查是否是 Shopify 商品
10905
11154
  if (enableAddToCart && addToCartPopupId) {
10906
- // 设置弹窗数据
10907
- setPopupDetailData === null || setPopupDetailData === void 0 ? void 0 : setPopupDetailData(Object.assign(Object.assign({}, data), { index: position }));
10908
- // 上报点击事件
10909
- bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
10910
- eventName: 'ClickCTA',
10911
- product: product ? [product] : undefined,
10912
- contentType: 'product',
10913
- data,
10914
- position,
10915
- cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
10916
- cta_action_type: 'open_internal_popup',
10917
- target_content_id: product === null || product === void 0 ? void 0 : product.itemId
10918
- });
10919
- console.log('[CommodityDetail] 打开加购弹窗:', addToCartPopupId);
10920
- // 打开加购弹窗
10921
- if (typeof window !== 'undefined' && window.sxpPopup) {
10922
- window.sxpPopup(addToCartPopupId);
11155
+ // 问题3:只有 Shopify 商品(有 shopifyId)才打开加购弹窗
11156
+ if (!(product === null || product === void 0 ? void 0 : product.shopifyId)) {
11157
+ console.warn('[CommodityDetail] 非 Shopify 商品,跳过加购弹窗');
11158
+ // 继续执行默认行为(跳转链接)
10923
11159
  }
10924
11160
  else {
10925
- console.warn('[CommodityDetail] sxpPopup 方法不存在');
11161
+ // 设置弹窗数据
11162
+ setPopupDetailData === null || setPopupDetailData === void 0 ? void 0 : setPopupDetailData(Object.assign(Object.assign({}, data), { index: position }));
11163
+ // 上报点击事件
11164
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
11165
+ eventName: 'ClickCTA',
11166
+ product: product ? [product] : undefined,
11167
+ contentType: 'product',
11168
+ data,
11169
+ position,
11170
+ cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
11171
+ cta_action_type: 'open_internal_popup',
11172
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId
11173
+ });
11174
+ console.log('[CommodityDetail] 打开加购弹窗:', addToCartPopupId);
11175
+ // 打开加购弹窗
11176
+ if (typeof window !== 'undefined' && window.sxpPopup) {
11177
+ window.sxpPopup(addToCartPopupId);
11178
+ }
11179
+ else {
11180
+ console.warn('[CommodityDetail] sxpPopup 方法不存在');
11181
+ }
11182
+ return;
10926
11183
  }
10927
- return;
10928
11184
  }
10929
11185
  // 默认行为:跳转到商品链接
10930
11186
  if (product === null || product === void 0 ? void 0 : product.link) {
@@ -11894,7 +12150,7 @@ var settingRender$d = [
11894
12150
 
11895
12151
  const AddToCartPopup$1 = ({ isActive = true }) => {
11896
12152
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
11897
- const { popupDetailData, globalConfig } = useSxpDataSource();
12153
+ const { popupDetailData, globalConfig, bffFbReport } = useSxpDataSource();
11898
12154
  const [productData, setProductData] = useState(null);
11899
12155
  const [selectedOptions, setSelectedOptions] = useState({});
11900
12156
  const [selectedVariant, setSelectedVariant] = useState(null);
@@ -12034,6 +12290,18 @@ const AddToCartPopup$1 = ({ isActive = true }) => {
12034
12290
  shopifyDomain,
12035
12291
  selectedVariant
12036
12292
  });
12293
+ // 上报 sessionCompleted 事件(问题4)
12294
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
12295
+ eventName: 'sessionCompleted',
12296
+ product: product ? [product] : undefined,
12297
+ contentType: 'product',
12298
+ rec: data,
12299
+ position: data === null || data === void 0 ? void 0 : data.index,
12300
+ cta_text: 'Add To Cart',
12301
+ cta_action_type: 'add_to_cart',
12302
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
12303
+ target_url: `https://${shopifyDomain}/cart/add`
12304
+ });
12037
12305
  // 使用 Shopify 的 /cart/add 接口,通过查询参数添加商品
12038
12306
  // 这种方式会跳转到购物车页面而不是结算页面
12039
12307
  const params = new URLSearchParams({
@@ -12048,6 +12316,10 @@ const AddToCartPopup$1 = ({ isActive = true }) => {
12048
12316
  const totalPrice = selectedVariant
12049
12317
  ? (parseFloat(selectedVariant.price.amount) * quantity).toFixed(2)
12050
12318
  : '0.00';
12319
+ // 只有选择了 variant 后才显示货币符号
12320
+ const displayPrice = selectedVariant
12321
+ ? `${getCurrencySymbol(selectedVariant.price.currencyCode)}${totalPrice}`
12322
+ : totalPrice;
12051
12323
  if (loading) {
12052
12324
  return (React.createElement("div", { className: 'add-to-cart-popup' },
12053
12325
  React.createElement("div", { className: 'loading' }, "Loading...")));
@@ -12081,9 +12353,7 @@ const AddToCartPopup$1 = ({ isActive = true }) => {
12081
12353
  "Available: ",
12082
12354
  selectedVariant.quantityAvailable))),
12083
12355
  React.createElement("div", { className: 'variant-price-row' },
12084
- React.createElement("div", { className: 'price' },
12085
- "$",
12086
- totalPrice),
12356
+ React.createElement("div", { className: 'price' }, displayPrice),
12087
12357
  React.createElement("div", { className: 'quantity-selector' },
12088
12358
  React.createElement("button", { className: 'qty-btn', onClick: () => setQuantity(Math.max(1, quantity - 1)), disabled: quantity <= 1 }, "\u2212"),
12089
12359
  React.createElement("span", { className: 'qty-value' }, quantity),
@@ -12091,16 +12361,26 @@ const AddToCartPopup$1 = ({ isActive = true }) => {
12091
12361
  React.createElement("div", { className: 'variant-options' }, productData.options.map(option => (React.createElement("div", { key: option.name, className: 'option-group' },
12092
12362
  React.createElement("div", { className: 'option-label' }, option.name),
12093
12363
  React.createElement("div", { className: 'option-values' }, option.values.map(value => {
12094
- // 检查这个选项是否可选(availableForSale = true,如果有 quantityAvailable 则还需 > 0)
12364
+ // 检查这个选项值与当前已选择的其他选项组合后是否可用
12095
12365
  const isAvailable = productData.variants.edges.some(({ node: variant }) => {
12366
+ // 检查这个variant是否匹配当前选项值
12096
12367
  const hasThisOption = variant.selectedOptions.some(opt => opt.name === option.name && opt.value === value);
12097
- if (!hasThisOption || !variant.availableForSale)
12368
+ if (!hasThisOption)
12098
12369
  return false;
12099
- // 如果有 quantityAvailable 字段,则需要检查库存
12100
- if (variant.quantityAvailable !== undefined) {
12101
- return variant.quantityAvailable > 0;
12102
- }
12103
- // 没有 quantityAvailable 字段时,只要 availableForSale 为 true 就可选
12370
+ // 检查这个variant是否匹配其他已选择的选项
12371
+ const matchesOtherSelections = Object.entries(selectedOptions).every(([key, val]) => {
12372
+ // 跳过当前正在检查的选项
12373
+ if (key === option.name)
12374
+ return true;
12375
+ return variant.selectedOptions.some(opt => opt.name === key && opt.value === val);
12376
+ });
12377
+ if (!matchesOtherSelections)
12378
+ return false;
12379
+ // 检查是否可售
12380
+ if (!variant.availableForSale)
12381
+ return false;
12382
+ // 如果有 quantityAvailable 字段且为0,但 availableForSale 为 true,仍然可选(问题2)
12383
+ // 如果 quantityAvailable 不存在,只要 availableForSale 为 true 就可选
12104
12384
  return true;
12105
12385
  });
12106
12386
  const isSelected = selectedOptions[option.name] === value;
@@ -12151,7 +12431,35 @@ const CommodityDetailDiroNew$1 = (_a) => {
12151
12431
  }
12152
12432
  const handleLink = (e) => {
12153
12433
  e.preventDefault();
12154
- // 上报点击事件
12434
+ // 问题3:只有 Shopify 商品(有 shopifyId)才打开加购弹窗
12435
+ if (!(product === null || product === void 0 ? void 0 : product.shopifyId)) {
12436
+ console.warn('[CommodityDetailDiroNew] 非 Shopify 商品,跳转到外链');
12437
+ // 上报点击事件
12438
+ ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
12439
+ eventSubject: 'clickCta',
12440
+ eventDescription: 'User clicked the CTA'
12441
+ }, data, product, position);
12442
+ bffFbReport === null || bffFbReport === void 0 ? void 0 : bffFbReport({
12443
+ eventName: 'ClickCTA',
12444
+ product: product ? [product] : undefined,
12445
+ contentType: 'product',
12446
+ data,
12447
+ position,
12448
+ cta_text: cta === null || cta === void 0 ? void 0 : cta.enTitle,
12449
+ cta_action_type: 'open_external_link',
12450
+ target_content_id: product === null || product === void 0 ? void 0 : product.itemId,
12451
+ target_url: product === null || product === void 0 ? void 0 : product.link
12452
+ });
12453
+ if (!isPost) {
12454
+ productView(data, product, cta, viewTime || curTimeRef.current, position);
12455
+ }
12456
+ // 跳转到商品链接
12457
+ if (product === null || product === void 0 ? void 0 : product.link) {
12458
+ window.location.href = window.getJointUtmLink(product.link);
12459
+ }
12460
+ return;
12461
+ }
12462
+ // Shopify 商品:上报点击事件
12155
12463
  ctaEvent === null || ctaEvent === void 0 ? void 0 : ctaEvent({
12156
12464
  eventSubject: 'clickCta',
12157
12465
  eventDescription: 'User clicked the CTA'
@@ -19774,7 +20082,13 @@ const StructurePage = (_a) => {
19774
20082
  var index$3 = /*#__PURE__*/Object.freeze({
19775
20083
  __proto__: null,
19776
20084
  EditorCore: EditorCore,
19777
- StructurePage: StructurePage
20085
+ Pagebuilder: Pagebuilder,
20086
+ StructurePage: StructurePage,
20087
+ createMaterial: createMaterial,
20088
+ hooks: index$4,
20089
+ localStore: localStore,
20090
+ sessionStore: sessionStore,
20091
+ tool: tool
19778
20092
  });
19779
20093
 
19780
20094
  /*