UNPKG

ui-utils-kit

Version:

ui-utils-kit 是一个高效的偏业务前端工具函数库

507 lines (493 loc) 15.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); const html2canvas = require('html2canvas-pro'); function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; } const html2canvas__default = /*#__PURE__*/_interopDefaultCompat(html2canvas); async function captureElementAsImage(element, canvasConfig = {}, outputOptions = { download: true, downloadName: "\u4E0B\u8F7D\u56FE\u7247", blob: false }) { if (!element) { throw new Error("captureElementAsImage element required"); } const defaultCanvasConfig = { scale: 2, // 提高清晰度 proxy: "", backgroundColor: "#ffffff", // 防止生成的图片背景透明 useCORS: false, // 允许跨域图片 allowTaint: false // 允许污染 canvas }; const defaultOutputOptions = { download: true, downloadName: "\u4E0B\u8F7D\u56FE\u7247", blob: false, ...outputOptions }; const finalCanvasConfig = { ...defaultCanvasConfig, ...canvasConfig }; let canvas = null; let dataUrl = null; let blobResult = null; canvas = await html2canvas__default(element, finalCanvasConfig); if (defaultOutputOptions.download) { dataUrl = canvas.toDataURL("image/png"); const link = document.createElement("a"); link.href = dataUrl; link.download = `${defaultOutputOptions.downloadName}.png`; document.body.appendChild(link); link.click(); document.body.removeChild(link); } if (defaultOutputOptions.blob) { blobResult = await new Promise((resolve, reject) => { canvas.toBlob((blob) => { if (blob) { resolve(blob); } else { reject(new Error("canvas \u8F6C Blob \u5931\u8D25\uFF01")); } }, "image/png", 1); }); } return { canvas, dataUrl, blob: blobResult }; } const business = { __proto__: null, captureElementAsImage: captureElementAsImage }; function safeJsonParse(jsonString, defaultValue) { try { const parsed = JSON.parse(jsonString); return [null, parsed]; } catch (error) { console.error("JSON \u89E3\u6790\u9519\u8BEF:", error); return [error instanceof Error ? error : new Error(String(error)), defaultValue]; } } function desensitize(value, type) { if (typeof value !== "string") { return value; } switch (type) { case "mobile": return value.replace(/^(1[3-9]\d)(\d{4})(\d{4})$/, (_, p1, _p2, p3) => `${p1}****${p3}`); case "idcard": return value.replace(/^(.{6})\d+(.{4})$/, (_, p1, p2) => `${p1}******${p2}`); case "email": return value.replace(/^(.)([^@]*)(@[^@]+)$/, (_, first, middle, domain) => `${first}${middle.replace(/./g, "*")}${domain}`); case "bankcard": return value.replace(/\s+/g, "").replace(/.(?=.{4})/g, "*").replace(/(.{4})/g, "$1 ").trim(); case "name": if (/[\u4E00-\u9FA5]/.test(value)) { const len = value.length; if (len === 2) { return `${value[0]}*`; } else if (len >= 3) { return value[0] + "*".repeat(len - 2) + value[len - 1]; } else { return "*"; } } else { return value.split(" ").map((part) => { const len = part.length; if (len >= 3) { return part[0] + "*".repeat(len - 2) + part[len - 1]; } else if (len === 2) { return `${part[0]}*`; } else if (len === 1) { return "*"; } return part; }).join(" "); } default: return value.replace(/^(.)(.*)(.)$/, (_, first, middle, last) => `${first}${middle.replace(/./g, "*")}${last}`); } } class Mutex { /** * 锁的状态:true 表示已锁定,false 表示未锁定 */ #locked = false; /** * 等待获取锁的 Promise resolve 函数队列 */ #queue = []; /** * 获取锁。如果当前已锁定,则将请求加入队列,等待解锁后依次获取。 * @returns Promise<void> - 当获取到锁时,Promise 被 resolve。 */ lock() { if (this.#locked) { return new Promise((resolve) => { this.#queue.push(resolve); }); } this.#locked = true; return Promise.resolve(); } /** * 释放锁。如果有等待队列,则唤醒队列中的下一个请求;否则将锁状态设为未锁定。 */ unlock() { if (this.#queue.length > 0) { const nextResolve = this.#queue.shift(); nextResolve?.(); } else { this.#locked = false; } } /** * 查询当前锁的状态 * @returns boolean - true 表示已锁定,false 表示未锁定 */ isLocked() { return this.#locked; } /** * 获取当前等待队列的长度 * @returns number - 等待队列中的请求数量 */ queueLength() { return this.#queue.length; } } function createSelfCorrectingClock(interval = 1e3) { let currentTime = Date.now(); let expected = Date.now() + interval; let timerId; const step = () => { const drift = Date.now() - expected; currentTime = Date.now(); expected += interval; const timeout = Math.max(0, interval - drift); timerId = setTimeout(step, timeout); }; timerId = setTimeout(step, interval); return { getCurrentTime: () => currentTime, stop: () => clearTimeout(timerId) // 内部清除,无须外部管理 :contentReference[oaicite:6]{index=6} }; } function createSelfCorrectingCountdown(targetTimestamp, interval = 1e3) { let remaining = Math.max(targetTimestamp - Date.now(), 0); let expected = Date.now() + interval; let timerId; const step = () => { const drift = Date.now() - expected; remaining = Math.max(targetTimestamp - Date.now(), 0); if (remaining === 0) { return; } expected += interval; const timeout = Math.max(0, interval - drift); timerId = setTimeout(step, timeout); }; timerId = setTimeout(step, interval); return { getRemainingTime: () => remaining, stop: () => clearTimeout(timerId) }; } const common = { __proto__: null, Mutex: Mutex, createSelfCorrectingClock: createSelfCorrectingClock, createSelfCorrectingCountdown: createSelfCorrectingCountdown, desensitize: desensitize, safeJsonParse: safeJsonParse }; const CheckStatus = { Unchecked: "0", HalfChecked: "1", Checked: "2" }; function buildTree(nodes) { const tree = []; const idToNodeMap = /* @__PURE__ */ new Map(); const idToChildMap = /* @__PURE__ */ new Map(); for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if (!node) { continue; } if (!idToNodeMap.has(node.id)) { idToNodeMap.set(node.id, node); } idToChildMap.set(node.id, []); node.children = []; } for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if (!node) { continue; } if (node.pid === null) { tree.push(node); } else { const parent = idToNodeMap.get(node.pid); const childrenIds = parent ? idToChildMap.get(parent.id) : []; if (parent && !childrenIds?.includes(Number(node.id))) { idToChildMap.get(parent.id)?.push(node.id); parent.children?.push(node); } } } return tree; } function treeToArr(data) { const result = []; function deep(tree, pid = null) { for (const item of tree) { const { id, name, children = [] } = item; if (children.length > 0) { deep(children, id); } result.push({ id, name, pid, check: CheckStatus.Unchecked }); } } deep(data); return result; } function updateTreeCheckStatus(tree, selectedNodes) { const nodeMap = /* @__PURE__ */ new Map(); function createNodeMap(nodes, map) { nodes.forEach((node) => { map.set(node.id, node); if (node.children && node.children.length > 0) { createNodeMap(node.children, map); } }); } function updateChildrenCheck(node, checkStatus) { node.check = checkStatus; if (node.children && node.children.length > 0) { node.children.forEach((child) => updateChildrenCheck(child, checkStatus)); } } function updateParentCheck(node) { const parent = nodeMap.get(node.pid ?? -1); if (parent) { const allChecked = parent.children?.every((child) => child.check === CheckStatus.Checked) ?? false; const allUnchecked = parent.children?.every((child) => child.check === CheckStatus.Unchecked) ?? false; if (allChecked) { parent.check = CheckStatus.Checked; } else if (allUnchecked) { parent.check = CheckStatus.Unchecked; } else { parent.check = CheckStatus.HalfChecked; } updateParentCheck(parent); } } createNodeMap(tree, nodeMap); selectedNodes.forEach((node) => { const targetNode = nodeMap.get(node.id); if (targetNode) { updateChildrenCheck(targetNode, CheckStatus.Checked); } }); selectedNodes.forEach((node) => { const targetNode = nodeMap.get(node.id); if (targetNode) { updateParentCheck(targetNode); } }); return tree; } function updateTreeCheckStatusFlat(tree, selectedNodes) { const idToNodeMap = /* @__PURE__ */ new Map(); const pidToChildrenMap = /* @__PURE__ */ new Map(); tree.forEach((node) => { idToNodeMap.set(node.id, node); if (!pidToChildrenMap.has(node.pid ?? -1)) { pidToChildrenMap.set(node.pid ?? -1, []); } pidToChildrenMap.get(node.pid ?? -1).push(node); }); function setCheckStatus(node, status) { node.check = status; if (pidToChildrenMap.has(node.id)) { pidToChildrenMap.get(node.id).forEach((child) => setCheckStatus(child, status)); } } function updateParentCheck(node) { const parent = idToNodeMap.get(node.pid ?? -1); if (parent) { const children = pidToChildrenMap.get(parent.id) ?? []; const allChecked = children.every((child) => child.check === CheckStatus.Checked); const allUnchecked = children.every((child) => child.check === CheckStatus.Unchecked); parent.check = allChecked ? CheckStatus.Checked : allUnchecked ? CheckStatus.Unchecked : CheckStatus.HalfChecked; updateParentCheck(parent); } } selectedNodes.forEach((node) => { const targetNode = idToNodeMap.get(node.id); if (targetNode) { setCheckStatus(targetNode, CheckStatus.Checked); } }); selectedNodes.forEach((node) => { const targetNode = idToNodeMap.get(node.id); if (targetNode) { updateParentCheck(targetNode); } }); return tree; } function searchTreeWithRelations(treeArr = [], keywords = "", mark = true) { const resultSet = /* @__PURE__ */ new Set(); const idToNodeMap = /* @__PURE__ */ new Map(); const pidToChildrenMap = /* @__PURE__ */ new Map(); const result = []; treeArr.forEach((node) => { const isMatched = node.name.includes(keywords); idToNodeMap.set(node.id, node); if (!pidToChildrenMap.has(node.pid)) { pidToChildrenMap.set(node.pid, []); } pidToChildrenMap.get(node.pid).push(node); if (isMatched) { resultSet.add(node.id); result.push(mark ? { ...node, isMatched } : node); } }); function findChildren(node) { const children = pidToChildrenMap.get(node.id); if (children) { children.forEach((child) => { if (!resultSet.has(child.id)) { resultSet.add(child.id); result.push(child); } findChildren(child); }); } } function findParent(node) { let parent = idToNodeMap.get(node.pid); while (parent) { if (!resultSet.has(parent.id)) { resultSet.add(parent.id); result.unshift(parent); } parent = idToNodeMap.get(parent.pid); } } treeArr.forEach((node) => { const isMatched = node.name.includes(keywords); if (isMatched) { findChildren(node); findParent(node); } }); return result; } function removeNodesFromTree(treeArr = [], selectedNodes = []) { const idsToRemove = new Set(selectedNodes.map((node) => node.id)); const remainingNodes = treeArr.filter((node) => { if (idsToRemove.has(node.id) || node.pid !== null && idsToRemove.has(node.pid)) { return false; } return true; }); return remainingNodes; } function mergeTrees(treeArr = [], nodes = []) { const nodesIdMap = new Set(treeArr.map((node) => node.id)); nodes.forEach((node) => { if (!nodesIdMap.has(node.id) && (node.pid === null || nodesIdMap.has(node.pid))) { treeArr.push(node); } }); return treeArr; } function selectRelatedNodes(treeData, selectedNodes = []) { const selectedNodeIds = /* @__PURE__ */ new Set(); const nodeByIdMap = /* @__PURE__ */ new Map(); const childrenByPidMap = /* @__PURE__ */ new Map(); const selectedNodesAndRelated = []; const selectedNodesMap = new Map(selectedNodes.map((node) => [node.id, node])); treeData.forEach((node) => { const isSelected = selectedNodesMap.get(node.id); nodeByIdMap.set(node.id, node); if (!childrenByPidMap.has(node.pid)) { childrenByPidMap.set(node.pid, []); } childrenByPidMap.get(node.pid).push(node); if (isSelected) { selectedNodeIds.add(node.id); selectedNodesAndRelated.push(node); } }); function collectChildren(node) { const children = childrenByPidMap.get(node.id); if (children) { children.forEach((child) => { if (!selectedNodeIds.has(child.id)) { selectedNodeIds.add(child.id); selectedNodesAndRelated.push(child); } collectChildren(child); }); } } function collectParents(node) { let parent = nodeByIdMap.get(node.pid); while (parent) { if (!selectedNodeIds.has(parent.id)) { selectedNodeIds.add(parent.id); selectedNodesAndRelated.unshift(parent); } parent = nodeByIdMap.get(parent.pid); } } treeData.forEach((node) => { const isSelected = selectedNodesMap.get(node.id); if (isSelected) { collectChildren(node); collectParents(node); } }); return selectedNodesAndRelated; } const tree = { __proto__: null, buildTree: buildTree, mergeTrees: mergeTrees, removeNodesFromTree: removeNodesFromTree, searchTreeWithRelations: searchTreeWithRelations, selectRelatedNodes: selectRelatedNodes, treeToArr: treeToArr, updateTreeCheckStatus: updateTreeCheckStatus, updateTreeCheckStatusFlat: updateTreeCheckStatusFlat }; const index = { tree, business, common }; exports.Mutex = Mutex; exports.buildTree = buildTree; exports.captureElementAsImage = captureElementAsImage; exports.createSelfCorrectingClock = createSelfCorrectingClock; exports.createSelfCorrectingCountdown = createSelfCorrectingCountdown; exports.default = index; exports.desensitize = desensitize; exports.mergeTrees = mergeTrees; exports.removeNodesFromTree = removeNodesFromTree; exports.safeJsonParse = safeJsonParse; exports.searchTreeWithRelations = searchTreeWithRelations; exports.selectRelatedNodes = selectRelatedNodes; exports.treeToArr = treeToArr; exports.updateTreeCheckStatus = updateTreeCheckStatus; exports.updateTreeCheckStatusFlat = updateTreeCheckStatusFlat;