ui-utils-kit
Version:
ui-utils-kit 是一个高效的偏业务前端工具函数库
507 lines (493 loc) • 15.2 kB
JavaScript
;
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;