import React from "react"; import * as Tools from 'jad-tool'; export type OptionType = { key: string | number, title?: string, fullName?: (string)[], parent?: OptionType, children?: OptionType[], checked?: boolean, halfChecked?: boolean, checkable?: boolean, selectable?: boolean, disabled?: boolean, [propName: string]: any, }; export type PropsKeyValue = { propPValue: string, propValue: string, propName: string, } // tree => flat export function transform2FlatData(treeData: OptionType[], keyValue: PropsKeyValue, rootPid: string | number) { if (!treeData.length) return []; const { propPValue, propValue } = keyValue; let flatData = []; const tree2Flat = (data, pid) => data.map(e => { flatData[flatData.length] = e; flatData[flatData.length - 1][propPValue] = flatData[flatData.length - 1][propPValue] || pid; if (e['children'] && e['children'].length) { tree2Flat(e['children'], e[propValue]); } }); tree2Flat(treeData, rootPid).filter(e => e); return flatData; }; // flat => tree export const transform2TreeData = (flatData: OptionType[], keyValue: PropsKeyValue, rootPid: string | number) => { const { propPValue, propValue } = keyValue; if (!flatData.length) return []; const flat2Tree = (parentData: OptionType[], excptParentData: OptionType[], parent?: OptionType) => { return parentData.map(e => { const hasChildrenData = excptParentData.filter(d => d[propPValue] === e[propValue]); e['checked'] = e['checked'] || false; e['halfChecked'] = e['halfChecked'] || false; if (e && parent) e['parent'] = parent; if (hasChildrenData && hasChildrenData.length) e['children'] = flat2Tree(hasChildrenData, excptParentData, e); return e; }).filter(e => e); } return flat2Tree(flatData.filter(e => e[propPValue] === rootPid), flatData.filter(e => e[propPValue] !== rootPid)); }; // 根据 checkedKeys 初始化 options、optionsFlat、checkedOptions,更新其属性 checked、halfChecked 状态。传入的 checkedKeys 是数组类型,选中项集合 // 利用引用类型的特性 export function initOptions(options: OptionType[], checkedKeys: any[]) { const { propValue } = this.keyValue; const { rootPid } = this.props; if (!options || !options.length) { console.warn(`TreeSelectSearch initOptions options has some problems`) return { options: [], optionsFlat: [], checkedOptions: [] }; } if (!checkedKeys || !checkedKeys.length) { const newOptionsFlat = transform2FlatData(options, this.keyValue, rootPid); const newCheckedOptions = []; return { options: options, optionsFlat: newOptionsFlat, checkedOptions: newCheckedOptions }; } function walk(walkKeys: any[], walkOptions: OptionType[]) { walkOptions.forEach(item => { if (Tools.isExist(item[propValue]) && walkKeys.includes(item[propValue])) { onCheckHigh2Low(true, item) onCheckLow2High(true, item) } else if (Tools.isExist(item[propValue]) && !walkKeys.includes(item[propValue])) { if (item.children && item.children.length) { walk(walkKeys, item.children) } } else { console.error(`Please check: TreeSelectSearch initOptions walk item[propValue] which is ${item[propValue]}`) } }) } walk(checkedKeys, options); const newOptionsFlat = transform2FlatData(options, this.keyValue, rootPid); const newCheckedOptions = getCheckedTreeOptions(options); const newCheckedAllStatus = options.every(item => item['checked']); return { options: options, optionsFlat: newOptionsFlat, checkedOptions: newCheckedOptions, checkedAllStatus: newCheckedAllStatus }; } // 修改单个选项的状态 export function updateOption(checked: boolean, record: OptionType) { onCheckHigh2Low(checked, record) onCheckLow2High(checked, record) } // 从高到低 export function onCheckHigh2Low(checked: boolean, record: OptionType) { record['checked'] = checked; record['halfChecked'] = false; // 从高到低,halfChecked 其实可直接设置为 false 的值,不需要遍历 children 的 checked if (record['children'] && record['children'].length) { record['children'].forEach(child => { onCheckHigh2Low(checked, child) }) } } // 从低到高 export function onCheckLow2High(checked: boolean, record: OptionType) { record['checked'] = checked; if (!record['parent']) { return } else { let parentChildren = record['parent']['children'] || []; let flag = false; if (parentChildren.every(item => item.checked)) { flag = true; } if (!flag && parentChildren.some(item => item.checked || item.halfChecked)) { record['parent']['halfChecked'] = true; } else { record['parent']['halfChecked'] = false; } record['parent']['checked'] = flag; onCheckLow2High(flag, record['parent']) }; } // 获取已选中的树状结构 checkedTreeOptions export function getCheckedTreeOptions(options: OptionType[]) { let checkedTreeOptions; // tree (包含halfChecked === true || checked === true) function loop(data: OptionType[]) { const newData = data.filter(item => item.checked || item.halfChecked).map(obj => { if (obj['children'] && obj['children'].length && (!obj.checked && obj.halfChecked)) { // 有 children 且 并没有全选时 const children = loop(obj['children']) const newObj = { ...obj, children } return newObj } else return obj; }) return newData } checkedTreeOptions = loop(options) return checkedTreeOptions }