import { Variables } from '@/constants/vars' ; import { HeaderDateUnit } from '@/typings/ParamOptions' ; import { addIfNotExist , uuid } from '@/utils/common' ; import { compareDate , createDate , getDateOffset , getMillisecond } from '@/utils/date' ; import { isArray , isDeepEqual , isObject } from '@/utils/is' ; export class Row { /**
     * 当前数据唯一 ID
     */ readonly uuid : string ; /**
     * 该数据索引位置
     */ index : number ; /**
     * 当前数据的父级路径集合
     */ parentId : number [ ] ; /**
     * 父级节点
     */ parentNode : Row | null ; /**
     * 层级
     */ level : number ; /**
     * 子节点
     */ children : Row [ ] ; /**
     * 数据属性
     */ options : DataOptions & { sl ? : string ; el ? : string ; } ; /**
     * 该数据在展开状态下的索引位置，仅用于渲染
     */ __uindex : number ; private __data : any ; private __isExpand : boolean ; private __isChecked : boolean ; constructor ( ) { this . uuid = uuid ( 12 ) ; this . __data = null ; this . index = 0 ; this . parentId = [ ] ; this . parentNode = null ; this . level = 0 ; this . __isExpand = true ; this . __isChecked = false ; this . children = [ ] ; this . options = { } ; this . __uindex = 0 ; } /**
     * 原始数据
     */ get data ( ) { return this . __data ; } /**
     * 是否展开
     */ get isExpand ( ) { return this . __isExpand ; } /**
     * 是否选中
     */ get isChecked ( ) { return this . __isChecked ; } /**
     * 起始时间
     */ get start ( ) { return createDate ( this . __data [ this . options . sl as string ] ) ; } /**
     * 截止时间
     */ get end ( ) { return createDate ( this . __data [ this . options . el as string ] ) ; } /**
     * 进度
     */ get progress ( ) { if ( this . children . length > 0 ) { let progress = 0 ; for ( const child of this . children ) { progress += child . progress ?? 0 ; } return progress / this . children . length ; } return this . __data . progress ?? 0 ; } setProgress ( v ) { if ( v < 0 ) this . __data . progress = 0 ; else if ( v > 1 ) this . __data . progress = 1 ; else this . __data . progress = v ; } param data param options initData ( data , options ) { const sl = options . startLabel || Variables . key . start ; const el = options . endLabel || Variables . key . end ; Object . assign ( this . options , { sl , el } ) ; this . __isExpand = this . options . isExpand || true ; this . __data = data ; } param obj returns isSame ( obj ) { return isDeepEqual ( obj , this . data ) ; } returns cloneData ( ) { return this . _clone ( this . data ) ; } _clone ( data ) { if ( ! isObject ( data ) ) { return data ; } const d = isArray ( data ) ? [ ] : ( { } as any ) ; for ( const i in data ) { d [ i ] = isObject ( data [ i ] ) ? this . _clone ( data [ i ] ) : data [ i ] ; } return d ; } param expand setExpand ( expand ) { this . __isExpand = expand ; } param checked param deep setChecked ( checked , deep = false ) { this . __isChecked = checked ; if ( deep ) { if ( this . children . length > 0 ) { for ( const child of this . children ) { child . setChecked ( checked , deep ) ; } } } } param date param unit param linkage setStart ( date , unit , linkage = false , modifyArr = [ ] ) { this . data [ this . options . sl as string ] = date ; if ( compareDate ( date , getDateOffset ( this . end as Date , - getMillisecond ( unit ) ) ) === 'r' ) this . data [ this . options . el as string ] = getDateOffset ( date , getMillisecond ( unit ) ) ; if ( ! linkage ) return ; let pNode = this . parentNode ; while ( pNode !== null ) { if ( compareDate ( this . start as Date , pNode . start as Date ) === 'l' ) { pNode . setStart ( this . start as Date , unit ) ; addIfNotExist < Row > ( modifyArr , pNode ) ; } else { break ; } pNode = pNode . parentNode ; } this . __setChildrenDate ( this , 'start' , unit , modifyArr ) ; } setEnd ( date , unit , linkage = false , modifyArr = [ ] ) { this . data [ this . options . el as string ] = date ; if ( compareDate ( date , getDateOffset ( this . start as Date , getMillisecond ( unit ) ) ) === 'l' ) this . data [ this . options . sl as string ] = getDateOffset ( date , - getMillisecond ( unit ) ) ; if ( ! linkage ) return ; let pNode = this . parentNode ; while ( pNode !== null ) { if ( compareDate ( this . end as Date , pNode . end as Date ) === 'r' ) { pNode . setEnd ( this . end as Date , unit ) ; addIfNotExist < Row > ( modifyArr , pNode ) ; } else { break ; } pNode = pNode . parentNode ; } this . __setChildrenDate ( this , 'end' , unit , modifyArr ) ; } /**
     * 逻辑上不需要子集联动。因为本身子集就不应该超过父级，这在创建内容时就应该避免。
     * 而且这里子集联动，会导致大量计算，如果数据很多，容易卡顿。
     * 并且，如果是分页，或者其他情况下数据不全，联动就没有意义。
     */ private __setChildrenDate ( node , key , unit , modifyArr ) { for ( let i = 0 ; i < node . children . length ; i ++ ) { const c = node . children [ i ] ; if ( key === 'start' ) { if ( compareDate ( c . start as Date , node . start as Date ) === 'l' ) { c . setStart ( node . start as Date , unit ) ; modifyArr . push ( c ) ; this . __setChildrenDate ( c , key , unit , modifyArr ) ; } } else if ( key === 'end' ) { if ( compareDate ( c . end as Date , node . end as Date ) === 'r' ) { c . setEnd ( node . end as Date , unit ) ; modifyArr . push ( c ) ; this . __setChildrenDate ( c , key , unit , modifyArr ) ; } } } } /**
     * 获取子项的展平状态
     */ getFlattenChildren ( ) { const arr = [ ] ; this . __getFlattenChildren ( arr ) ; arr . shift ( ) ; return arr ; } private __getFlattenChildren ( arr ) { arr . push ( this ) ; if ( this . children . length > 0 ) { for ( const child of this . children ) { child . __getFlattenChildren ( arr ) ; } } } } export default Row ;