a2bei4-utils 1.0.6 → 1.0.8

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.
@@ -357,7 +357,111 @@ function getAllSearchParams() {
357
357
  function getSearchParam(key) {
358
358
  const params = getAllSearchParams();
359
359
  return params[key];
360
- }
360
+ }
361
+
362
+ /**
363
+ * 全屏操作辅助工具对象
364
+ * @namespace fullscreenHelper
365
+ */
366
+ const fullscreenHelper = {
367
+ /**
368
+ * 请求进入全屏模式
369
+ * @param {Element} element - 要全屏显示的元素
370
+ * @returns {Promise<void> | undefined} 全屏请求 Promise(如支持)
371
+ */
372
+ requestFullscreen: (element) => {
373
+ if (!element) {
374
+ console.warn("未提供有效的 DOM 元素");
375
+ return;
376
+ }
377
+ if (element.requestFullscreen) {
378
+ return element.requestFullscreen();
379
+ } else if (element.mozRequestFullScreen) {
380
+ return element.mozRequestFullScreen();
381
+ } else if (element.webkitRequestFullscreen) {
382
+ return element.webkitRequestFullscreen();
383
+ } else if (element.msRequestFullscreen) {
384
+ return element.msRequestFullscreen();
385
+ } else {
386
+ console.warn("当前浏览器不支持全屏 API");
387
+ }
388
+ },
389
+
390
+ /**
391
+ * 退出全屏模式
392
+ * @returns {Promise<void> | undefined} 退出全屏请求 Promise(如支持)
393
+ */
394
+ exitFullscreen: () => {
395
+ if (document.exitFullscreen) {
396
+ return document.exitFullscreen();
397
+ } else if (document.mozCancelFullScreen) {
398
+ return document.mozCancelFullScreen();
399
+ } else if (document.webkitExitFullscreen) {
400
+ return document.webkitExitFullscreen();
401
+ } else if (document.msExitFullscreen) {
402
+ return document.msExitFullscreen();
403
+ }
404
+ },
405
+
406
+ /**
407
+ * 获取当前全屏元素
408
+ * @returns {Element | null} 当前处于全屏模式的元素,无则返回 null
409
+ */
410
+ getFullscreenElement: () => {
411
+ return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement || null;
412
+ },
413
+
414
+ /**
415
+ * 检测当前是否处于全屏模式
416
+ * @returns {boolean} 是否全屏中
417
+ */
418
+ isFullscreen: () => {
419
+ return !!(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);
420
+ },
421
+
422
+ /**
423
+ * 检测浏览器是否支持全屏 API
424
+ * @returns {boolean} 是否支持全屏
425
+ */
426
+ isFullscreenEnabled: () => {
427
+ return !!(document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled);
428
+ },
429
+
430
+ /**
431
+ * 切换指定元素的全屏状态
432
+ * @param {Element} element - 要切换全屏的元素
433
+ * @returns {Promise<void> | undefined} 全屏操作 Promise
434
+ */
435
+ toggleFullscreen: (element) => {
436
+ if (fullscreenHelper.isFullscreen()) {
437
+ return fullscreenHelper.exitFullscreen();
438
+ } else {
439
+ return fullscreenHelper.requestFullscreen(element);
440
+ }
441
+ },
442
+
443
+ /**
444
+ * 监听全屏变化事件
445
+ * @param {Function} callback - 全屏状态变化时的回调函数,参数为 isFullscreen: boolean
446
+ * @returns {Function} 取消监听的函数
447
+ */
448
+ onFullscreenChange: (callback) => {
449
+ const handler = () => {
450
+ callback(fullscreenHelper.isFullscreen());
451
+ };
452
+ document.addEventListener("fullscreenchange", handler);
453
+ document.addEventListener("webkitfullscreenchange", handler);
454
+ document.addEventListener("mozfullscreenchange", handler);
455
+ document.addEventListener("msfullscreenchange", handler);
456
+
457
+ return () => {
458
+ document.removeEventListener("fullscreenchange", handler);
459
+ document.removeEventListener("webkitfullscreenchange", handler);
460
+ document.removeEventListener("mozfullscreenchange", handler);
461
+ document.removeEventListener("msfullscreenchange", handler);
462
+ };
463
+ }
464
+ };
361
465
 
362
466
  //#region 数据类型判断
363
467
 
@@ -1224,6 +1328,9 @@ async function fetchOrDownloadByUrl(url, fileName) {
1224
1328
  const urlPathname = new URL(url).pathname;
1225
1329
  // 获取路径的最后一部分作为文件名,并移除可能的查询参数
1226
1330
  fileName = urlPathname.substring(urlPathname.lastIndexOf("/") + 1).split("?")[0];
1331
+ if (fileName) {
1332
+ fileName = decodeURIComponent(fileName);
1333
+ }
1227
1334
  } catch (e) {}
1228
1335
  // 如果提取后文件名为空(例如 URL 以 '/' 结尾),也使用时间戳
1229
1336
  if (!fileName) {
@@ -1899,6 +2006,64 @@ function extractFullyCheckedKeys(treeData, selectedKeys, idKey = "id", childrenK
1899
2006
  checked: [...checked],
1900
2007
  halfChecked: [...halfChecked]
1901
2008
  };
2009
+ }
2010
+
2011
+ /**
2012
+ * 在树形结构中查找目标节点的完整路径(从根节点到目标节点,含目标节点自身)。
2013
+ *
2014
+ * @template T extends Record<PropertyKey, any>
2015
+ * @param {T[]} nodes - 树形结构森林(支持多根)
2016
+ * @param {any} targetValue - 目标节点的 key 值
2017
+ * @param {string} [key='id'] - 节点唯一标识字段
2018
+ * @param {string} [parentKey='pid'] - 父节点标识字段(指向父节点的 key 值)
2019
+ * @param {string} [childrenKey='children'] - 子节点数组字段
2020
+ * @returns {T[]} 从根到目标节点的路径数组;未找到返回空数组
2021
+ *
2022
+ * @example
2023
+ * const tree = [
2024
+ * { id: 1, pid: null, children: [
2025
+ * { id: 2, pid: 1, children: [
2026
+ * { id: 3, pid: 2 }
2027
+ * ]}
2028
+ * ]}
2029
+ * ];
2030
+ * findTreeNodePath(tree, 3); // [{id:1, ...}, {id:2, ...}, {id:3, ...}]
2031
+ */
2032
+ function findTreeNodePath(nodes, targetValue, key = "id", parentKey = "pid", childrenKey = "children") {
2033
+ if (!Array.isArray(nodes) || nodes.length === 0 || targetValue == null) {
2034
+ return [];
2035
+ }
2036
+
2037
+ // 1. 建立节点索引
2038
+ const index = new Map();
2039
+ const stack = [...nodes];
2040
+
2041
+ while (stack.length) {
2042
+ const node = stack.pop();
2043
+ if (!node || typeof node !== "object") continue;
2044
+
2045
+ index.set(node[key], node);
2046
+
2047
+ const children = node[childrenKey];
2048
+ if (Array.isArray(children)) {
2049
+ stack.push(...children);
2050
+ }
2051
+ }
2052
+
2053
+ // 2. 回溯路径(防循环引用)
2054
+ const path = [];
2055
+ const visited = new Set();
2056
+ let cur = index.get(targetValue);
2057
+
2058
+ while (cur && !visited.has(cur[key])) {
2059
+ visited.add(cur[key]);
2060
+ path.push(cur);
2061
+
2062
+ const parentValue = cur[parentKey];
2063
+ cur = parentValue != null ? index.get(parentValue) : undefined;
2064
+ }
2065
+
2066
+ return path.reverse();
1902
2067
  }
1903
2068
 
1904
2069
  /**
@@ -2324,8 +2489,10 @@ exports.extractFullyCheckedKeys = extractFullyCheckedKeys;
2324
2489
  exports.fetchOrDownloadByUrl = fetchOrDownloadByUrl;
2325
2490
  exports.findObjAttrValueById = findObjAttrValueById;
2326
2491
  exports.findTreeNodeById = findTreeNodeById;
2492
+ exports.findTreeNodePath = findTreeNodePath;
2327
2493
  exports.flatCompleteTree2NestedTree = flatCompleteTree2NestedTree;
2328
2494
  exports.formatTimeForLocale = formatTimeForLocale;
2495
+ exports.fullscreenHelper = fullscreenHelper;
2329
2496
  exports.getAllSearchParams = getAllSearchParams;
2330
2497
  exports.getDataType = getDataType;
2331
2498
  exports.getFunctionArgNames = getFunctionArgNames;