a2bei4-utils 1.0.9 → 1.0.11
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/dist/a2bei4.utils.cjs.js +193 -2
- package/dist/a2bei4.utils.cjs.js.map +1 -1
- package/dist/a2bei4.utils.cjs.min.js +1 -1
- package/dist/a2bei4.utils.cjs.min.js.map +1 -1
- package/dist/a2bei4.utils.esm.js +191 -2
- package/dist/a2bei4.utils.esm.js.map +1 -1
- package/dist/a2bei4.utils.esm.min.js +1 -1
- package/dist/a2bei4.utils.esm.min.js.map +1 -1
- package/dist/a2bei4.utils.umd.js +193 -2
- package/dist/a2bei4.utils.umd.js.map +1 -1
- package/dist/a2bei4.utils.umd.min.js +1 -1
- package/dist/a2bei4.utils.umd.min.js.map +1 -1
- package/dist/arr.cjs.map +1 -1
- package/dist/arr.js.map +1 -1
- package/dist/audio.cjs.map +1 -1
- package/dist/audio.js.map +1 -1
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.js.map +1 -1
- package/dist/common.cjs.map +1 -1
- package/dist/common.js.map +1 -1
- package/dist/date.cjs.map +1 -1
- package/dist/date.js.map +1 -1
- package/dist/download.cjs.map +1 -1
- package/dist/download.js.map +1 -1
- package/dist/evt.cjs.map +1 -1
- package/dist/evt.js.map +1 -1
- package/dist/id.cjs.map +1 -1
- package/dist/id.js.map +1 -1
- package/dist/menu.cjs.map +1 -1
- package/dist/menu.js.map +1 -1
- package/dist/timer.cjs +14 -0
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.js +14 -0
- package/dist/timer.js.map +1 -1
- package/dist/tree.cjs +177 -0
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.js +176 -1
- package/dist/tree.js.map +1 -1
- package/dist/webSocket.cjs.map +1 -1
- package/dist/webSocket.js.map +1 -1
- package/package.json +5 -5
- package/types/index.d.ts +186 -2
- package/types/timer.d.ts +4 -0
- package/types/tree.d.ts +182 -1
package/dist/a2bei4.utils.cjs.js
CHANGED
|
@@ -564,7 +564,7 @@ function isFunction(obj) {
|
|
|
564
564
|
* @param {*} obj - 待检测的值
|
|
565
565
|
* @returns {obj is string}
|
|
566
566
|
*/
|
|
567
|
-
function isNonEmptyString(obj) {
|
|
567
|
+
function isNonEmptyString$1(obj) {
|
|
568
568
|
return getDataType(obj) === "string" && obj.length > 0;
|
|
569
569
|
}
|
|
570
570
|
|
|
@@ -1823,6 +1823,10 @@ class IntervalTimer {
|
|
|
1823
1823
|
this._fn = fn;
|
|
1824
1824
|
this._ms = ms;
|
|
1825
1825
|
this._timerId = null;
|
|
1826
|
+
/**
|
|
1827
|
+
* @type {symbol | null}
|
|
1828
|
+
*/
|
|
1829
|
+
this._loopId = null;
|
|
1826
1830
|
}
|
|
1827
1831
|
|
|
1828
1832
|
/**
|
|
@@ -1831,8 +1835,17 @@ class IntervalTimer {
|
|
|
1831
1835
|
*/
|
|
1832
1836
|
start() {
|
|
1833
1837
|
this.stop();
|
|
1838
|
+
|
|
1839
|
+
const curLoopId = Symbol();
|
|
1840
|
+
this._loopId = curLoopId;
|
|
1841
|
+
|
|
1834
1842
|
const loop = () => {
|
|
1843
|
+
if (this._loopId !== curLoopId) return;
|
|
1844
|
+
|
|
1835
1845
|
this._fn(); // 执行业务
|
|
1846
|
+
|
|
1847
|
+
if (this._loopId !== curLoopId) return;
|
|
1848
|
+
|
|
1836
1849
|
this._timerId = setTimeout(loop, this._ms);
|
|
1837
1850
|
};
|
|
1838
1851
|
loop(); // 立即执行第一次
|
|
@@ -1842,6 +1855,7 @@ class IntervalTimer {
|
|
|
1842
1855
|
* 停止定时器。
|
|
1843
1856
|
*/
|
|
1844
1857
|
stop() {
|
|
1858
|
+
this._loopId = null;
|
|
1845
1859
|
if (this._timerId !== null) {
|
|
1846
1860
|
clearTimeout(this._timerId);
|
|
1847
1861
|
this._timerId = null;
|
|
@@ -2094,6 +2108,181 @@ function findTreeNodePath(nodes, targetValue, key = "id", parentKey = "pid", chi
|
|
|
2094
2108
|
}
|
|
2095
2109
|
|
|
2096
2110
|
return path.reverse();
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
/**
|
|
2114
|
+
* 处理函数的返回值类型,用于控制节点是否添加。
|
|
2115
|
+
* @typedef {Object} TransformTreeDataWithExtra_HandlerResult
|
|
2116
|
+
* @property {boolean} [isAdd] - 是否将该节点添加到树中。如果为 false,则过滤掉该节点。
|
|
2117
|
+
*/
|
|
2118
|
+
|
|
2119
|
+
/**
|
|
2120
|
+
* 最终输出的树形结构的字段配置。
|
|
2121
|
+
* @typedef {Object} TransformTreeDataWithExtra_TreeDataOption
|
|
2122
|
+
* @property {string} [idKey="key"] - 最终树节点的唯一标识字段名。
|
|
2123
|
+
* @property {string} [titleKey="title"] - 最终树节点的标题显示字段名。
|
|
2124
|
+
* @property {string} [childrenKey="children"] - 最终树节点的子节点列表字段名。
|
|
2125
|
+
*/
|
|
2126
|
+
|
|
2127
|
+
/**
|
|
2128
|
+
* 主数据(父节点)的相关配置选项。
|
|
2129
|
+
* @typedef {Object} TransformTreeDataWithExtra_NodeOption
|
|
2130
|
+
* @property {string} [idPrefix] - 节点 ID 的前缀。
|
|
2131
|
+
* @property {string} [idKey="id"] - 原始数据中作为唯一标识的字段名。
|
|
2132
|
+
* @property {string} [titleKey="name"] - 原始数据中作为标题的字段名。
|
|
2133
|
+
* @property {string} [childrenKey="children"] - 原始数据中子节点列表的字段名。
|
|
2134
|
+
* @property {Record<string, any>} [assignData] - 需要额外合并到每个树节点上的静态属性。
|
|
2135
|
+
* @property {string} [rawDataKey] - 如果提供,会将原始节点数据对象挂载到树节点的此字段下。
|
|
2136
|
+
* @property {Object<string, any>} [nodeDataId2Obj] - (副作用) 引用传递的对象,用于建立 id -> 原始数据的映射。
|
|
2137
|
+
* @property {function(object, object): TransformTreeDataWithExtra_HandlerResult | void} [nodeDataHandler] - 对每个主节点进行处理的回调函数。
|
|
2138
|
+
*/
|
|
2139
|
+
|
|
2140
|
+
/**
|
|
2141
|
+
* 额外数据(子节点)的相关配置选项。
|
|
2142
|
+
* @typedef {Object} TransformTreeDataWithExtra_ExtraOption
|
|
2143
|
+
* @property {string} [idPrefix] - 额外节点 ID 的前缀。
|
|
2144
|
+
* @property {string} [idKey="id"] - 额外数据中作为唯一标识的字段名。
|
|
2145
|
+
* @property {string} [titleKey="name"] - 额外数据中作为标题的字段名。
|
|
2146
|
+
* @property {string} [childrenKey="extraChildren"] - 在主节点上查找额外数据列表的字段名。
|
|
2147
|
+
* @property {Record<string, any>} [assignData] - 需要额外合并到每个额外树节点上的静态属性。
|
|
2148
|
+
* @property {string} [rawDataKey] - 如果提供,会将原始额外数据对象挂载到树节点的此字段下。
|
|
2149
|
+
* @property {Object<string, any>} [extraDataId2Obj] - (副作用) 引用传递的对象,用于建立 id -> 额外数据的映射。
|
|
2150
|
+
* @property {function(object, object, object): TransformTreeDataWithExtra_HandlerResult | void} [extraDataHandler] - 对每个额外节点进行处理的回调函数。
|
|
2151
|
+
*/
|
|
2152
|
+
|
|
2153
|
+
/**
|
|
2154
|
+
* 将平铺或嵌套的原始数据转换为标准树形结构。
|
|
2155
|
+
* 支持将外部“额外数据”节点作为子节点插入到主节点层级中。
|
|
2156
|
+
* 支持自定义字段映射、ID 前缀、数据挂载以及通过回调函数过滤节点。
|
|
2157
|
+
*
|
|
2158
|
+
* @template T
|
|
2159
|
+
* @param {Array<T>} data - 原始数据数组。
|
|
2160
|
+
* @param {TransformTreeDataWithExtra_ExtraOption} [extraOption] - 额外数据(子节点)的相关配置选项。
|
|
2161
|
+
* @param {TransformTreeDataWithExtra_NodeOption} [nodeOption] - 主数据(父节点)的相关配置选项。
|
|
2162
|
+
* @param {TransformTreeDataWithExtra_TreeDataOption} [treeDataOption] - 最终输出的树形结构的字段配置选项。
|
|
2163
|
+
* @returns {Array<object>} 转换后的树形数据数组。
|
|
2164
|
+
*/
|
|
2165
|
+
function transformTreeDataWithExtra(data, extraOption = {}, nodeOption = {}, treeDataOption = {}) {
|
|
2166
|
+
const { idPrefix: nodeIdPrefix, idKey: nodeIdKey = "id", titleKey: nodeTitleKey = "name", childrenKey: nodeChildrenKey = "children", assignData: nodeAssignData = {}, rawDataKey: nodeRawDataKey, nodeDataId2Obj, nodeDataHandler } = nodeOption;
|
|
2167
|
+
const { idPrefix: extraIdPrefix, idKey: extraIdKey = "id", titleKey: extraTitleKey = "name", childrenKey: extraChildrenKey = "extraChildren", assignData: extraAssignData = {}, rawDataKey: extraRawDataKey, extraDataId2Obj, extraDataHandler } = extraOption;
|
|
2168
|
+
|
|
2169
|
+
const { idKey: treeIdKey = "key", titleKey: treeTitleKey = "title", childrenKey: treeChildrenKey = "children" } = treeDataOption;
|
|
2170
|
+
|
|
2171
|
+
const transformNode = (node) => {
|
|
2172
|
+
const treeNode = {
|
|
2173
|
+
[treeIdKey]: isNonEmptyString(nodeIdPrefix) ? nodeIdPrefix + node[nodeIdKey] : node[nodeIdKey],
|
|
2174
|
+
[treeTitleKey]: node[nodeTitleKey],
|
|
2175
|
+
[treeChildrenKey]: [],
|
|
2176
|
+
...nodeAssignData
|
|
2177
|
+
};
|
|
2178
|
+
if (isNonEmptyString(nodeRawDataKey)) {
|
|
2179
|
+
treeNode[nodeRawDataKey] = node;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
if (Array.isArray(node[nodeChildrenKey]) && node[nodeChildrenKey].length > 0) {
|
|
2183
|
+
treeNode[treeChildrenKey] = node[nodeChildrenKey].map((child) => transformNode(child)).filter((child) => child !== null);
|
|
2184
|
+
}
|
|
2185
|
+
|
|
2186
|
+
if (Array.isArray(node[extraChildrenKey]) && node[extraChildrenKey].length > 0) {
|
|
2187
|
+
const isValidExtraDataId2Obj = typeof extraDataId2Obj === "object" && extraDataId2Obj !== null;
|
|
2188
|
+
const extraNodes = [];
|
|
2189
|
+
for (const extraItem of node[extraChildrenKey]) {
|
|
2190
|
+
if (isValidExtraDataId2Obj) {
|
|
2191
|
+
extraDataId2Obj[extraItem[extraIdKey]] = extraItem;
|
|
2192
|
+
}
|
|
2193
|
+
const extraNode = {
|
|
2194
|
+
[treeIdKey]: isNonEmptyString(extraIdPrefix) ? extraIdPrefix + extraItem[extraIdKey] : extraItem[extraIdKey],
|
|
2195
|
+
[treeTitleKey]: extraItem[extraTitleKey],
|
|
2196
|
+
[treeChildrenKey]: [],
|
|
2197
|
+
...extraAssignData
|
|
2198
|
+
};
|
|
2199
|
+
if (isNonEmptyString(extraRawDataKey)) {
|
|
2200
|
+
extraNode[extraRawDataKey] = extraItem;
|
|
2201
|
+
}
|
|
2202
|
+
if (typeof extraDataHandler === "function") {
|
|
2203
|
+
const result = extraDataHandler(extraNode, extraItem, node);
|
|
2204
|
+
if (result?.isAdd === false) continue;
|
|
2205
|
+
}
|
|
2206
|
+
extraNodes.push(extraNode);
|
|
2207
|
+
}
|
|
2208
|
+
treeNode[treeChildrenKey] = [...treeNode[treeChildrenKey], ...extraNodes];
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
if (typeof nodeDataId2Obj === "object" && nodeDataId2Obj !== null) {
|
|
2212
|
+
nodeDataId2Obj[node[nodeIdKey]] = node;
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
if (typeof nodeDataHandler === "function") {
|
|
2216
|
+
const result = nodeDataHandler(treeNode, node);
|
|
2217
|
+
if (result?.isAdd === false) {
|
|
2218
|
+
return null;
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
return treeNode;
|
|
2223
|
+
};
|
|
2224
|
+
|
|
2225
|
+
return data.map((item) => transformNode(item)).filter((item) => item !== null);
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
/**
|
|
2229
|
+
* 自定义过滤函数的类型定义。
|
|
2230
|
+
* @callback FilterTreeData_FilterFn
|
|
2231
|
+
* @param {object} node - 当前遍历到的树节点对象。
|
|
2232
|
+
* @param {string | number} filterValue - 当前用于过滤的值。
|
|
2233
|
+
* @param {Array<object>} [children] - 当前节点的子节点数组(原始数据)。
|
|
2234
|
+
* @returns {boolean} 返回 true 表示保留该节点,false 表示过滤掉。
|
|
2235
|
+
*/
|
|
2236
|
+
|
|
2237
|
+
/**
|
|
2238
|
+
* 递归过滤树形数据。
|
|
2239
|
+
*
|
|
2240
|
+
* 该函数会保留符合条件的节点。特别地,**即使当前节点本身不匹配条件,只要其子孙节点中有匹配项,该节点也会被保留**,
|
|
2241
|
+
* 从而保证过滤后的树结构能展示出匹配节点的完整路径。
|
|
2242
|
+
*
|
|
2243
|
+
* @template T
|
|
2244
|
+
* @param {Array<T>} treeData - 源树形数据数组。
|
|
2245
|
+
* @param {string | number} filterValue - 用于过滤的关键字。
|
|
2246
|
+
* @param {string} [filterKey="name"] - 节点对象中用于匹配的字段名。默认为 "name"。如果提供了 filterFn 则此项无效。
|
|
2247
|
+
* @param {string} [childrenKey="children"] - 节点对象中存储子数组的字段名。默认为 "children"。
|
|
2248
|
+
* @param {FilterTreeData_FilterFn} [filterFn] - 自定义过滤函数。如果提供,将忽略 filterKey,使用此函数的返回值判断是否匹配。
|
|
2249
|
+
* @returns {Array<T>} 过滤后的新树形数据数组。注意:返回的是节点对象的浅拷贝。
|
|
2250
|
+
*/
|
|
2251
|
+
function filterTreeData(treeData, filterValue, filterKey = "name", childrenKey = "children", filterFn) {
|
|
2252
|
+
if (!Array.isArray(treeData) || treeData.length === 0) {
|
|
2253
|
+
return [];
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
if (filterValue == null || filterValue === "") {
|
|
2257
|
+
return treeData.map((node) => ({ ...node }));
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
const result = [];
|
|
2261
|
+
|
|
2262
|
+
for (const node of treeData) {
|
|
2263
|
+
const newNode = { ...node };
|
|
2264
|
+
const children = node[childrenKey];
|
|
2265
|
+
|
|
2266
|
+
// 后代节点
|
|
2267
|
+
let isDescendantMatch = false;
|
|
2268
|
+
if (Array.isArray(children)) {
|
|
2269
|
+
const newChildren = filterTreeData(children, filterValue, filterKey, childrenKey, filterFn);
|
|
2270
|
+
newNode[childrenKey] = newChildren;
|
|
2271
|
+
isDescendantMatch = newChildren.length > 0;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
if (isDescendantMatch) {
|
|
2275
|
+
result.push(newNode);
|
|
2276
|
+
} else {
|
|
2277
|
+
// 当前节点
|
|
2278
|
+
const isMatch = typeof filterFn === "function" ? filterFn(node, filterValue, children) : node[filterKey]?.toString().includes(filterValue);
|
|
2279
|
+
|
|
2280
|
+
if (isMatch) {
|
|
2281
|
+
result.push(newNode);
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
return result;
|
|
2097
2286
|
}
|
|
2098
2287
|
|
|
2099
2288
|
/**
|
|
@@ -2518,6 +2707,7 @@ exports.downloadExcel = downloadExcel;
|
|
|
2518
2707
|
exports.downloadJSON = downloadJSON;
|
|
2519
2708
|
exports.extractFullyCheckedKeys = extractFullyCheckedKeys;
|
|
2520
2709
|
exports.fetchOrDownloadByUrl = fetchOrDownloadByUrl;
|
|
2710
|
+
exports.filterTreeData = filterTreeData;
|
|
2521
2711
|
exports.findObjAttrValueById = findObjAttrValueById;
|
|
2522
2712
|
exports.findTreeNodeById = findTreeNodeById;
|
|
2523
2713
|
exports.findTreeNodePath = findTreeNodePath;
|
|
@@ -2535,7 +2725,7 @@ exports.handleDbMenuItems = handleDbMenuItems;
|
|
|
2535
2725
|
exports.isBlob = isBlob;
|
|
2536
2726
|
exports.isDate = isDate;
|
|
2537
2727
|
exports.isFunction = isFunction;
|
|
2538
|
-
exports.isNonEmptyString = isNonEmptyString;
|
|
2728
|
+
exports.isNonEmptyString = isNonEmptyString$1;
|
|
2539
2729
|
exports.isPlainObject = isPlainObject;
|
|
2540
2730
|
exports.isPromise = isPromise;
|
|
2541
2731
|
exports.millisecond2Duration = millisecond2Duration;
|
|
@@ -2556,4 +2746,5 @@ exports.second2DurationMaxHour = second2DurationMaxHour;
|
|
|
2556
2746
|
exports.shuffle = shuffle;
|
|
2557
2747
|
exports.throttle = throttle;
|
|
2558
2748
|
exports.toDate = toDate;
|
|
2749
|
+
exports.transformTreeDataWithExtra = transformTreeDataWithExtra;
|
|
2559
2750
|
//# sourceMappingURL=a2bei4.utils.cjs.js.map
|