virtual scroll of organization is implemented
This commit is contained in:
parent
241fd65d31
commit
50c8c2a02d
|
@ -33,10 +33,10 @@
|
||||||
.mat-tab-labels {
|
.mat-tab-labels {
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
height: 280px;
|
height: 280px;
|
||||||
padding-top:10px;
|
padding-top: 10px;
|
||||||
.mat-tab-label {
|
.mat-tab-label {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
padding:0 16px;
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mat-ink-bar {
|
.mat-ink-bar {
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transform: scale(0.9);
|
transform: scale(0.9);
|
||||||
transition: transform .3s cubic-bezier(.4,0,0,1);
|
transition: transform 0.3s cubic-bezier(0.4, 0, 0, 1);
|
||||||
|
|
||||||
svg {
|
svg {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
.mat-tab-label-content {
|
.mat-tab-label-content {
|
||||||
.icon-item {
|
.icon-item {
|
||||||
background: #ef4c73;
|
background: #ef4c73;
|
||||||
transform: scale(1.0);
|
transform: scale(1);
|
||||||
/*svg {
|
/*svg {
|
||||||
stroke: #ef4c73;
|
stroke: #ef4c73;
|
||||||
fill: #ef4c73;
|
fill: #ef4c73;
|
||||||
|
|
|
@ -71,7 +71,7 @@ export class GroupComponent implements OnInit, OnDestroy {
|
||||||
UserInfo | UserInfoSS | UserInfoF | UserInfoDN
|
UserInfo | UserInfoSS | UserInfoF | UserInfoDN
|
||||||
>();
|
>();
|
||||||
|
|
||||||
@ViewChild('groupExpansionPanel', { static: true })
|
@ViewChild('groupExpansionPanel', { static: false })
|
||||||
groupExpansionPanel: GroupExpansionPanelComponent;
|
groupExpansionPanel: GroupExpansionPanelComponent;
|
||||||
|
|
||||||
@ViewChild('profileContextMenuTrigger', { static: true })
|
@ViewChild('profileContextMenuTrigger', { static: true })
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
>
|
>
|
||||||
</ucap-organization-tenant-search>
|
</ucap-organization-tenant-search>
|
||||||
</div>
|
</div>
|
||||||
<div class="oraganization-tab" *ngIf="departmentInfoList$ | async">
|
<div class="oraganization-tab">
|
||||||
<div class="oraganization-tab-tree">
|
<div class="oraganization-tab-tree">
|
||||||
<ucap-organization-tree
|
<ucap-organization-tree
|
||||||
[oraganizationList]="departmentInfoList$ | async"
|
[oraganizationList]="departmentInfoList$ | async"
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
ElementRef,
|
ElementRef,
|
||||||
AfterViewInit,
|
AfterViewInit,
|
||||||
Output,
|
Output,
|
||||||
EventEmitter,
|
EventEmitter
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {
|
import {
|
||||||
ucapAnimations,
|
ucapAnimations,
|
||||||
|
@ -20,7 +20,7 @@ import {
|
||||||
AlertDialogData,
|
AlertDialogData,
|
||||||
AlertDialogResult,
|
AlertDialogResult,
|
||||||
FileUploadQueueComponent,
|
FileUploadQueueComponent,
|
||||||
StringUtil,
|
StringUtil
|
||||||
} from '@ucap-webmessenger/ui';
|
} from '@ucap-webmessenger/ui';
|
||||||
import { Store, select } from '@ngrx/store';
|
import { Store, select } from '@ngrx/store';
|
||||||
import { NGXLogger } from 'ngx-logger';
|
import { NGXLogger } from 'ngx-logger';
|
||||||
|
@ -33,7 +33,7 @@ import {
|
||||||
isRecallable,
|
isRecallable,
|
||||||
InfoResponse,
|
InfoResponse,
|
||||||
EventJson,
|
EventJson,
|
||||||
FileEventJson,
|
FileEventJson
|
||||||
} from '@ucap-webmessenger/protocol-event';
|
} from '@ucap-webmessenger/protocol-event';
|
||||||
|
|
||||||
import * as AppStore from '@app/store';
|
import * as AppStore from '@app/store';
|
||||||
|
@ -47,36 +47,36 @@ import {
|
||||||
EnvironmentsInfo,
|
EnvironmentsInfo,
|
||||||
KEY_ENVIRONMENTS_INFO,
|
KEY_ENVIRONMENTS_INFO,
|
||||||
UserSelectDialogType,
|
UserSelectDialogType,
|
||||||
RightDrawer,
|
RightDrawer
|
||||||
} from '@app/types';
|
} from '@app/types';
|
||||||
import { RoomInfo, UserInfo, RoomType } from '@ucap-webmessenger/protocol-room';
|
import { RoomInfo, UserInfo, RoomType } from '@ucap-webmessenger/protocol-room';
|
||||||
import { tap, take, map, catchError } from 'rxjs/operators';
|
import { tap, take, map, catchError } from 'rxjs/operators';
|
||||||
import {
|
import {
|
||||||
FileInfo,
|
FileInfo,
|
||||||
FormComponent as UCapUiChatFormComponent,
|
FormComponent as UCapUiChatFormComponent
|
||||||
} from '@ucap-webmessenger/ui-chat';
|
} from '@ucap-webmessenger/ui-chat';
|
||||||
import { KEY_VER_INFO } from '@app/types/ver-info.type';
|
import { KEY_VER_INFO } from '@app/types/ver-info.type';
|
||||||
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
||||||
import {
|
import {
|
||||||
MatMenuTrigger,
|
MatMenuTrigger,
|
||||||
MatSnackBarRef,
|
MatSnackBarRef,
|
||||||
SimpleSnackBar,
|
SimpleSnackBar
|
||||||
} from '@angular/material';
|
} from '@angular/material';
|
||||||
import {
|
import {
|
||||||
CommonApiService,
|
CommonApiService,
|
||||||
FileUploadItem,
|
FileUploadItem,
|
||||||
FileTalkSaveRequest,
|
FileTalkSaveRequest,
|
||||||
FileTalkSaveResponse,
|
FileTalkSaveResponse
|
||||||
} from '@ucap-webmessenger/api-common';
|
} from '@ucap-webmessenger/api-common';
|
||||||
import {
|
import {
|
||||||
CreateChatDialogComponent,
|
CreateChatDialogComponent,
|
||||||
CreateChatDialogData,
|
CreateChatDialogData,
|
||||||
CreateChatDialogResult,
|
CreateChatDialogResult
|
||||||
} from '../dialogs/chat/create-chat.dialog.component';
|
} from '../dialogs/chat/create-chat.dialog.component';
|
||||||
import {
|
import {
|
||||||
FileViewerDialogComponent,
|
FileViewerDialogComponent,
|
||||||
FileViewerDialogData,
|
FileViewerDialogData,
|
||||||
FileViewerDialogResult,
|
FileViewerDialogResult
|
||||||
} from '@app/layouts/common/dialogs/file-viewer.dialog.component';
|
} from '@app/layouts/common/dialogs/file-viewer.dialog.component';
|
||||||
import { CONST, FileUtil } from '@ucap-webmessenger/core';
|
import { CONST, FileUtil } from '@ucap-webmessenger/core';
|
||||||
import { PerfectScrollbarComponent } from 'ngx-perfect-scrollbar';
|
import { PerfectScrollbarComponent } from 'ngx-perfect-scrollbar';
|
||||||
|
@ -84,12 +84,12 @@ import { StatusCode } from '@ucap-webmessenger/api';
|
||||||
import {
|
import {
|
||||||
EditChatRoomDialogComponent,
|
EditChatRoomDialogComponent,
|
||||||
EditChatRoomDialogResult,
|
EditChatRoomDialogResult,
|
||||||
EditChatRoomDialogData,
|
EditChatRoomDialogData
|
||||||
} from '../dialogs/chat/edit-chat-room.dialog.component';
|
} from '../dialogs/chat/edit-chat-room.dialog.component';
|
||||||
import {
|
import {
|
||||||
SelectGroupDialogComponent,
|
SelectGroupDialogComponent,
|
||||||
SelectGroupDialogResult,
|
SelectGroupDialogResult,
|
||||||
SelectGroupDialogData,
|
SelectGroupDialogData
|
||||||
} from '../dialogs/group/select-group.dialog.component';
|
} from '../dialogs/group/select-group.dialog.component';
|
||||||
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
|
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
|
||||||
selector: 'app-layout-messenger-messages',
|
selector: 'app-layout-messenger-messages',
|
||||||
templateUrl: './messages.component.html',
|
templateUrl: './messages.component.html',
|
||||||
styleUrls: ['./messages.component.scss'],
|
styleUrls: ['./messages.component.scss'],
|
||||||
animations: ucapAnimations,
|
animations: ucapAnimations
|
||||||
})
|
})
|
||||||
export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
@Output()
|
@Output()
|
||||||
|
@ -379,7 +379,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
// duration: 3000,
|
// duration: 3000,
|
||||||
verticalPosition: 'bottom',
|
verticalPosition: 'bottom',
|
||||||
horizontalPosition: 'center',
|
horizontalPosition: 'center',
|
||||||
panelClass: ['chat-snackbar-class'],
|
panelClass: ['chat-snackbar-class']
|
||||||
});
|
});
|
||||||
this.snackBarPreviewEvent.onAction().subscribe(() => {
|
this.snackBarPreviewEvent.onAction().subscribe(() => {
|
||||||
this.setEventMoreInit();
|
this.setEventMoreInit();
|
||||||
|
@ -420,7 +420,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
EventStore.info({
|
EventStore.info({
|
||||||
roomSeq: this.roomInfo.roomSeq,
|
roomSeq: this.roomInfo.roomSeq,
|
||||||
baseSeq: seq,
|
baseSeq: seq,
|
||||||
requestCount: CONST.EVENT_INFO_READ_COUNT,
|
requestCount: CONST.EVENT_INFO_READ_COUNT
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -438,8 +438,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
width: '360px',
|
width: '360px',
|
||||||
data: {
|
data: {
|
||||||
title: 'Alert',
|
title: 'Alert',
|
||||||
message: `대화내용을 입력해주세요.`,
|
message: `대화내용을 입력해주세요.`
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -453,8 +453,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
roomSeq: this.roomInfo.roomSeq,
|
roomSeq: this.roomInfo.roomSeq,
|
||||||
eventType: EventType.MassText,
|
eventType: EventType.MassText,
|
||||||
// sentMessage: message.replace(/\n/gi, '\r\n')
|
// sentMessage: message.replace(/\n/gi, '\r\n')
|
||||||
sentMessage: message,
|
sentMessage: message
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
@ -464,8 +464,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
req: {
|
req: {
|
||||||
roomSeq: this.roomInfo.roomSeq,
|
roomSeq: this.roomInfo.roomSeq,
|
||||||
eventType: EventType.Character,
|
eventType: EventType.Character,
|
||||||
sentMessage: message,
|
sentMessage: message
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -479,7 +479,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
onMassDetail(value: number) {
|
onMassDetail(value: number) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
ChatStore.selectedMassDetail({
|
ChatStore.selectedMassDetail({
|
||||||
massEventSeq: value,
|
massEventSeq: value
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -491,7 +491,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
FileViewerDialogResult
|
FileViewerDialogResult
|
||||||
>(FileViewerDialogComponent, {
|
>(FileViewerDialogComponent, {
|
||||||
position: {
|
position: {
|
||||||
top: '30px',
|
top: '30px'
|
||||||
},
|
},
|
||||||
maxWidth: '100vw',
|
maxWidth: '100vw',
|
||||||
maxHeight: '100vh',
|
maxHeight: '100vh',
|
||||||
|
@ -504,8 +504,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
downloadUrl: this.sessionVerInfo.downloadUrl,
|
downloadUrl: this.sessionVerInfo.downloadUrl,
|
||||||
deviceType: this.environmentsInfo.deviceType,
|
deviceType: this.environmentsInfo.deviceType,
|
||||||
token: this.loginRes.tokenString,
|
token: this.loginRes.tokenString,
|
||||||
userSeq: this.loginRes.userSeq,
|
userSeq: this.loginRes.userSeq
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +531,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
|
|
||||||
const info = {
|
const info = {
|
||||||
senderSeq: this.loginRes.userSeq,
|
senderSeq: this.loginRes.userSeq,
|
||||||
roomSeq: this.roomInfo.roomSeq,
|
roomSeq: this.roomInfo.roomSeq
|
||||||
};
|
};
|
||||||
|
|
||||||
const allObservables: Observable<FileTalkSaveResponse>[] = [];
|
const allObservables: Observable<FileTalkSaveResponse>[] = [];
|
||||||
|
@ -552,7 +552,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
'rv',
|
'rv',
|
||||||
'ts',
|
'ts',
|
||||||
'webm',
|
'webm',
|
||||||
'wmv',
|
'wmv'
|
||||||
].indexOf(FileUtil.getExtension(fileUploadItem.file.name))
|
].indexOf(FileUtil.getExtension(fileUploadItem.file.name))
|
||||||
) {
|
) {
|
||||||
thumbnail = await FileUtil.thumbnail(fileUploadItem.file);
|
thumbnail = await FileUtil.thumbnail(fileUploadItem.file);
|
||||||
|
@ -567,7 +567,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
file: fileUploadItem.file,
|
file: fileUploadItem.file,
|
||||||
fileName: fileUploadItem.file.name,
|
fileName: fileUploadItem.file.name,
|
||||||
thumb: thumbnail,
|
thumb: thumbnail,
|
||||||
fileUploadItem,
|
fileUploadItem
|
||||||
};
|
};
|
||||||
|
|
||||||
allObservables.push(
|
allObservables.push(
|
||||||
|
@ -599,8 +599,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
req: {
|
req: {
|
||||||
roomSeq: info.roomSeq,
|
roomSeq: info.roomSeq,
|
||||||
eventType: EventType.File,
|
eventType: EventType.File,
|
||||||
sentMessage: res.returnJson,
|
sentMessage: res.returnJson
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -626,7 +626,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.messageContextMenuTrigger.menu.focusFirstItem('mouse');
|
this.messageContextMenuTrigger.menu.focusFirstItem('mouse');
|
||||||
this.messageContextMenuTrigger.menuData = {
|
this.messageContextMenuTrigger.menuData = {
|
||||||
message: params.message,
|
message: params.message,
|
||||||
loginRes: this.loginRes,
|
loginRes: this.loginRes
|
||||||
};
|
};
|
||||||
this.messageContextMenuTrigger.openMenu();
|
this.messageContextMenuTrigger.openMenu();
|
||||||
}
|
}
|
||||||
|
@ -646,7 +646,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.snackBarService.open('클립보드에 복사되었습니다.', '', {
|
this.snackBarService.open('클립보드에 복사되었습니다.', '', {
|
||||||
duration: 3000,
|
duration: 3000,
|
||||||
verticalPosition: 'top',
|
verticalPosition: 'top',
|
||||||
horizontalPosition: 'center',
|
horizontalPosition: 'center'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -658,7 +658,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
userSeq: this.loginRes.userSeq,
|
userSeq: this.loginRes.userSeq,
|
||||||
deviceType: this.environmentsInfo.deviceType,
|
deviceType: this.environmentsInfo.deviceType,
|
||||||
token: this.loginRes.tokenString,
|
token: this.loginRes.tokenString,
|
||||||
eventMassSeq: message.seq,
|
eventMassSeq: message.seq
|
||||||
})
|
})
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe(res => {
|
.subscribe(res => {
|
||||||
|
@ -669,7 +669,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
{
|
{
|
||||||
duration: 3000,
|
duration: 3000,
|
||||||
verticalPosition: 'top',
|
verticalPosition: 'top',
|
||||||
horizontalPosition: 'center',
|
horizontalPosition: 'center'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -693,8 +693,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
data: {
|
data: {
|
||||||
type: UserSelectDialogType.MessageForward,
|
type: UserSelectDialogType.MessageForward,
|
||||||
title: 'MessageForward',
|
title: 'MessageForward',
|
||||||
ignoreRoom: [this.roomInfo],
|
ignoreRoom: [this.roomInfo]
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!result && !!result.choice && result.choice) {
|
if (!!result && !!result.choice && result.choice) {
|
||||||
|
@ -718,10 +718,10 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
req: {
|
req: {
|
||||||
roomSeq: '-999',
|
roomSeq: '-999',
|
||||||
eventType: message.type,
|
eventType: message.type,
|
||||||
sentMessage: message.sentMessage,
|
sentMessage: message.sentMessage
|
||||||
},
|
},
|
||||||
trgtUserSeqs: userSeqs,
|
trgtUserSeqs: userSeqs,
|
||||||
trgtRoomSeq: roomSeq,
|
trgtRoomSeq: roomSeq
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -737,9 +737,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
req: {
|
req: {
|
||||||
roomSeq: '-999',
|
roomSeq: '-999',
|
||||||
eventType: message.type,
|
eventType: message.type,
|
||||||
sentMessage: message.sentMessage,
|
sentMessage: message.sentMessage
|
||||||
},
|
},
|
||||||
trgtUserSeqs: [this.loginRes.talkWithMeBotSeq],
|
trgtUserSeqs: [this.loginRes.talkWithMeBotSeq]
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -755,15 +755,15 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
width: '220px',
|
width: '220px',
|
||||||
data: {
|
data: {
|
||||||
title: 'Delete',
|
title: 'Delete',
|
||||||
html: `선택한 메시지를 삭제하시겠습니까?<br/>삭제된 메시지는 내 대화방에서만 적용되며 상대방의 대화방에서는 삭제되지 않습니다.`,
|
html: `선택한 메시지를 삭제하시겠습니까?<br/>삭제된 메시지는 내 대화방에서만 적용되며 상대방의 대화방에서는 삭제되지 않습니다.`
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!result && !!result.choice && result.choice) {
|
if (!!result && !!result.choice && result.choice) {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
EventStore.del({
|
EventStore.del({
|
||||||
roomSeq: this.roomInfo.roomSeq,
|
roomSeq: this.roomInfo.roomSeq,
|
||||||
eventSeq: message.seq,
|
eventSeq: message.seq
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -779,8 +779,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
width: '220px',
|
width: '220px',
|
||||||
data: {
|
data: {
|
||||||
title: 'ReCall',
|
title: 'ReCall',
|
||||||
html: `해당 대화를 회수하시겠습니까?<br/>상대방 대화창에서도 회수됩니다.`,
|
html: `해당 대화를 회수하시겠습니까?<br/>상대방 대화창에서도 회수됩니다.`
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!result && !!result.choice && result.choice) {
|
if (!!result && !!result.choice && result.choice) {
|
||||||
|
@ -788,7 +788,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
EventStore.cancel({
|
EventStore.cancel({
|
||||||
roomSeq: this.roomInfo.roomSeq,
|
roomSeq: this.roomInfo.roomSeq,
|
||||||
eventSeq: message.seq,
|
eventSeq: message.seq,
|
||||||
deviceType: this.environmentsInfo.deviceType,
|
deviceType: this.environmentsInfo.deviceType
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -805,7 +805,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
{
|
{
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
ChatStore.selectedRightDrawer({
|
ChatStore.selectedRightDrawer({
|
||||||
req: RightDrawer.AlbumBox,
|
req: RightDrawer.AlbumBox
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -814,7 +814,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
{
|
{
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
ChatStore.selectedRightDrawer({
|
ChatStore.selectedRightDrawer({
|
||||||
req: RightDrawer.FileBox,
|
req: RightDrawer.FileBox
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -823,7 +823,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
{
|
{
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
ChatStore.selectedRightDrawer({
|
ChatStore.selectedRightDrawer({
|
||||||
req: RightDrawer.RoomUser,
|
req: RightDrawer.RoomUser
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -841,8 +841,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
title: 'Edit Chat Member',
|
title: 'Edit Chat Member',
|
||||||
curRoomUser: this.userInfoList.filter(
|
curRoomUser: this.userInfoList.filter(
|
||||||
user => user.seq !== this.loginRes.userSeq
|
user => user.seq !== this.loginRes.userSeq
|
||||||
),
|
)
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!result && !!result.choice && result.choice) {
|
if (!!result && !!result.choice && result.choice) {
|
||||||
|
@ -864,8 +864,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
RoomStore.inviteOrOpen({
|
RoomStore.inviteOrOpen({
|
||||||
req: {
|
req: {
|
||||||
divCd: 'Invite',
|
divCd: 'Invite',
|
||||||
userSeqs,
|
userSeqs
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -881,8 +881,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
>(SelectGroupDialogComponent, {
|
>(SelectGroupDialogComponent, {
|
||||||
width: '600px',
|
width: '600px',
|
||||||
data: {
|
data: {
|
||||||
title: 'Group Select',
|
title: 'Group Select'
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!result && !!result.choice && result.choice) {
|
if (!!result && !!result.choice && result.choice) {
|
||||||
|
@ -899,7 +899,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
SyncStore.updateGroupMember({
|
SyncStore.updateGroupMember({
|
||||||
oldGroup,
|
oldGroup,
|
||||||
trgtUserSeq,
|
trgtUserSeq
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -916,8 +916,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
width: '600px',
|
width: '600px',
|
||||||
data: {
|
data: {
|
||||||
title: 'Edit Chat Room',
|
title: 'Edit Chat Room',
|
||||||
roomInfo: this.roomInfo,
|
roomInfo: this.roomInfo
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!result && !!result.choice && result.choice) {
|
if (!!result && !!result.choice && result.choice) {
|
||||||
|
@ -934,8 +934,8 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
roomName,
|
roomName,
|
||||||
receiveAlarm: roomInfo.receiveAlarm,
|
receiveAlarm: roomInfo.receiveAlarm,
|
||||||
syncAll:
|
syncAll:
|
||||||
roomNameChangeTarget.toUpperCase() === 'ALL' ? true : false,
|
roomNameChangeTarget.toUpperCase() === 'ALL' ? true : false
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -947,7 +947,7 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
|
||||||
this.store.dispatch(
|
this.store.dispatch(
|
||||||
RoomStore.updateTimeRoomInterval({
|
RoomStore.updateTimeRoomInterval({
|
||||||
roomSeq: roomInfo.roomSeq,
|
roomSeq: roomInfo.roomSeq,
|
||||||
timerInterval: timeRoomInterval,
|
timerInterval: timeRoomInterval
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="chat-messages">
|
<div class="chat-messages" #scrollMe>
|
||||||
<!-- <div class="message-row" *ngIf="eventRemain">
|
<!-- <div class="message-row" *ngIf="eventRemain">
|
||||||
<button mat-button (click)="onClickMore($event)">이전 대화 보기</button>
|
<button mat-button (click)="onClickMore($event)">이전 대화 보기</button>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
|
|
@ -1,41 +1,54 @@
|
||||||
<mat-tree
|
<cdk-virtual-scroll-viewport #cvsvOrganization itemSize="48" fxFlexFill>
|
||||||
#orgranizationTree
|
<ng-container
|
||||||
[dataSource]="dataSource"
|
*cdkVirtualFor="let node of dataSource.expandedData$"
|
||||||
[treeControl]="treeControl"
|
></ng-container>
|
||||||
class="organization-tree"
|
<mat-tree
|
||||||
>
|
#orgranizationTree
|
||||||
<mat-nested-tree-node *matTreeNodeDef="let node">
|
[dataSource]="dataSource"
|
||||||
<li>
|
[treeControl]="treeControl"
|
||||||
<div class="mat-tree-node" (click)="onClickNode(node)">
|
class="organization-tree"
|
||||||
{{ node.title }}
|
>
|
||||||
</div>
|
<!-- This is the tree node template for leaf nodes -->
|
||||||
</li>
|
<mat-tree-node *matTreeNodeDef="let node" matTreeNodePadding>
|
||||||
</mat-nested-tree-node>
|
<li>
|
||||||
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasChildren" class="tree-node-frame">
|
<div class="mat-tree-node" (click)="onClickNode(node)">
|
||||||
<li>
|
{{ node.name }}
|
||||||
<div class="mat-tree-node" (click)="onClickNode(node)" class="path">
|
|
||||||
<span class="horizontal-line"></span>
|
|
||||||
<button
|
|
||||||
mat-icon-button
|
|
||||||
color="accent"
|
|
||||||
matTreeNodeToggle
|
|
||||||
[attr.aria-label]="'toggle ' + node.filename"
|
|
||||||
>
|
|
||||||
<mat-icon class="mat-icon-rtl-mirror">
|
|
||||||
<!-- {{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}-->
|
|
||||||
{{ treeControl.isExpanded(node) ? 'remove' : 'add' }}
|
|
||||||
</mat-icon>
|
|
||||||
</button>
|
|
||||||
<span class="dept-name">{{ node.title }}</span>
|
|
||||||
</div>
|
|
||||||
<ul
|
|
||||||
[class.organization-tree-node-invisible]="!treeControl.isExpanded(node)"
|
|
||||||
>
|
|
||||||
<div *ngIf="treeControl.isExpanded(node)" class="boxnone">
|
|
||||||
<div class="vertical-line"></div>
|
|
||||||
<ng-container matTreeNodeOutlet></ng-container>
|
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
</li>
|
||||||
</li>
|
</mat-tree-node>
|
||||||
</mat-nested-tree-node>
|
<!-- This is the tree node template for expandable nodes -->
|
||||||
</mat-tree>
|
<mat-tree-node
|
||||||
|
*matTreeNodeDef="let node; when: hasChild"
|
||||||
|
matTreeNodePadding
|
||||||
|
class="tree-node-frame"
|
||||||
|
>
|
||||||
|
<li>
|
||||||
|
<div class="mat-tree-node" (click)="onClickNode(node)" class="path">
|
||||||
|
<span class="horizontal-line"></span>
|
||||||
|
<button
|
||||||
|
mat-icon-button
|
||||||
|
color="accent"
|
||||||
|
matTreeNodeToggle
|
||||||
|
[attr.aria-label]="'toggle ' + node.filename"
|
||||||
|
>
|
||||||
|
<mat-icon class="mat-icon-rtl-mirror">
|
||||||
|
<!-- {{ treeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}-->
|
||||||
|
{{ treeControl.isExpanded(node) ? 'remove' : 'add' }}
|
||||||
|
</mat-icon>
|
||||||
|
</button>
|
||||||
|
<span class="dept-name">{{ node.name }}</span>
|
||||||
|
</div>
|
||||||
|
<ul
|
||||||
|
[class.organization-tree-node-invisible]="
|
||||||
|
!treeControl.isExpanded(node)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div *ngIf="treeControl.isExpanded(node)" class="boxnone">
|
||||||
|
<div class="vertical-line"></div>
|
||||||
|
<ng-container matTreeNodeOutlet></ng-container>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</mat-tree-node>
|
||||||
|
</mat-tree>
|
||||||
|
</cdk-virtual-scroll-viewport>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@charset 'utf-8';
|
@charset 'utf-8';
|
||||||
.organization-tree {
|
.organization-tree {
|
||||||
padding:10px;
|
padding: 10px;
|
||||||
ul,
|
ul,
|
||||||
li {
|
li {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
@ -13,83 +13,83 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-node-frame{
|
.tree-node-frame {
|
||||||
li{
|
li {
|
||||||
.path{
|
.path {
|
||||||
.horizontal-line{
|
.horizontal-line {
|
||||||
display:none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.mat-tree-node {
|
.mat-tree-node {
|
||||||
min-height: 30px;
|
min-height: 30px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding-left:20px;
|
padding-left: 20px;
|
||||||
margin-top:4px;
|
margin-top: 4px;
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f4f4f4;
|
background-color: #f4f4f4;
|
||||||
border:1px solid #cccccc;
|
border: 1px solid #cccccc;
|
||||||
border-radius:4px;
|
border-radius: 4px;
|
||||||
box-shadow: 0 1px 4px rgba(32, 33, 36, 0.1);
|
box-shadow: 0 1px 4px rgba(32, 33, 36, 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ul .tree-node-frame li .path > .horizontal-line{
|
ul .tree-node-frame li .path > .horizontal-line {
|
||||||
display:inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.boxnone{
|
.boxnone {
|
||||||
position:relative;
|
position: relative;
|
||||||
.vertical-line{
|
.vertical-line {
|
||||||
background: rgba(189,189,189,.4);
|
background: rgba(189, 189, 189, 0.4);
|
||||||
bottom: 6px;
|
bottom: 6px;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
width: 2px;
|
width: 2px;
|
||||||
}
|
}
|
||||||
.mat-nested-tree-node:last-child{
|
.mat-tree-node:last-child {
|
||||||
padding-bottom:10px;
|
padding-bottom: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.path {
|
.path {
|
||||||
padding: 6px 4px;
|
padding: 6px 4px;
|
||||||
+ ul{
|
+ ul {
|
||||||
li:last-chlid{
|
li:last-chlid {
|
||||||
border-bottom:1px solid #dddddd;
|
border-bottom: 1px solid #dddddd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.horizontal-line{
|
.horizontal-line {
|
||||||
width:10px;
|
width: 10px;
|
||||||
height:1px;
|
height: 1px;
|
||||||
background-color: #dddddd;
|
background-color: #dddddd;
|
||||||
display:inline-block;
|
display: inline-block;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
margin-left:-10px;
|
margin-left: -10px;
|
||||||
}
|
}
|
||||||
.mat-icon-button{
|
.mat-icon-button {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
.mat-icon-rtl-mirror{
|
.mat-icon-rtl-mirror {
|
||||||
border: 1px solid #dddddd;
|
border: 1px solid #dddddd;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
min-width: 14px;
|
min-width: 14px;
|
||||||
min-height: 14px;
|
min-height: 14px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
width:20px;
|
width: 20px;
|
||||||
height:20px;
|
height: 20px;
|
||||||
box-shadow: 0 2px 1px rgba(48, 48, 48, 0.2);
|
box-shadow: 0 2px 1px rgba(48, 48, 48, 0.2);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.dept-name{
|
.dept-name {
|
||||||
padding-left:10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,39 +8,26 @@ import {
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
AfterViewInit
|
AfterViewInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { MatTreeNestedDataSource, MatTree } from '@angular/material';
|
import { MatTreeFlattener, MatTree } from '@angular/material';
|
||||||
import { NestedTreeControl } from '@angular/cdk/tree';
|
|
||||||
import { BehaviorSubject } from 'rxjs';
|
|
||||||
import { NGXLogger } from 'ngx-logger';
|
import { NGXLogger } from 'ngx-logger';
|
||||||
|
|
||||||
import { DeptInfo } from '@ucap-webmessenger/protocol-query';
|
import { DeptInfo } from '@ucap-webmessenger/protocol-query';
|
||||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||||
|
import { FlatTreeControl } from '@angular/cdk/tree';
|
||||||
|
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||||
|
import { VirtualScrollTreeFlatDataSource } from '@ucap-webmessenger/ui';
|
||||||
|
|
||||||
export class OraganizationNode {
|
interface OrganizationNode {
|
||||||
private childNodeBehaviorSubject: BehaviorSubject<OraganizationNode[]>;
|
deptInfo: DeptInfo;
|
||||||
private childNodeList: OraganizationNode[];
|
name: string;
|
||||||
|
children?: OrganizationNode[];
|
||||||
|
}
|
||||||
|
|
||||||
get title(): string {
|
/** Flat node with expandable and level information */
|
||||||
return this.deptInfo.name;
|
interface FlatNode {
|
||||||
}
|
expandable: boolean;
|
||||||
|
name: string;
|
||||||
get children(): BehaviorSubject<OraganizationNode[]> {
|
level: number;
|
||||||
if (!this.childNodeBehaviorSubject) {
|
|
||||||
this.childNodeBehaviorSubject = new BehaviorSubject(
|
|
||||||
undefined === this.childNodeList ? [] : this.childNodeList
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return this.childNodeBehaviorSubject;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(public deptInfo: DeptInfo) {}
|
|
||||||
|
|
||||||
addChild(childNode: OraganizationNode) {
|
|
||||||
if (!this.childNodeList) {
|
|
||||||
this.childNodeList = [];
|
|
||||||
}
|
|
||||||
this.childNodeList.push(childNode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -55,87 +42,96 @@ export class TreeComponent implements OnInit, AfterViewInit {
|
||||||
@Input()
|
@Input()
|
||||||
loginRes: LoginResponse;
|
loginRes: LoginResponse;
|
||||||
@Input()
|
@Input()
|
||||||
set oraganizationList(deptInfo: DeptInfo[]) {
|
set oraganizationList(deptInfoList: DeptInfo[]) {
|
||||||
const nodeMap = new Map<number, OraganizationNode>();
|
if (!deptInfoList || 0 === deptInfoList.length) {
|
||||||
const rootNodeList: OraganizationNode[] = [];
|
return;
|
||||||
const remainChildNodeList: OraganizationNode[] = [];
|
}
|
||||||
let myNode: OraganizationNode;
|
const nodeMap = new Map<number, OrganizationNode>();
|
||||||
|
const rootNodeList: OrganizationNode[] = [];
|
||||||
|
const remainChildNodeList: OrganizationNode[] = [];
|
||||||
|
let myNode: OrganizationNode;
|
||||||
|
|
||||||
deptInfo.forEach(value => {
|
deptInfoList.forEach(deptInfo => {
|
||||||
const node = new OraganizationNode(value);
|
const node: OrganizationNode = {
|
||||||
if (nodeMap.has(value.seq)) {
|
deptInfo,
|
||||||
this.logger.warn('duplicate seq', value.seq);
|
name: deptInfo.name,
|
||||||
|
children: []
|
||||||
|
};
|
||||||
|
if (nodeMap.has(deptInfo.seq)) {
|
||||||
|
this.logger.warn('duplicate seq', deptInfo.seq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nodeMap.set(value.seq, node);
|
nodeMap.set(deptInfo.seq, node);
|
||||||
|
|
||||||
if (value.seq === this.loginRes.departmentCode) {
|
if (deptInfo.seq === this.loginRes.departmentCode) {
|
||||||
myNode = node;
|
myNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 === value.parentSeq) {
|
if (0 === deptInfo.parentSeq) {
|
||||||
rootNodeList.push(node);
|
rootNodeList.push(node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeMap.has(value.parentSeq)) {
|
if (nodeMap.has(deptInfo.parentSeq)) {
|
||||||
nodeMap.get(value.parentSeq).addChild(node);
|
nodeMap.get(deptInfo.parentSeq).children.push(node);
|
||||||
} else {
|
} else {
|
||||||
remainChildNodeList.push(node);
|
remainChildNodeList.push(node);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
remainChildNodeList.forEach(value => {
|
remainChildNodeList.forEach(node => {
|
||||||
if (nodeMap.has(value.deptInfo.parentSeq)) {
|
if (nodeMap.has(node.deptInfo.parentSeq)) {
|
||||||
nodeMap.get(value.deptInfo.parentSeq).addChild(value);
|
nodeMap.get(node.deptInfo.parentSeq).children.push(node);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dataSource.data = rootNodeList;
|
this.dataSource.data = rootNodeList;
|
||||||
// console.log('myNode', myNode);
|
|
||||||
// console.log('this.dataSource.data', this.dataSource.data[0]);
|
|
||||||
// this.treeControl.expandDescendants(this.dataSource.data[2]);
|
|
||||||
// console.log('this.dataSource', this.dataSource);
|
|
||||||
// console.log('this.dataSource.data', this.dataSource.data);
|
|
||||||
// console.log('this.treeControl', this.treeControl);
|
|
||||||
// console.log('this.treeControl.dataNodes', this.treeControl.dataNodes);
|
|
||||||
|
|
||||||
// const myNode = this.treeControl.dataNodes.filter(
|
|
||||||
// node => node.deptInfo.seq === this.loginRes.departmentCode
|
|
||||||
// );
|
|
||||||
// if (!!myNode && myNode.length > 0) {
|
|
||||||
// this.treeControl.expand(myNode[0]);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewChild('orgranizationTree', { static: true })
|
@ViewChild('cvsvOrganization', { static: false })
|
||||||
orgranizationTree: MatTree<OraganizationNode>;
|
cvsvOrganization: CdkVirtualScrollViewport;
|
||||||
|
|
||||||
levels = new Map<OraganizationNode, number>();
|
@ViewChild('orgranizationTree', { static: false })
|
||||||
treeControl: NestedTreeControl<OraganizationNode>;
|
orgranizationTree: MatTree<OrganizationNode>;
|
||||||
|
|
||||||
dataSource: MatTreeNestedDataSource<OraganizationNode>;
|
treeControl: FlatTreeControl<FlatNode>;
|
||||||
|
treeFlattener: MatTreeFlattener<OrganizationNode, FlatNode>;
|
||||||
|
dataSource: VirtualScrollTreeFlatDataSource<OrganizationNode, FlatNode>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private changeDetectorRef: ChangeDetectorRef,
|
private changeDetectorRef: ChangeDetectorRef,
|
||||||
private logger: NGXLogger
|
private logger: NGXLogger
|
||||||
) {
|
) {
|
||||||
this.treeControl = new NestedTreeControl<OraganizationNode>(
|
this.treeControl = new FlatTreeControl<FlatNode>(
|
||||||
this.getChildren
|
node => node.level,
|
||||||
|
node => node.expandable
|
||||||
);
|
);
|
||||||
this.dataSource = new MatTreeNestedDataSource();
|
this.treeFlattener = new MatTreeFlattener<OrganizationNode, FlatNode>(
|
||||||
|
(node: OrganizationNode, level: number) => {
|
||||||
|
return {
|
||||||
|
expandable: !!node.children && node.children.length > 0,
|
||||||
|
name: node.name,
|
||||||
|
level
|
||||||
|
};
|
||||||
|
},
|
||||||
|
node => node.level,
|
||||||
|
node => node.expandable,
|
||||||
|
node => node.children
|
||||||
|
);
|
||||||
|
this.dataSource = new VirtualScrollTreeFlatDataSource<
|
||||||
|
OrganizationNode,
|
||||||
|
FlatNode
|
||||||
|
>(this.treeControl, this.treeFlattener);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {}
|
ngOnInit() {}
|
||||||
|
|
||||||
ngAfterViewInit(): void {}
|
ngAfterViewInit(): void {
|
||||||
|
this.dataSource.cdkVirtualScrollViewport = this.cvsvOrganization;
|
||||||
|
}
|
||||||
|
|
||||||
getChildren = (node: OraganizationNode) => node.children;
|
hasChild = (_: number, node: FlatNode) => node.expandable;
|
||||||
|
|
||||||
hasChildren = (index: number, node: OraganizationNode) =>
|
onClickNode(node: OrganizationNode) {
|
||||||
0 < node.children.value.length;
|
|
||||||
|
|
||||||
onClickNode(node: OraganizationNode) {
|
|
||||||
this.selected.emit(node.deptInfo);
|
this.selected.emit(node.deptInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ReactiveFormsModule } from '@angular/forms';
|
import { ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
|
||||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||||
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
@ -21,6 +23,7 @@ const SERVICES = [];
|
||||||
CommonModule,
|
CommonModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
|
|
||||||
|
FlexLayoutModule,
|
||||||
ScrollingModule,
|
ScrollingModule,
|
||||||
|
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
|
||||||
|
import { FlatTreeControl } from '@angular/cdk/tree';
|
||||||
|
import {
|
||||||
|
BehaviorSubject,
|
||||||
|
merge,
|
||||||
|
Observable,
|
||||||
|
Subject,
|
||||||
|
Subscription
|
||||||
|
} from 'rxjs';
|
||||||
|
import { map, share } from 'rxjs/operators';
|
||||||
|
import { MatTreeFlattener } from '@angular/material';
|
||||||
|
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
|
||||||
|
|
||||||
|
export class VirtualScrollTreeFlatDataSource<T, F> extends DataSource<F> {
|
||||||
|
private flattenedDataSubject = new BehaviorSubject<F[]>([]);
|
||||||
|
|
||||||
|
private expandedDataSubject = new BehaviorSubject<F[]>([]);
|
||||||
|
expandedData$: Observable<F[]>;
|
||||||
|
|
||||||
|
private connectSubject: Subject<F[]>;
|
||||||
|
private dataChangeSubscription: Subscription;
|
||||||
|
private rangeChangeSubscription: Subscription;
|
||||||
|
|
||||||
|
private rangeSubject: BehaviorSubject<{
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
private _cdkVirtualScrollViewport: CdkVirtualScrollViewport;
|
||||||
|
set cdkVirtualScrollViewport(
|
||||||
|
cdkVirtualScrollViewport: CdkVirtualScrollViewport
|
||||||
|
) {
|
||||||
|
if (!cdkVirtualScrollViewport) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._cdkVirtualScrollViewport = cdkVirtualScrollViewport;
|
||||||
|
this.rangeSubject = new BehaviorSubject<{ start: number; end: number }>({
|
||||||
|
start: 0,
|
||||||
|
end: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
this.rangeChangeSubscription = cdkVirtualScrollViewport.renderedRangeStream.subscribe(
|
||||||
|
range => {
|
||||||
|
this.rangeSubject.next({
|
||||||
|
start: range.start,
|
||||||
|
end: range.end
|
||||||
|
});
|
||||||
|
if (!!this.connectSubject) {
|
||||||
|
this.connectSubject.next(
|
||||||
|
this.expandedDataSubject.value.slice(
|
||||||
|
this.rangeSubject.value.start,
|
||||||
|
this.rangeSubject.value.end
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line: variable-name
|
||||||
|
private _data: BehaviorSubject<T[]>;
|
||||||
|
get data() {
|
||||||
|
return this._data.value;
|
||||||
|
}
|
||||||
|
set data(value: T[]) {
|
||||||
|
this._data.next(value);
|
||||||
|
this.flattenedDataSubject.next(this.treeFlattener.flattenNodes(this.data));
|
||||||
|
this.treeControl.dataNodes = this.flattenedDataSubject.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private treeControl: FlatTreeControl<F>,
|
||||||
|
private treeFlattener: MatTreeFlattener<T, F>,
|
||||||
|
initialData: T[] = []
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this._data = new BehaviorSubject<T[]>(initialData);
|
||||||
|
this.expandedData$ = this.expandedDataSubject.asObservable().pipe(share());
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(collectionViewer: CollectionViewer): Observable<F[]> {
|
||||||
|
this.connectSubject = new Subject<F[]>();
|
||||||
|
|
||||||
|
this.dataChangeSubscription = merge(
|
||||||
|
collectionViewer.viewChange,
|
||||||
|
this.treeControl.expansionModel.changed,
|
||||||
|
this.flattenedDataSubject
|
||||||
|
)
|
||||||
|
.pipe(
|
||||||
|
map(() => {
|
||||||
|
this.expandedDataSubject.next(
|
||||||
|
this.treeFlattener.expandFlattenedNodes(
|
||||||
|
this.flattenedDataSubject.value,
|
||||||
|
this.treeControl
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return !this.rangeSubject
|
||||||
|
? this.expandedDataSubject.value
|
||||||
|
: this.expandedDataSubject.value.slice(
|
||||||
|
this.rangeSubject.value.start,
|
||||||
|
this.rangeSubject.value.end
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.subscribe(datas => {
|
||||||
|
this.connectSubject.next(datas);
|
||||||
|
if (!!this._cdkVirtualScrollViewport) {
|
||||||
|
this._cdkVirtualScrollViewport.checkViewportSize();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.connectSubject.asObservable();
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
if (!!this.dataChangeSubscription) {
|
||||||
|
this.dataChangeSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!!this.rangeChangeSubscription) {
|
||||||
|
this.rangeChangeSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,8 @@ export * from './lib/components/file-upload-queue.component';
|
||||||
export * from './lib/components/file-viewer.component';
|
export * from './lib/components/file-viewer.component';
|
||||||
export * from './lib/components/float-action-button.component';
|
export * from './lib/components/float-action-button.component';
|
||||||
|
|
||||||
|
export * from './lib/data-source/virtual-scroll-tree-flat.data-source';
|
||||||
|
|
||||||
export * from './lib/dialogs/alert.dialog.component';
|
export * from './lib/dialogs/alert.dialog.component';
|
||||||
export * from './lib/dialogs/confirm.dialog.component';
|
export * from './lib/dialogs/confirm.dialog.component';
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user