UNPKG

ohayolibs

Version:

Ohayo is a set of essential modules for ohayojp.

226 lines (216 loc) 7.59 kB
import { Injectable } from '@angular/core'; import { NzTreeNode } from 'ng-zorro-antd/core/tree'; import { NzSafeAny } from 'ng-zorro-antd/core/types'; import { OhayoConfigService, OhayoUtilArrayConfig } from '../config'; export interface ArrayServiceTreeToArrOptions { /** 深度项名,默认:`'deep'` */ deepMapName?: string; /** 扁平后数组的父数据项名,默认:`'parent'` */ parentMapName?: string; /** 源数据子项名,默认:`'children'` */ childrenMapName?: string; /** 是否移除 `children` 节点,默认:`true` */ clearChildren?: boolean; /** 转换成数组结构时回调 */ cb?: (item: NzSafeAny, parent: NzSafeAny, deep: number) => void; } export interface ArrayServiceArrToTreeOptions { /** 编号项名,默认:`'id'` */ idMapName?: string; /** 父编号项名,默认:`'parent_id'` */ parentIdMapName?: string; /** 子项名,默认:`'children'` */ childrenMapName?: string; /** 转换成树数据时回调 */ cb?: (item: NzSafeAny) => void; } export interface ArrayServiceArrToTreeNodeOptions { /** 编号项名,默认:`'id'` */ idMapName?: string; /** 父编号项名,默认:`'parent_id'` */ parentIdMapName?: string; /** 标题项名,默认:`'title'` */ titleMapName?: string; /** 设置为叶子节点项名,若数据源不存在时自动根据 `children` 值决定是否为叶子节点,默认:`'isLeaf'` */ isLeafMapName?: string; /** 节点 Checkbox 是否选中项名,默认:`'checked'` */ checkedMapname?: string; /** 节点本身是否选中项名,默认:`'selected'` */ selectedMapname?: string; /** 节点是否展开(叶子节点无效)项名,默认:`'expanded'` */ expandedMapname?: string; /** 设置是否禁用节点(不可进行任何操作)项名,默认:`'disabled'` */ disabledMapname?: string; /** 转换成树数据后,执行的递归回调 */ cb?: (item: NzSafeAny, parent: NzSafeAny, deep: number) => void; } export interface ArrayServiceGetKeysByTreeNodeOptions { /** 是否包含半选状态的值,默认:`true` */ includeHalfChecked?: boolean; /** 是否重新指定 `key` 键名,若不指定表示使用 `NzTreeNode.key` 值 */ keyMapName?: string; /** 回调,返回一个值 `key` 值,优先级高于其他 */ cb?: (item: NzTreeNode, parent: NzTreeNode, deep: number) => NzSafeAny; } @Injectable({ providedIn: 'root' }) export class ArrayService { private c: OhayoUtilArrayConfig; constructor(cog: OhayoConfigService) { this.c = cog.merge('utilArray', { deepMapName: 'deep', parentMapName: 'parent', idMapName: 'id', parentIdMapName: 'parent_id', childrenMapName: 'children', titleMapName: 'title', checkedMapname: 'checked', selectedMapname: 'selected', expandedMapname: 'expanded', disabledMapname: 'disabled', })!; } /** * 将树结构转换成数组结构 */ treeToArr(tree: NzSafeAny[], options?: ArrayServiceTreeToArrOptions): NzSafeAny[] { const opt = { deepMapName: this.c.deepMapName, parentMapName: this.c.parentMapName, childrenMapName: this.c.childrenMapName, clearChildren: true, cb: null, ...options, } as ArrayServiceTreeToArrOptions; const result: NzSafeAny[] = []; const inFn = (list: NzSafeAny[], parent: NzSafeAny, deep: number = 0) => { for (const i of list) { i[opt.deepMapName!] = deep; i[opt.parentMapName!] = parent; if (opt.cb) { opt.cb(i, parent, deep); } result.push(i); const children = i[opt.childrenMapName!]; if (children != null && Array.isArray(children) && children.length > 0) { inFn(children, i, deep + 1); } if (opt.clearChildren) { delete i[opt.childrenMapName!]; } } }; inFn(tree, 1); return result; } /** * 数组转换成树数据 */ arrToTree(arr: NzSafeAny[], options?: ArrayServiceArrToTreeOptions): NzSafeAny[] { const opt = { idMapName: this.c.idMapName, parentIdMapName: this.c.parentIdMapName, childrenMapName: this.c.childrenMapName, cb: null, ...options, } as ArrayServiceArrToTreeOptions; const tree: NzSafeAny[] = []; const childrenOf: NzSafeAny = {}; for (const item of arr) { const id = item[opt.idMapName!]; const pid = item[opt.parentIdMapName!]; childrenOf[id] = childrenOf[id] || []; item[opt.childrenMapName!] = childrenOf[id]; if (opt.cb) { opt.cb(item); } if (pid) { childrenOf[pid] = childrenOf[pid] || []; childrenOf[pid].push(item); } else { tree.push(item); } } return tree; } /** * 数组转换成 `nz-tree` 数据源,通过 `options` 转化项名,也可以使用 `options.cb` 更高级决定数据项 */ arrToTreeNode(arr: NzSafeAny[], options?: ArrayServiceArrToTreeNodeOptions): NzTreeNode[] { const opt = { idMapName: this.c.idMapName, parentIdMapName: this.c.parentIdMapName, titleMapName: this.c.titleMapName, isLeafMapName: 'isLeaf', checkedMapname: this.c.checkedMapname, selectedMapname: this.c.selectedMapname, expandedMapname: this.c.expandedMapname, disabledMapname: this.c.disabledMapname, cb: null, ...options, } as ArrayServiceArrToTreeNodeOptions; const tree = this.arrToTree(arr, { idMapName: opt.idMapName, parentIdMapName: opt.parentIdMapName, childrenMapName: 'children', }); this.visitTree(tree, (item: NzSafeAny, parent: NzSafeAny, deep: number) => { item.key = item[opt.idMapName!]; item.title = item[opt.titleMapName!]; item.checked = item[opt.checkedMapname!]; item.selected = item[opt.selectedMapname!]; item.expanded = item[opt.expandedMapname!]; item.disabled = item[opt.disabledMapname!]; if (item[opt.isLeafMapName!] == null) { item.isLeaf = item.children.length === 0; } else { item.isLeaf = item[opt.isLeafMapName!]; } if (opt.cb) { opt.cb(item, parent, deep); } }); return tree.map(node => new NzTreeNode(node)); } /** * 递归访问整个树 */ visitTree( tree: NzSafeAny[], cb: (item: NzSafeAny, parent: NzSafeAny, deep: number) => void, options?: { /** 子项名,默认:`'children'` */ childrenMapName?: string; }, ): void { options = { childrenMapName: this.c.childrenMapName, ...options, }; const inFn = (data: NzSafeAny[], parent: NzSafeAny, deep: number) => { for (const item of data) { cb(item, parent, deep); const childrenVal = item[options!.childrenMapName!]; if (childrenVal && childrenVal.length > 0) { inFn(childrenVal, item, deep + 1); } } }; inFn(tree, null, 1); } /** * 获取所有已经选中的 `key` 值 */ getKeysByTreeNode(tree: NzTreeNode[], options?: ArrayServiceGetKeysByTreeNodeOptions): NzSafeAny[] { const opt = { includeHalfChecked: true, ...options, } as ArrayServiceGetKeysByTreeNodeOptions; const keys: NzSafeAny[] = []; this.visitTree(tree, (item: NzTreeNode, parent: NzTreeNode, deep: number) => { if (item.isChecked || (opt.includeHalfChecked && item.isHalfChecked)) { keys.push(opt.cb ? opt.cb(item, parent, deep) : opt.keyMapName ? item.origin[opt.keyMapName] : item.key); } }); return keys; } }