166 lines
3.9 KiB
TypeScript
166 lines
3.9 KiB
TypeScript
import { $t } from '@/locales';
|
||
/**
|
||
* Transform record to option
|
||
*
|
||
* @example
|
||
* ```ts
|
||
* const record = {
|
||
* key1: 'label1',
|
||
* key2: 'label2'
|
||
* };
|
||
* const options = transformRecordToOption(record);
|
||
* // [
|
||
* // { value: 'key1', label: 'label1' },
|
||
* // { value: 'key2', label: 'label2' }
|
||
* // ]
|
||
* ```;
|
||
*
|
||
* @param record
|
||
*/
|
||
export function transformRecordToOption<T extends Record<string, string>>(record: T) {
|
||
return Object.entries(record).map(([value, label]) => ({
|
||
value,
|
||
label
|
||
})) as CommonType.Option<keyof T>[];
|
||
}
|
||
|
||
export function transformRecordToNumberOption<T extends Record<string, string>>(record: T) {
|
||
return Object.entries(record).map(([value, label]) => ({
|
||
value,
|
||
label
|
||
})) as CommonType.Option<keyof T>[];
|
||
}
|
||
|
||
/**
|
||
* Translate options
|
||
*
|
||
* @param options
|
||
*/
|
||
export function translateOptions(options: CommonType.Option<string>[]) {
|
||
return options.map(option => ({
|
||
...option,
|
||
label: $t(option.label as App.I18n.I18nKey)
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* Toggle html class
|
||
*
|
||
* @param className
|
||
*/
|
||
export function toggleHtmlClass(className: string) {
|
||
function add() {
|
||
document.documentElement.classList.add(className);
|
||
}
|
||
|
||
function remove() {
|
||
document.documentElement.classList.remove(className);
|
||
}
|
||
|
||
return {
|
||
add,
|
||
remove
|
||
};
|
||
}
|
||
|
||
/* 驼峰转换下划线 */
|
||
export function humpToLine(str: string, line: string = '-') {
|
||
let temp = str.replace(/[A-Z]/g, match => {
|
||
return `${line}${match.toLowerCase()}`;
|
||
});
|
||
// 如果首字母是大写,执行replace时会多一个_,这里需要去掉
|
||
if (temp.slice(0, 1) === line) {
|
||
temp = temp.slice(1);
|
||
}
|
||
return temp;
|
||
}
|
||
|
||
/** 判断是否为空 */
|
||
export function isNotNull(value: any) {
|
||
return value !== undefined && value !== null && value !== '' && value !== 'undefined' && value !== 'null';
|
||
}
|
||
|
||
/** 判断是否为空 */
|
||
export function isNull(value: any) {
|
||
return value === undefined || value === null || value === '' || value === 'undefined' || value === 'null';
|
||
}
|
||
|
||
/** 判断是否为图片类型 */
|
||
export function isImage(suffix: string) {
|
||
const imgSuffixList = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
|
||
return imgSuffixList.includes(suffix.toLowerCase());
|
||
}
|
||
|
||
/**
|
||
* 构造树型结构数据
|
||
*
|
||
* @param {T[]} data 数据源
|
||
* @param {TreeConfig} config 配置选项
|
||
* @returns {T[]} 树形结构数据
|
||
*/
|
||
export const handleTree = <T extends Record<string, any>>(data: T[], config: CommonType.TreeConfig): T[] => {
|
||
if (!data?.length) {
|
||
return [];
|
||
}
|
||
|
||
const {
|
||
idField,
|
||
parentIdField = 'parentId',
|
||
childrenField = 'children',
|
||
filterFn = () => true // 添加过滤函数,默认为不过滤
|
||
} = config;
|
||
|
||
// 使用 Map 替代普通对象,提高性能
|
||
const childrenMap = new Map<string | number, T[]>();
|
||
const nodeMap = new Map<string | number, T>();
|
||
const tree: T[] = [];
|
||
|
||
// 第一遍遍历:构建节点映射
|
||
for (const item of data) {
|
||
const id = item[idField];
|
||
const parentId = item[parentIdField];
|
||
|
||
nodeMap.set(id, item);
|
||
|
||
if (!childrenMap.has(parentId)) {
|
||
childrenMap.set(parentId, []);
|
||
}
|
||
// 应用过滤函数
|
||
if (filterFn(item)) {
|
||
childrenMap.get(parentId)!.push(item);
|
||
}
|
||
}
|
||
|
||
// 第二遍遍历:找出根节点
|
||
for (const item of data) {
|
||
const parentId = item[parentIdField];
|
||
if (!nodeMap.has(parentId) && filterFn(item)) {
|
||
tree.push(item);
|
||
}
|
||
}
|
||
|
||
// 递归构建树形结构
|
||
const buildTree = (node: T) => {
|
||
const id = node[idField];
|
||
const children = childrenMap.get(id);
|
||
|
||
if (children?.length) {
|
||
// 使用类型断言确保类型安全
|
||
(node as any)[childrenField] = children;
|
||
for (const child of children) {
|
||
buildTree(child);
|
||
}
|
||
} else {
|
||
// 如果没有子节点,设置为 undefined
|
||
(node as any)[childrenField] = undefined;
|
||
}
|
||
};
|
||
|
||
// 从根节点开始构建树
|
||
for (const root of tree) {
|
||
buildTree(root);
|
||
}
|
||
|
||
return tree;
|
||
};
|