import * as Tools from "jad-tool"; export interface cascaderOptionsItemType extends initOptionsType { [propName:string]: any, level: number, checked: boolean, indeterminate: boolean, parent: cascaderOptionsItemType|undefined, children: cascaderOptionsItemType[] } export type initOptionsType = { [propName:string]: any, id:string|number, pid:string|number } export type cascaderConfigTtye = { initOptions?:initOptionsType[] propValue?:string propName?:string onCreateInitOptions?:()=>cascaderOptionsItemType[] selectMap?:{[propName:string]: any}[] } // 给 record 新增属性 fullName 代表完整层级 的 name export function getFullName(record: cascaderOptionsItemType, propName: string) { return record['fullName'] ? record['fullName'] : (record['parent'] ? [...record['parent']['fullName'], record[propName]] : [record[propName]]); } export class Cascader { private level:number private propValue:string private propName: string private maxLevel = 10; public options:cascaderOptionsItemType[] public flatOptions:cascaderOptionsItemType[] //平铺的数据结构,用于快速查找定位 public selectMap:cascaderOptionsItemType[] //当前选中的集合 constructor({ initOptions=[], onCreateInitOptions, propValue='value', propName='name', selectMap, }:cascaderConfigTtye){ this.propValue = propValue this.propName = propName this.options = onCreateInitOptions?onCreateInitOptions():this.initCreateOptions(initOptions,undefined,0) this.flatOptions = this.initFlatOptions( this.options ) this.selectMap = [] if(selectMap){ this.resetOptions(selectMap) } } //初始化options initCreateOptions(options:initOptionsType[],parent:cascaderOptionsItemType,level:number):cascaderOptionsItemType[]{ if(level > this.maxLevel){ throw new Error('Cascader initCreateOptions level 超过 maxLevel限制 ,请确保options.pid是否正确') } return options.filter(e=>{ const { pid } = e; if(!pid && !parent){ return true }else if(parent){ return pid === parent.id } return false; }).map(item=>{ var el = { ...item, level, indeterminate:false, checked:false, parent:parent, children:[] } if (!el['fullName']) { el['fullName'] = getFullName(el, this.propName) } el.children = this.initCreateOptions(options,el,level+1) return el }) } initFlatOptions(options:cascaderOptionsItemType[]):cascaderOptionsItemType[]{ return this.coolect(options) as cascaderOptionsItemType[] } //恢复options勾选 resetOptions(selectMap:{[propName:string]: any}|string[]){ selectMap.forEach(item => { const targetKey = Tools.isObject(item)?item[this.propValue]:Tools.toString(item) const target = this.flatOptions.find(e=>e[this.propValue] === targetKey) if(target){ this.activeSelect(true,target) } }); return this.selectMap } //激活选择 activeSelect(checked:boolean,record:cascaderOptionsItemType){ //这里是根据引用类型去修改显示状态的 this.handleSelectToLow(checked,record) this.handleSelectToHight(checked,record); this.selectMap = this.collectSelectMap(this.options) return this.selectMap } //获取数据 getCollectData(targetParams?:cascaderOptionsItemType){ if(!targetParams){ return this.options } const target = this.flatOptions.find(e=>e[this.propValue] === targetParams[this.propValue]) return (target && target.children)?target.children:[] } getFlatCollectData(){ return this.flatOptions } //处理相关选择 handleSelectToLow(checked:boolean,record:cascaderOptionsItemType){ record.checked=checked; if(!record.children) return checked; let arrs = record.children && record.children.reduce((prev,current)=>{ return prev=prev.concat( this.handleSelectToLow(checked,current) ) },[]) let flag =arrs.every(item=>item) let clear = !flag && arrs.every(item=>item===false) let someSelected = !flag && arrs.some(item=>item) if(flag || clear){ record.indeterminate=false; } if(someSelected && !clear){ record.indeterminate=true; } return checked } handleSelectToHight(checked:boolean,record:cascaderOptionsItemType){ record.checked=checked; if(!record.parent){ return }else{ let children = record.parent.children; let flag=false; if(children.every(item=>item.checked)){ flag = true; } if(!flag && children.some(item=>item.checked||item.indeterminate)){ record.parent.indeterminate=true; }else{ record.parent.indeterminate=false } record.parent.checked=flag; this.handleSelectToHight(flag,record.parent) }; } //收集的部分 coolect(record:cascaderOptionsItemType[]){ return record.reduce((prev,current)=>{ if(current.children && current.children.length){ prev.push(current) prev = prev.concat(this.initFlatOptions(current.children)) return prev } prev.push(current) return prev },[]) } collectSelectMap(record:cascaderOptionsItemType[]){ return record.reduce((prev,current)=>{ if(current.checked){ return prev.concat(current) }else if( current.indeterminate){ //后代部分选中 return prev.concat(this.collectSelectMap(current.children)) } return prev },[]) } collectChildren(record:cascaderOptionsItemType[]){ return record.reduce((prev,current)=>{ if(current.children && current.children.length){ //后代部分收集 return prev.concat(this.collectChildren(current.children)) } prev.push(current) return prev },[]) } }