조직도 타이틀, 검색 기능 구현.

This commit is contained in:
leejinho 2019-11-12 09:47:56 +09:00
parent d28b6cc171
commit 8fec0e15f2
3 changed files with 264 additions and 107 deletions

View File

@ -1,37 +1,50 @@
<div <div>
class="oraganization-tab" <div class="current-head">
*ngIf="departmentInfoList$ | async" <h3>조직도</h3>
> </div>
<div class="oraganization-tab-tree" > <ucap-organization-tenant-search
[companyList]="companyList$ | async"
[companyCode]="companyCode"
(keyDownEnter)="onKeyDownEnterOrganizationTenantSearch($event)"
(cancel)="onClickCancel($event)"
>
</ucap-organization-tenant-search>
</div>
<div class="oraganization-tab" *ngIf="departmentInfoList$ | async">
<div class="oraganization-tab-tree">
<ucap-organization-tree <ucap-organization-tree
[oraganizationList]="departmentInfoList$ | async" [oraganizationList]="departmentInfoList$ | async"
[loginRes]="loginRes" [loginRes]="loginRes"
(selected)="onSelectedOrganization($event)" (selected)="onSelectedOrganization($event)"
></ucap-organization-tree> ></ucap-organization-tree>
</div> </div>
<div class="select-list "> <div class="select-list">
<dl class="select-dept text-accent-color"> <dl class="select-dept text-accent-color">
<dt> <dt>
<ng-container *ngIf="!isShowSearch">
{{ getSelectedDepartmentName() }} {{ getSelectedDepartmentName() }}
</dt> </ng-container>
<dd> <ng-container *ngIf="isShowSearch">
<mat-checkbox 검색결과<span class="text-accent-color"
#checkbox >({{ searchUserInfos.length }}명)</span
[checked]="getCheckedAllUser()"
(change)="onCheckAllUser(checkbox.checked)"
(click)="$event.stopPropagation()"
> >
</mat-checkbox> </ng-container>
</dd> </dt>
</dl> <dd>
<mat-checkbox
#checkbox
[checked]="getCheckedAllUser()"
(change)="onCheckAllUser(checkbox.checked)"
(click)="$event.stopPropagation()"
>
</mat-checkbox>
</dd>
</dl>
<div *ngIf="selectedDepartmentProcessing"> <div *ngIf="selectedDepartmentProcessing">
<mat-progress-bar mode="indeterminate"></mat-progress-bar> <mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div> </div>
<div class="search-list"> <div *ngIf="!isShowSearch" class="search-list">
<cdk-virtual-scroll-viewport <cdk-virtual-scroll-viewport itemSize="20" style="height: 100%;">
itemSize="20"
style="height: 100%;"
>
<ucap-profile-user-list-item <ucap-profile-user-list-item
*cdkVirtualFor="let userInfo of selectedDepartmentUserInfoList" *cdkVirtualFor="let userInfo of selectedDepartmentUserInfoList"
[userInfo]="userInfo" [userInfo]="userInfo"
@ -55,11 +68,25 @@
> >
</ucap-profile-user-list-item> --> </ucap-profile-user-list-item> -->
</div> </div>
<div *ngIf="isShowSearch" class="search-result">
<cdk-virtual-scroll-viewport itemSize="20" style="height: 100%;">
<ucap-profile-user-list-item
*cdkVirtualFor="let userInfo of searchUserInfos"
[userInfo]="userInfo"
[checkable]="true"
[sessionVerinfo]="sessionVerinfo"
[selectedUserList]="selectedUserList"
[isChecked]="getCheckedUser(userInfo)"
(checkUser)="onCheckUser($event)"
>
</ucap-profile-user-list-item>
</cdk-virtual-scroll-viewport>
</div>
</div> </div>
<div *ngIf="!isUserSelect" class="btn-box"> <div *ngIf="!isUserSelect" class="btn-box">
<!--선택된 후에는 disabled="true" 빼주세요. -->
<button <button
mat-stroked-button mat-stroked-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
class="mat-primary" class="mat-primary"
(click)="onClickShowSelectedUserList()" (click)="onClickShowSelectedUserList()"
> >
@ -69,18 +96,29 @@
</button> </button>
<ul> <ul>
<li> <li>
<button mat-flat-button (click)="onClickAddGroup()" class="mat-primary"> <button
mat-flat-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
(click)="onClickAddGroup()"
class="mat-primary"
>
그룹에 추가 그룹에 추가
</button> </button>
</li> </li>
<li> <li>
<button mat-flat-button (click)="onClickChatOpen()" class="mat-primary"> <button
mat-flat-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
(click)="onClickChatOpen()"
class="mat-primary"
>
대화 대화
</button> </button>
</li> </li>
<li> <li>
<button <button
mat-flat-button mat-flat-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
(click)="onClickConference()" (click)="onClickConference()"
class="mat-primary" class="mat-primary"
> >

View File

@ -11,98 +11,134 @@
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: $row; -webkit-line-clamp: $row;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
word-wrap: break-word; word-wrap: break-word;
} }
} }
.current-head {
display: flex;
justify-content: center;
padding: 0 10px;
height: 70px;
background-color: #eeeeee;
background: #f15f79;
background: -webkit-linear-gradient(to right, #352a37, #f15f79);
background: linear-gradient(to right, #352a37, #ef4c73);
color: #ffffff;
h3 {
display: inline-flex;
padding-left: 10px;
align-items: center;
width: 100%;
}
.btn-box {
height: 100%;
margin-left: auto;
display: inline-flex;
align-items: center;
svg {
stroke: #333333;
}
}
}
.search-result {
height: calc(100% - 40px);
overflow: auto;
.result-num {
padding: 10px;
display: flex;
height: 40px;
}
}
.oraganization-tab { .oraganization-tab {
height: 100%; height: calc(100% - 130px);
flex-direction: inherit; flex-direction: inherit;
display: flex; display: flex;
.oraganization-tab-tree { .oraganization-tab-tree {
height:40%; height: 40%;
overflow-y: auto; overflow-y: auto;
} }
} }
//팝업에 있는 조직도 //팝업에 있는 조직도
.mat-card-content{ .mat-card-content {
.mat-tab-body-content{ .mat-tab-body-content {
.oraganization-box{ .oraganization-box {
.oraganization-tab { .oraganization-tab {
height: 80%; height: 80%;
flex-direction: row; flex-direction: row;
}
}
}
}
.select-list{
height:60%;
border-top:1px solid #dddddd;
.select-dept{
padding:0 20px;
height:40px;
line-height:40px;
display:flex;
background-color: #f9f9f9;
dt{
}
dd{
margin-left:auto;
}
}
.search-list{
height: calc(100% - 40px);
overflow: auto;
.list-item{
height:70px;
}
}
}
.btn-box{
padding:10px;
button{
width:100%;
@include ellipsis(1);
}
ul{
display:flex;
flex-flow: row;
align-content: space-between;
margin-top:4px;
li{
display:inline-flex;
align-items: center;
flex-grow: 1;
width:33%;
margin-right: 4px;
&:last-child{
margin-right: 0;
}
button{
text-align:center;
width:100%;
height:100%;
padding: 0 6px;
}
} }
} }
} }
}
.select-list {
height: 60%;
border-top: 1px solid #dddddd;
.select-dept {
padding: 0 20px;
height: 40px;
line-height: 40px;
display: flex;
background-color: #f9f9f9;
dt {
}
dd {
margin-left: auto;
}
}
.search-list {
height: calc(100% - 40px);
overflow: auto;
.list-item {
height: 70px;
}
}
}
.btn-box {
padding: 10px;
button {
width: 100%;
@include ellipsis(1);
span {
vertical-align: baseline;
}
}
ul {
display: flex;
flex-flow: row;
align-content: space-between;
margin-top: 4px;
li {
display: inline-flex;
align-items: center;
flex-grow: 1;
width: 33%;
margin-right: 4px;
&:last-child {
margin-right: 0;
}
button {
text-align: center;
width: 100%;
height: 100%;
padding: 0 6px;
}
}
}
}
.dialog-org { .dialog-org {
.oraganization-tab { .oraganization-tab {
width: 100%; width: 100%;
height:380px; height: 380px;
border-bottom: 1px solid #dddddd; border-bottom: 1px solid #dddddd;
position: relative; position: relative;
.oraganization-tab-tree { .oraganization-tab-tree {
display: inline-flex; display: inline-flex;
width: 50%; width: 50%;
height:100%; height: 100%;
border-right: 1px solid #dddddd; border-right: 1px solid #dddddd;
overflow: auto; overflow: auto;
} }
@ -110,11 +146,11 @@
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
width: 50%; width: 50%;
height:100%; height: 100%;
overflow: auto; overflow: auto;
.search-list { .search-list {
overflow: auto; overflow: auto;
} }
} }
} }
} }

View File

@ -4,10 +4,10 @@ import {
OnDestroy, OnDestroy,
Output, Output,
EventEmitter, EventEmitter,
Input Input,
} from '@angular/core'; } from '@angular/core';
import { ucapAnimations, DialogService } from '@ucap-webmessenger/ui'; import { ucapAnimations, DialogService } from '@ucap-webmessenger/ui';
import { Observable, Subscription } from 'rxjs'; import { Observable, Subscription, of } from 'rxjs';
import { import {
DeptInfo, DeptInfo,
QueryProtocolService, QueryProtocolService,
@ -15,7 +15,10 @@ import {
UserInfoSS, UserInfoSS,
DeptUserResponse, DeptUserResponse,
UserInfoF, UserInfoF,
UserInfoDN UserInfoDN,
SSVC_TYPE_QUERY_DEPT_USER_DATA,
SSVC_TYPE_QUERY_DEPT_USER_RES,
DeptUserData,
} from '@ucap-webmessenger/protocol-query'; } from '@ucap-webmessenger/protocol-query';
import { UserInfo, GroupDetailData } from '@ucap-webmessenger/protocol-sync'; import { UserInfo, GroupDetailData } from '@ucap-webmessenger/protocol-sync';
import { Store, select } from '@ngrx/store'; import { Store, select } from '@ngrx/store';
@ -25,23 +28,25 @@ import * as AppStore from '@app/store';
import * as QueryStore from '@app/store/messenger/query'; import * as QueryStore from '@app/store/messenger/query';
import * as SyncStore from '@app/store/messenger/sync'; import * as SyncStore from '@app/store/messenger/sync';
import * as ChatStore from '@app/store/messenger/chat'; import * as ChatStore from '@app/store/messenger/chat';
import * as StatusStore from '@app/store/messenger/status';
import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { LoginInfo, KEY_LOGIN_INFO } from '@app/types'; import { LoginInfo, KEY_LOGIN_INFO } from '@app/types';
import { take, map, tap, delay } from 'rxjs/operators'; import { take, map, tap, delay, catchError } from 'rxjs/operators';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { KEY_VER_INFO } from '@app/types/ver-info.type'; import { KEY_VER_INFO } from '@app/types/ver-info.type';
import { import {
SelectGroupDialogComponent, SelectGroupDialogComponent,
SelectGroupDialogData, SelectGroupDialogData,
SelectGroupDialogResult SelectGroupDialogResult,
} from '../../dialogs/group/select-group.dialog.component'; } from '../../dialogs/group/select-group.dialog.component';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { Company } from '@ucap-webmessenger/api-external';
@Component({ @Component({
selector: 'app-layout-chat-left-sidenav-organization', selector: 'app-layout-chat-left-sidenav-organization',
templateUrl: './organization.component.html', templateUrl: './organization.component.html',
styleUrls: ['./organization.component.scss'], styleUrls: ['./organization.component.scss'],
animations: ucapAnimations animations: ucapAnimations,
}) })
export class OrganizationComponent implements OnInit, OnDestroy { export class OrganizationComponent implements OnInit, OnDestroy {
@Input() @Input()
@ -62,6 +67,9 @@ export class OrganizationComponent implements OnInit, OnDestroy {
userInfos: (UserInfo | UserInfoSS | UserInfoF | UserInfoDN)[]; userInfos: (UserInfo | UserInfoSS | UserInfoF | UserInfoDN)[];
}>(); }>();
companyList$: Observable<Company[]>;
companyCode: string;
departmentInfoList$: Observable<DeptInfo[]>; departmentInfoList$: Observable<DeptInfo[]>;
selectedDepartmentUserInfoList$: Observable<UserInfoSS[]>; selectedDepartmentUserInfoList$: Observable<UserInfoSS[]>;
selectedDepartmentUserInfoList: UserInfoSS[] = []; selectedDepartmentUserInfoList: UserInfoSS[] = [];
@ -75,9 +83,13 @@ export class OrganizationComponent implements OnInit, OnDestroy {
loginRes: LoginResponse; loginRes: LoginResponse;
sessionVerinfo: VersionInfo2Response; sessionVerinfo: VersionInfo2Response;
isShowSearch = false;
searchUserInfos: UserInfoSS[] = [];
constructor( constructor(
private store: Store<any>, private store: Store<any>,
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
private queryProtocolService: QueryProtocolService,
private dialogService: DialogService, private dialogService: DialogService,
private logger: NGXLogger private logger: NGXLogger
) { ) {
@ -88,6 +100,11 @@ export class OrganizationComponent implements OnInit, OnDestroy {
} }
ngOnInit() { ngOnInit() {
this.companyCode = this.loginInfo.companyCode;
this.companyList$ = this.store.pipe(
select(AppStore.SettingSelector.CompanySelector.companyList)
);
this.departmentInfoList$ = this.store.pipe( this.departmentInfoList$ = this.store.pipe(
select(AppStore.MessengerSelector.QuerySelector.departmentInfoList) select(AppStore.MessengerSelector.QuerySelector.departmentInfoList)
); );
@ -133,7 +150,7 @@ export class OrganizationComponent implements OnInit, OnDestroy {
search: '', search: '',
searchRange: DeptSearchType.All, searchRange: DeptSearchType.All,
senderCompanyCode: this.loginInfo.companyCode, senderCompanyCode: this.loginInfo.companyCode,
senderEmployeeType: loginRes.userInfo.employeeType senderEmployeeType: loginRes.userInfo.employeeType,
}) })
); );
return loginRes; return loginRes;
@ -155,7 +172,67 @@ export class OrganizationComponent implements OnInit, OnDestroy {
} }
} }
/** 유저검색 */
onKeyDownEnterOrganizationTenantSearch(params: {
companyCode: string;
searchWord: string;
}) {
if (params.searchWord.trim().length > 1) {
this.isShowSearch = true;
this.selectedDepartmentProcessing = true;
const searchUserInfos: UserInfoSS[] = [];
this.queryProtocolService
.deptUser({
divCd: 'GRP',
companyCode: params.companyCode,
searchRange: DeptSearchType.All,
search: params.searchWord,
senderCompanyCode: params.companyCode,
senderEmployeeType: this.loginRes.userInfo.employeeType,
})
.pipe(
map(res => {
switch (res.SSVC_TYPE) {
case SSVC_TYPE_QUERY_DEPT_USER_DATA:
searchUserInfos.push(...(res as DeptUserData).userInfos);
break;
case SSVC_TYPE_QUERY_DEPT_USER_RES:
{
// 검색 결과 처리.
this.searchUserInfos = searchUserInfos;
this.selectedDepartmentProcessing = false;
// 검색 결과에 따른 프레즌스 조회.
const userSeqList: number[] = [];
this.searchUserInfos.map(user => userSeqList.push(user.seq));
if (userSeqList.length > 0) {
this.store.dispatch(
StatusStore.bulkInfo({
divCd: 'orgSrch',
userSeqs: userSeqList,
})
);
}
}
break;
}
}),
catchError(error => {
this.selectedDepartmentProcessing = false;
return of(this.logger.error(error));
})
)
.subscribe();
}
}
/** 검색 취소 */
onClickCancel() {
this.isShowSearch = false;
this.searchUserInfos = [];
}
onSelectedOrganization(deptInfo: DeptInfo) { onSelectedOrganization(deptInfo: DeptInfo) {
this.onClickCancel();
this.store this.store
.pipe( .pipe(
take(1), take(1),
@ -169,7 +246,7 @@ export class OrganizationComponent implements OnInit, OnDestroy {
search: '', search: '',
searchRange: DeptSearchType.All, searchRange: DeptSearchType.All,
senderCompanyCode: this.loginInfo.companyCode, senderCompanyCode: this.loginInfo.companyCode,
senderEmployeeType: loginRes.userInfo.employeeType senderEmployeeType: loginRes.userInfo.employeeType,
}) })
); );
}), }),
@ -182,7 +259,7 @@ export class OrganizationComponent implements OnInit, OnDestroy {
getSelectedDepartmentName() { getSelectedDepartmentName() {
if (!!this.selectedDepartmentProcessing) { if (!!this.selectedDepartmentProcessing) {
return '부서조회중..'; return '조회중..';
} }
if (!!this.selectedDepartmentName) { if (!!this.selectedDepartmentName) {
@ -194,10 +271,14 @@ export class OrganizationComponent implements OnInit, OnDestroy {
/** 전체 체크여부 */ /** 전체 체크여부 */
getCheckedAllUser() { getCheckedAllUser() {
const compareList: UserInfoSS[] = this.isShowSearch
? this.searchUserInfos
: this.selectedDepartmentUserInfoList;
if ( if (
!this.selectedDepartmentUserInfoList || !compareList ||
this.selectedDepartmentUserInfoList.length === 0 || compareList.length === 0 ||
this.selectedDepartmentUserInfoList.filter( compareList.filter(
item => item =>
!( !(
this.selectedUserList.filter(user => user.seq === item.seq).length > this.selectedUserList.filter(user => user.seq === item.seq).length >
@ -225,7 +306,9 @@ export class OrganizationComponent implements OnInit, OnDestroy {
onCheckAllUser(value: boolean) { onCheckAllUser(value: boolean) {
this.checkAllUser.emit({ this.checkAllUser.emit({
isChecked: value, isChecked: value,
userInfos: this.selectedDepartmentUserInfoList userInfos: this.isShowSearch
? this.searchUserInfos
: this.selectedDepartmentUserInfoList,
}); });
} }
@ -251,8 +334,8 @@ export class OrganizationComponent implements OnInit, OnDestroy {
>(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) {
@ -269,7 +352,7 @@ export class OrganizationComponent implements OnInit, OnDestroy {
this.store.dispatch( this.store.dispatch(
SyncStore.updateGroupMember({ SyncStore.updateGroupMember({
oldGroup, oldGroup,
trgtUserSeq trgtUserSeq,
}) })
); );