조직도 UX 변경
This commit is contained in:
parent
3393265b74
commit
3064213ed5
|
@ -1,21 +1,21 @@
|
|||
import { IntroComponent } from './intro.component';
|
||||
import { LeftNaviComponent } from './left-nav.component';
|
||||
import { LeftSideComponent } from './left-side.component';
|
||||
import { MessagesComponent } from './messages.component';
|
||||
import { MainContentsComponent } from './main-contents.component';
|
||||
import { RightSideComponent } from './right-side.component';
|
||||
import { RightDrawerComponent } from './right-drawer.component';
|
||||
|
||||
import { LEFT_SIDENAV_COMPONENTS } from './left-sidenav';
|
||||
import { MAIN_CONTENTS_COMPONENTS } from './main-contents';
|
||||
import { RIGHT_DRAWER_COMPONENTS } from './right-drawer';
|
||||
|
||||
export const COMPONENTS = [
|
||||
IntroComponent,
|
||||
LeftNaviComponent,
|
||||
LeftSideComponent,
|
||||
MessagesComponent,
|
||||
MainContentsComponent,
|
||||
RightSideComponent,
|
||||
RightDrawerComponent,
|
||||
|
||||
...LEFT_SIDENAV_COMPONENTS,
|
||||
...MAIN_CONTENTS_COMPONENTS,
|
||||
...RIGHT_DRAWER_COMPONENTS
|
||||
];
|
||||
|
|
|
@ -27,7 +27,10 @@
|
|||
MainMenu.Organization === currentTabLable ? 'block' : 'none'
|
||||
"
|
||||
>
|
||||
<app-layout-chat-left-sidenav-organization
|
||||
<app-layout-chat-left-sidenav-organization-tree
|
||||
class="organization-side"
|
||||
></app-layout-chat-left-sidenav-organization-tree>
|
||||
<!-- <app-layout-chat-left-sidenav-organization
|
||||
[selectedUserList]="selectedUserList"
|
||||
[isVisible]="currentTabLable === MainMenu.Organization"
|
||||
(checkAllUser)="onCheckAllUser($event)"
|
||||
|
@ -39,7 +42,7 @@
|
|||
(toggleUser)="onToggleUser($event)"
|
||||
(resetSelectedUserList)="onResetSelectedUserList($event)"
|
||||
class="organization-side"
|
||||
></app-layout-chat-left-sidenav-organization>
|
||||
></app-layout-chat-left-sidenav-organization> -->
|
||||
</div>
|
||||
<div
|
||||
#tabs
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { CallComponent } from './call.component';
|
||||
import { ChatComponent } from './chat.component';
|
||||
import { GroupComponent } from './group.component';
|
||||
import { OrganizationTreeComponent } from './organization-tree.component';
|
||||
import { OrganizationComponent } from './organization.component';
|
||||
import { MessageBoxComponent } from './message.component';
|
||||
|
||||
|
@ -8,6 +9,7 @@ export const LEFT_SIDENAV_COMPONENTS = [
|
|||
CallComponent,
|
||||
ChatComponent,
|
||||
GroupComponent,
|
||||
OrganizationTreeComponent,
|
||||
OrganizationComponent,
|
||||
MessageBoxComponent
|
||||
];
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<div>
|
||||
<div class="current-head">
|
||||
<h3>{{ 'organization.chart' | translate }}</h3>
|
||||
</div>
|
||||
<ucap-organization-tenant-search
|
||||
[companyList]="companyList$ | async"
|
||||
[companyCode]="companyCode"
|
||||
(keyDownEnter)="onKeyDownEnterOrganizationTenantSearch($event)"
|
||||
(cancel)="onClickCancel()"
|
||||
>
|
||||
</ucap-organization-tenant-search>
|
||||
</div>
|
||||
<div class="oraganization-tab">
|
||||
<div class="oraganization-tab-tree">
|
||||
<ucap-organization-tree
|
||||
[oraganizationList]="departmentInfoList$ | async"
|
||||
[loginRes]="loginRes"
|
||||
[activate$]="organizationTreeActivatedSubject.asObservable()"
|
||||
(selected)="onSelectedOrganization($event)"
|
||||
class="tab-tree-frame"
|
||||
></ucap-organization-tree>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,44 @@
|
|||
@charset 'utf-8';
|
||||
|
||||
@mixin ellipsis($row) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@if $row == 1 {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
} @else if $row >= 2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: $row;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.current-head {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.oraganization-tab {
|
||||
// height: calc(100% - 120px);
|
||||
flex-direction: inherit;
|
||||
display: flex;
|
||||
.oraganization-tab-tree {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { OrganizationComponent } from './organization.component';
|
||||
|
||||
describe('Chat::LeftSidenav::OrganizationComponent', () => {
|
||||
let component: OrganizationComponent;
|
||||
let fixture: ComponentFixture<OrganizationComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OrganizationComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(OrganizationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,171 @@
|
|||
import { Component, OnInit, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
||||
import { ucapAnimations, DialogService } from '@ucap-webmessenger/ui';
|
||||
import { Observable, Subscription, BehaviorSubject, combineLatest } from 'rxjs';
|
||||
import {
|
||||
DeptInfo,
|
||||
QueryProtocolService,
|
||||
DeptSearchType,
|
||||
UserInfoSS
|
||||
} from '@ucap-webmessenger/protocol-query';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
import * as AppStore from '@app/store';
|
||||
import * as QueryStore from '@app/store/messenger/query';
|
||||
import * as StatusStore from '@app/store/messenger/status';
|
||||
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
|
||||
import { LoginInfo, KEY_LOGIN_INFO, MainMenu } from '@app/types';
|
||||
import { take, tap } from 'rxjs/operators';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { Company } from '@ucap-webmessenger/api-external';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { OrganizationService } from '@ucap-webmessenger/ui-organization';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-chat-left-sidenav-organization-tree',
|
||||
templateUrl: './organization-tree.component.html',
|
||||
styleUrls: ['./organization-tree.component.scss'],
|
||||
animations: ucapAnimations
|
||||
})
|
||||
export class OrganizationTreeComponent implements OnInit, OnDestroy {
|
||||
companyList$: Observable<Company[]>;
|
||||
companyCode: string;
|
||||
|
||||
departmentInfoList$: Observable<DeptInfo[]>;
|
||||
myDepartmentUserInfoListSubscription: Subscription;
|
||||
|
||||
loginInfo: LoginInfo;
|
||||
loginRes: LoginResponse;
|
||||
loginResSubscription: Subscription;
|
||||
|
||||
isShowSearch = false;
|
||||
searchUserInfos: UserInfoSS[] = [];
|
||||
|
||||
organizationTreeActivatedSubject: BehaviorSubject<
|
||||
boolean
|
||||
> = new BehaviorSubject<boolean>(false);
|
||||
organizationTreeActivatedSubscription: Subscription;
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private sessionStorageService: SessionStorageService,
|
||||
private queryProtocolService: QueryProtocolService,
|
||||
private organizationService: OrganizationService,
|
||||
private logger: NGXLogger
|
||||
) {
|
||||
this.loginInfo = this.sessionStorageService.get<LoginInfo>(KEY_LOGIN_INFO);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.companyCode = this.loginInfo.companyCode;
|
||||
this.companyList$ = this.store.pipe(
|
||||
select(AppStore.SettingSelector.CompanySelector.companyList)
|
||||
);
|
||||
|
||||
this.departmentInfoList$ = this.store.pipe(
|
||||
select(AppStore.MessengerSelector.QuerySelector.departmentInfoList)
|
||||
);
|
||||
|
||||
this.loginResSubscription = this.store
|
||||
.pipe(
|
||||
take(1),
|
||||
select(AppStore.AccountSelector.AuthenticationSelector.loginRes),
|
||||
tap(loginRes => {
|
||||
this.loginRes = loginRes;
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
|
||||
this.myDepartmentUserInfoListSubscription = this.store
|
||||
.pipe(
|
||||
select(
|
||||
AppStore.MessengerSelector.QuerySelector.myDepartmentUserInfoList
|
||||
)
|
||||
)
|
||||
.subscribe(list => {
|
||||
if (!list) {
|
||||
this.store
|
||||
.pipe(
|
||||
take(1),
|
||||
select(AppStore.AccountSelector.AuthenticationSelector.loginRes),
|
||||
tap(loginRes => {
|
||||
if (!!loginRes) {
|
||||
this.store.dispatch(
|
||||
QueryStore.selectedDept({
|
||||
seq: loginRes.departmentCode,
|
||||
name: loginRes.userInfo.deptName,
|
||||
nameEn: loginRes.userInfo.deptNameEn,
|
||||
nameCn: loginRes.userInfo.deptNameCn
|
||||
})
|
||||
);
|
||||
}
|
||||
this.loginRes = loginRes;
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
this.organizationTreeActivatedSubscription = combineLatest([
|
||||
this.store.pipe(
|
||||
select(AppStore.MessengerSelector.SettingsSelector.gnbMenuIndex)
|
||||
),
|
||||
this.store.pipe(
|
||||
select(
|
||||
AppStore.MessengerSelector.SettingsSelector.organizationTreeActivated
|
||||
)
|
||||
)
|
||||
]).subscribe(([menu, activate]) => {
|
||||
this.organizationTreeActivatedSubject.next(
|
||||
menu === MainMenu.Organization || activate
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.loginResSubscription) {
|
||||
this.loginResSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.myDepartmentUserInfoListSubscription) {
|
||||
this.myDepartmentUserInfoListSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.organizationTreeActivatedSubscription) {
|
||||
this.organizationTreeActivatedSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
/** 유저검색 */
|
||||
onKeyDownEnterOrganizationTenantSearch(params: {
|
||||
companyCode: string;
|
||||
searchWord: string;
|
||||
}) {
|
||||
if (params.searchWord.trim().length > 1) {
|
||||
this.store.dispatch(
|
||||
QueryStore.searchDeptUser({
|
||||
companyCode: params.companyCode,
|
||||
search: params.searchWord
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
/** 검색 취소 */
|
||||
onClickCancel() {
|
||||
this.store.dispatch(QueryStore.cancelSearchDeptUser({}));
|
||||
}
|
||||
|
||||
/** 조직도 부서 선택 */
|
||||
onSelectedOrganization(deptInfo: DeptInfo) {
|
||||
this.onClickCancel();
|
||||
|
||||
this.store.dispatch(
|
||||
QueryStore.selectedDept({
|
||||
seq: deptInfo.seq,
|
||||
name: deptInfo.name,
|
||||
nameEn: deptInfo.nameEn,
|
||||
nameCn: deptInfo.nameCn
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<app-layout-messenger-intro
|
||||
*ngIf="
|
||||
!this.selectedChat && (this.gnbMenuIndex$ | async) !== MainMenu.Organization
|
||||
"
|
||||
></app-layout-messenger-intro>
|
||||
|
||||
<app-layout-messenger-messages
|
||||
*ngIf="
|
||||
!!this.selectedChat &&
|
||||
(this.gnbMenuIndex$ | async) !== MainMenu.Organization
|
||||
"
|
||||
(openProfile)="onClickOpenProfile($event)"
|
||||
(closeRightDrawer)="onCloseRightDrawer()"
|
||||
></app-layout-messenger-messages>
|
||||
|
||||
<app-layout-messenger-organization
|
||||
[style.display]="
|
||||
MainMenu.Organization === (this.gnbMenuIndex$ | async) ? 'block' : 'none'
|
||||
"
|
||||
>
|
||||
</app-layout-messenger-organization>
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { MainContentsComponent } from './main-contents.component';
|
||||
|
||||
describe('MainContentsComponent', () => {
|
||||
let component: MainContentsComponent;
|
||||
let fixture: ComponentFixture<MainContentsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ MainContentsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MainContentsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,43 @@
|
|||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { OpenProfileOptions } from '@ucap-webmessenger/protocol-buddy';
|
||||
|
||||
import * as AppStore from '@app/store';
|
||||
import { select, Store } from '@ngrx/store';
|
||||
|
||||
import { MainMenu } from '@app/types';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-messenger-main-contents',
|
||||
templateUrl: './main-contents.component.html',
|
||||
styleUrls: ['./main-contents.component.scss']
|
||||
})
|
||||
export class MainContentsComponent implements OnInit {
|
||||
@Input()
|
||||
selectedChat: Observable<string | null>;
|
||||
|
||||
@Output()
|
||||
openProfile = new EventEmitter<{
|
||||
userSeq: number;
|
||||
}>();
|
||||
@Output()
|
||||
closeRightDrawer = new EventEmitter();
|
||||
|
||||
MainMenu = MainMenu;
|
||||
gnbMenuIndex$: Observable<string>;
|
||||
|
||||
constructor(private store: Store<any>) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.gnbMenuIndex$ = this.store.pipe(
|
||||
select(AppStore.MessengerSelector.SettingsSelector.gnbMenuIndex)
|
||||
);
|
||||
}
|
||||
|
||||
onClickOpenProfile(params: {
|
||||
userSeq: number;
|
||||
openProfileOptions?: OpenProfileOptions;
|
||||
}) {}
|
||||
|
||||
onCloseRightDrawer() {}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import { IntroComponent } from './intro.component';
|
||||
import { MessagesComponent } from './messages.component';
|
||||
import { OrganizationComponent } from './organization.component';
|
||||
|
||||
export const MAIN_CONTENTS_COMPONENTS = [
|
||||
IntroComponent,
|
||||
MessagesComponent,
|
||||
OrganizationComponent
|
||||
];
|
|
@ -1,6 +1,6 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { ucapAnimations } from '@ucap-webmessenger/ui';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { environment } from '../../../../../environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-messenger-intro',
|
|
@ -95,7 +95,7 @@ import {
|
|||
CreateChatDialogComponent,
|
||||
CreateChatDialogData,
|
||||
CreateChatDialogResult
|
||||
} from '../dialogs/chat/create-chat.dialog.component';
|
||||
} from '../../dialogs/chat/create-chat.dialog.component';
|
||||
import {
|
||||
FileViewerDialogComponent,
|
||||
FileViewerDialogData,
|
||||
|
@ -108,18 +108,18 @@ import {
|
|||
EditChatRoomDialogComponent,
|
||||
EditChatRoomDialogResult,
|
||||
EditChatRoomDialogData
|
||||
} from '../dialogs/chat/edit-chat-room.dialog.component';
|
||||
} from '../../dialogs/chat/edit-chat-room.dialog.component';
|
||||
import {
|
||||
SelectGroupDialogComponent,
|
||||
SelectGroupDialogResult,
|
||||
SelectGroupDialogData
|
||||
} from '../dialogs/group/select-group.dialog.component';
|
||||
} from '../../dialogs/group/select-group.dialog.component';
|
||||
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { environment } from '../../../../../environments/environment';
|
||||
import {
|
||||
MassDetailComponent,
|
||||
MassDetailDialogData
|
||||
} from '../dialogs/chat/mass-detail.component';
|
||||
} from '../../dialogs/chat/mass-detail.component';
|
||||
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
|
@ -127,14 +127,14 @@ import {
|
|||
ClipboardDialogComponent,
|
||||
ClipboardDialogData,
|
||||
ClipboardDialogResult
|
||||
} from '../dialogs/chat/clipboard.dialog.component';
|
||||
} from '../../dialogs/chat/clipboard.dialog.component';
|
||||
import { AppFileService } from '@app/services/file.service';
|
||||
import { FileType } from '@ucap-webmessenger/protocol-file';
|
||||
import {
|
||||
ConferenceDetailDialogComponent,
|
||||
ConferenceDetailDialogResult,
|
||||
ConferenceDetailDialogData
|
||||
} from '../dialogs/conference/conference-detail.dialog.component';
|
||||
} from '../../dialogs/conference/conference-detail.dialog.component';
|
||||
import { ConferenceService } from '@ucap-webmessenger/api-prompt';
|
||||
import { AuthResponse } from '@ucap-webmessenger/protocol-query';
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<div class="container" fxFlex fxLayout="column">
|
||||
<mat-toolbar class="organization-toolbar">
|
||||
<div fxFlex fxLayout="row" class="organization-header">
|
||||
<div fxLayout="row" fxLayoutAlign="start center" class="profile-img">
|
||||
icon
|
||||
</div>
|
||||
<div class="organization-info">
|
||||
<h3 class="organization-name">
|
||||
title
|
||||
</h3>
|
||||
</div>
|
||||
<div class="organization-option">
|
||||
<button mat-icon-button aria-label="more">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</mat-toolbar>
|
||||
|
||||
<div fxFlex="1 1 auto" class="organization-content">
|
||||
contents
|
||||
</div>
|
||||
|
||||
<div fxFlex="0 0 auto" fxLayout="column"></div>
|
||||
</div>
|
|
@ -0,0 +1,74 @@
|
|||
@charset 'utf-8';
|
||||
:host {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@mixin ellipsis($row) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@if $row == 1 {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
} @else if $row >= 2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: $row;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.organization-toolbar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
align-items: center;
|
||||
background-color: #ffffff !important;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16);
|
||||
z-index: 1;
|
||||
padding: 0;
|
||||
.organization-header {
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-items: center;
|
||||
padding: 4px 20px;
|
||||
|
||||
.organization-info {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
.organization-name {
|
||||
font-size: 0.94rem;
|
||||
line-height: normal;
|
||||
@include ellipsis(1);
|
||||
}
|
||||
}
|
||||
.organization-option {
|
||||
margin-left: auto;
|
||||
margin-right: -10px;
|
||||
.icon-button {
|
||||
transform: translateY(-2px);
|
||||
i {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.organization-content {
|
||||
position: relative;
|
||||
background: transparent;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { OrganizationComponent } from './organization.component';
|
||||
|
||||
describe('OrganizationComponent', () => {
|
||||
let component: OrganizationComponent;
|
||||
let fixture: ComponentFixture<OrganizationComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ OrganizationComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(OrganizationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,12 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-messenger-organization',
|
||||
templateUrl: './organization.component.html',
|
||||
styleUrls: ['./organization.component.scss']
|
||||
})
|
||||
export class OrganizationComponent implements OnInit {
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
}
|
|
@ -25,14 +25,12 @@
|
|||
</div>
|
||||
<div class="messenger-statusbar-actions"></div>
|
||||
</div> -->
|
||||
<app-layout-messenger-intro
|
||||
*ngIf="!(this.selectedChat$ | async)"
|
||||
></app-layout-messenger-intro>
|
||||
<app-layout-messenger-messages
|
||||
*ngIf="!!(this.selectedChat$ | async)"
|
||||
<app-layout-messenger-main-contents
|
||||
[selectedChat]="this.selectedChat$ | async"
|
||||
(openProfile)="onClickOpenProfile($event)"
|
||||
(closeRightDrawer)="onCloseRightDrawer()"
|
||||
></app-layout-messenger-messages>
|
||||
>
|
||||
</app-layout-messenger-main-contents>
|
||||
<button
|
||||
mat-icon-button
|
||||
class="left-drawer-toggle"
|
||||
|
|
|
@ -7,9 +7,11 @@ import {
|
|||
DeptInfo,
|
||||
DeptUserRequest,
|
||||
UserInfoSS,
|
||||
DeptUserResponse
|
||||
DeptUserResponse,
|
||||
SelectedDept
|
||||
} from '@ucap-webmessenger/protocol-query';
|
||||
|
||||
/** 권한 조회 */
|
||||
export const auth = createAction(
|
||||
'[Messenger::Query] Auth',
|
||||
props<AuthRequest>()
|
||||
|
@ -25,6 +27,7 @@ export const authFailure = createAction(
|
|||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
/** 부서 조회 */
|
||||
export const dept = createAction(
|
||||
'[Messenger::Query] Dept',
|
||||
props<DeptRequest>()
|
||||
|
@ -39,6 +42,39 @@ export const deptFailure = createAction(
|
|||
'[Messenger::Query] Dept Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
/** 트리 > 부서 선택 > 부서원 조회 */
|
||||
export const selectedDept = createAction(
|
||||
'[Messenger::Query] selected Department on tree',
|
||||
props<SelectedDept>()
|
||||
);
|
||||
|
||||
export const selectedDeptSuccess = createAction(
|
||||
'[Messenger::Query] selected Department on tree Success',
|
||||
props()
|
||||
);
|
||||
|
||||
export const deptUser = createAction(
|
||||
'[Messenger::Query] Dept User',
|
||||
props<DeptUserRequest>()
|
||||
);
|
||||
|
||||
export const deptUserSuccess = createAction(
|
||||
'[Messenger::Query] Dept User Success',
|
||||
props<{ userInfos: UserInfoSS[] }>()
|
||||
);
|
||||
|
||||
export const deptUserFailure = createAction(
|
||||
'[Messenger::Query] Dept User Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
/** 내 부서 조회 */
|
||||
export const selectedMyDept = createAction(
|
||||
'[Messenger::Query] selected Department on tree',
|
||||
props<SelectedDept>()
|
||||
);
|
||||
|
||||
export const myDeptUser = createAction(
|
||||
'[Messenger::Query] My Dept User',
|
||||
props<DeptUserRequest>()
|
||||
|
@ -53,3 +89,27 @@ export const myDeptUserFailure = createAction(
|
|||
'[Messenger::Query] My Dept User Failure',
|
||||
props<{ error: any }>()
|
||||
);
|
||||
|
||||
/** 조직도 > 조회 */
|
||||
export const searchDeptUser = createAction(
|
||||
'[Messenger::Query] Search Dept User',
|
||||
props<{
|
||||
companyCode: string;
|
||||
search: string;
|
||||
}>()
|
||||
);
|
||||
|
||||
export const searchDeptUserSuccess = createAction(
|
||||
'[Messenger::Query] Search Dept User Success',
|
||||
props<{ userInfos: UserInfoSS[] }>()
|
||||
);
|
||||
|
||||
export const searchDeptUserFailure = createAction(
|
||||
'[Messenger::Query] Search Dept User Failure',
|
||||
props()
|
||||
);
|
||||
|
||||
export const cancelSearchDeptUser = createAction(
|
||||
'[Messenger::Query] Cancel Search Dept User Success',
|
||||
props()
|
||||
);
|
||||
|
|
|
@ -2,8 +2,17 @@ import { Injectable } from '@angular/core';
|
|||
|
||||
import { Actions, ofType, createEffect } from '@ngrx/effects';
|
||||
|
||||
import * as StatusStore from '@app/store/messenger/status';
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { catchError, map, tap, switchMap } from 'rxjs/operators';
|
||||
import {
|
||||
catchError,
|
||||
map,
|
||||
tap,
|
||||
switchMap,
|
||||
withLatestFrom,
|
||||
take
|
||||
} from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
dept,
|
||||
|
@ -11,7 +20,16 @@ import {
|
|||
deptFailure,
|
||||
myDeptUserSuccess,
|
||||
myDeptUser,
|
||||
myDeptUserFailure
|
||||
myDeptUserFailure,
|
||||
deptUserSuccess,
|
||||
deptUser,
|
||||
selectedDept,
|
||||
deptUserFailure,
|
||||
selectedDeptSuccess,
|
||||
selectedMyDept,
|
||||
searchDeptUser,
|
||||
searchDeptUserSuccess,
|
||||
cancelSearchDeptUser
|
||||
} from './actions';
|
||||
|
||||
import {
|
||||
|
@ -24,13 +42,16 @@ import {
|
|||
SSVC_TYPE_QUERY_DEPT_USER_DATA,
|
||||
DeptUserData,
|
||||
SSVC_TYPE_QUERY_DEPT_USER_RES,
|
||||
DeptUserResponse
|
||||
DeptUserResponse,
|
||||
DeptSearchType
|
||||
} from '@ucap-webmessenger/protocol-query';
|
||||
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { KEY_LOGIN_RES_INFO } from '@app/types';
|
||||
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
|
||||
import { OrganizationService } from '@ucap-webmessenger/ui-organization';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
|
||||
@Injectable()
|
||||
export class Effects {
|
||||
|
@ -70,6 +91,209 @@ export class Effects {
|
|||
{ dispatch: false }
|
||||
);
|
||||
|
||||
selectedDept$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(selectedDept),
|
||||
withLatestFrom(
|
||||
this.store.pipe(
|
||||
select(
|
||||
(state: any) =>
|
||||
state.account.authentication.loginRes as LoginResponse
|
||||
)
|
||||
)
|
||||
),
|
||||
switchMap(([req, loginResInfo]) => {
|
||||
return this.organizationService
|
||||
.getDeptUser({
|
||||
divCd: 'ORG',
|
||||
companyCode: loginResInfo.companyCode,
|
||||
seq: req.seq,
|
||||
search: '',
|
||||
searchRange: DeptSearchType.All,
|
||||
senderCompanyCode: loginResInfo.companyCode,
|
||||
senderEmployeeType: loginResInfo.userInfo.employeeType
|
||||
})
|
||||
.pipe(
|
||||
map(datas => {
|
||||
const userInfos: UserInfoSS[] = datas.userInfos;
|
||||
|
||||
this.store.dispatch(
|
||||
deptUserSuccess({
|
||||
userInfos
|
||||
})
|
||||
);
|
||||
|
||||
// 검색 결과에 따른 프레즌스 조회.
|
||||
const userSeqList: number[] = [];
|
||||
userInfos.map(user => userSeqList.push(user.seq));
|
||||
if (userSeqList.length > 0) {
|
||||
this.store.dispatch(
|
||||
StatusStore.bulkInfo({
|
||||
divCd: 'orgtrSrch',
|
||||
userSeqs: userSeqList
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
this.store.dispatch(selectedDeptSuccess({}));
|
||||
}),
|
||||
catchError(error => of(deptUserFailure({ error })))
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
selectedMyDept$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(selectedMyDept),
|
||||
withLatestFrom(
|
||||
this.store.pipe(
|
||||
select(
|
||||
(state: any) =>
|
||||
state.account.authentication.loginRes as LoginResponse
|
||||
)
|
||||
)
|
||||
),
|
||||
switchMap(([req, loginResInfo]) => {
|
||||
return this.organizationService
|
||||
.getDeptUser({
|
||||
divCd: 'ORG_MY',
|
||||
companyCode: loginResInfo.companyCode,
|
||||
seq: req.seq,
|
||||
search: '',
|
||||
searchRange: DeptSearchType.All,
|
||||
senderCompanyCode: loginResInfo.companyCode,
|
||||
senderEmployeeType: loginResInfo.userInfo.employeeType
|
||||
})
|
||||
.pipe(
|
||||
map(datas => {
|
||||
const userInfos: UserInfoSS[] = datas.userInfos;
|
||||
|
||||
this.store.dispatch(
|
||||
deptUserSuccess({
|
||||
userInfos
|
||||
})
|
||||
);
|
||||
this.store.dispatch(
|
||||
myDeptUserSuccess({
|
||||
userInfos
|
||||
})
|
||||
);
|
||||
|
||||
this.store.dispatch(selectedDeptSuccess({}));
|
||||
}),
|
||||
catchError(error => of(myDeptUserFailure({ error })))
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
searchDeptUser$ = createEffect(
|
||||
() => {
|
||||
return this.actions$.pipe(
|
||||
ofType(searchDeptUser),
|
||||
withLatestFrom(
|
||||
this.store.pipe(
|
||||
select(
|
||||
(state: any) =>
|
||||
state.account.authentication.loginRes as LoginResponse
|
||||
)
|
||||
)
|
||||
),
|
||||
switchMap(([req, loginResInfo]) => {
|
||||
return this.organizationService
|
||||
.getDeptUser({
|
||||
divCd: 'ORG_SRCH',
|
||||
companyCode: req.companyCode,
|
||||
search: req.search,
|
||||
searchRange: DeptSearchType.All,
|
||||
senderCompanyCode: loginResInfo.companyCode,
|
||||
senderEmployeeType: loginResInfo.userInfo.employeeType
|
||||
})
|
||||
.pipe(
|
||||
map(datas => {
|
||||
const userInfos: UserInfoSS[] = datas.userInfos;
|
||||
|
||||
this.store.dispatch(
|
||||
searchDeptUserSuccess({
|
||||
userInfos
|
||||
})
|
||||
);
|
||||
|
||||
// 검색 결과에 따른 프레즌스 조회.
|
||||
const userSeqList: number[] = [];
|
||||
userInfos.map(user => userSeqList.push(user.seq));
|
||||
if (userSeqList.length > 0) {
|
||||
this.store.dispatch(
|
||||
StatusStore.bulkInfo({
|
||||
divCd: 'orgtrSrch',
|
||||
userSeqs: userSeqList
|
||||
})
|
||||
);
|
||||
}
|
||||
}),
|
||||
catchError(error => of(deptUserFailure({ error })))
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
deptUser$ = createEffect(
|
||||
() => {
|
||||
let userInfos: UserInfoSS[];
|
||||
|
||||
return this.actions$.pipe(
|
||||
ofType(deptUser),
|
||||
tap(() => {
|
||||
userInfos = [];
|
||||
}),
|
||||
switchMap(req => {
|
||||
return this.queryProtocolService.deptUser(req).pipe(
|
||||
map(res => {
|
||||
switch (res.SSVC_TYPE) {
|
||||
case SSVC_TYPE_QUERY_DEPT_USER_DATA:
|
||||
userInfos.push(...(res as DeptUserData).userInfos);
|
||||
break;
|
||||
case SSVC_TYPE_QUERY_DEPT_USER_RES:
|
||||
userInfos.sort((a, b) =>
|
||||
a.order < b.order
|
||||
? -1
|
||||
: a.order > b.order
|
||||
? 1
|
||||
: a.name < b.name
|
||||
? -1
|
||||
: a.name > b.name
|
||||
? 1
|
||||
: 0
|
||||
);
|
||||
|
||||
this.store.dispatch(
|
||||
deptUserSuccess({
|
||||
userInfos
|
||||
})
|
||||
);
|
||||
this.store.dispatch(
|
||||
myDeptUserSuccess({
|
||||
userInfos
|
||||
})
|
||||
);
|
||||
break;
|
||||
}
|
||||
}),
|
||||
catchError(error => of(deptUserFailure({ error })))
|
||||
);
|
||||
})
|
||||
);
|
||||
},
|
||||
{ dispatch: false }
|
||||
);
|
||||
|
||||
myDeptUser$ = createEffect(
|
||||
() => {
|
||||
let userInfos: UserInfoSS[];
|
||||
|
@ -99,6 +323,11 @@ export class Effects {
|
|||
: 0
|
||||
);
|
||||
|
||||
this.store.dispatch(
|
||||
deptUserSuccess({
|
||||
userInfos
|
||||
})
|
||||
);
|
||||
this.store.dispatch(
|
||||
myDeptUserSuccess({
|
||||
userInfos
|
||||
|
@ -119,6 +348,8 @@ export class Effects {
|
|||
private actions$: Actions,
|
||||
private store: Store<any>,
|
||||
private queryProtocolService: QueryProtocolService,
|
||||
private sessionStorageService: SessionStorageService
|
||||
private organizationService: OrganizationService,
|
||||
private sessionStorageService: SessionStorageService,
|
||||
private logger: NGXLogger
|
||||
) {}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
import { createReducer, on } from '@ngrx/store';
|
||||
import { initialState } from './state';
|
||||
import { authSuccess, deptSuccess, myDeptUserSuccess } from './actions';
|
||||
import {
|
||||
authSuccess,
|
||||
deptSuccess,
|
||||
myDeptUserSuccess,
|
||||
deptUserSuccess,
|
||||
selectedDept,
|
||||
selectedDeptSuccess,
|
||||
searchDeptUser,
|
||||
searchDeptUserSuccess,
|
||||
searchDeptUserFailure,
|
||||
deptUserFailure,
|
||||
cancelSearchDeptUser,
|
||||
myDeptUserFailure
|
||||
} from './actions';
|
||||
|
||||
import * as AuthenticationStore from '@app/store/account/authentication';
|
||||
|
||||
|
@ -20,12 +33,76 @@ export const reducer = createReducer(
|
|||
};
|
||||
}),
|
||||
|
||||
on(selectedDept, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
selectedDepartment: action,
|
||||
selectedDepartmentProcessing: true
|
||||
};
|
||||
}),
|
||||
on(selectedDeptSuccess, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
selectedDepartmentProcessing: false
|
||||
};
|
||||
}),
|
||||
|
||||
on(deptUserSuccess, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
departmentUserInfoList: action.userInfos
|
||||
};
|
||||
}),
|
||||
on(deptUserFailure, state => {
|
||||
return {
|
||||
...state,
|
||||
selectedDepartmentProcessing: false
|
||||
};
|
||||
}),
|
||||
|
||||
on(myDeptUserSuccess, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
myDepartmentUserInfoList: action.userInfos
|
||||
};
|
||||
}),
|
||||
on(myDeptUserFailure, state => {
|
||||
return {
|
||||
...state,
|
||||
selectedDepartmentProcessing: false
|
||||
};
|
||||
}),
|
||||
|
||||
on(searchDeptUser, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
isSearch: true,
|
||||
selectedDepartmentProcessing: true
|
||||
};
|
||||
}),
|
||||
|
||||
on(searchDeptUserSuccess, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
searchDepartmentUserInfoList: action.userInfos,
|
||||
selectedDepartmentProcessing: false
|
||||
};
|
||||
}),
|
||||
|
||||
on(searchDeptUserFailure, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
selectedDepartmentProcessing: false
|
||||
};
|
||||
}),
|
||||
|
||||
on(cancelSearchDeptUser, (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
isSearch: false,
|
||||
searchDepartmentUserInfoList: null
|
||||
};
|
||||
}),
|
||||
|
||||
on(AuthenticationStore.logoutInitialize, (state, action) => {
|
||||
return {
|
||||
|
|
|
@ -2,7 +2,8 @@ import { Selector, createSelector } from '@ngrx/store';
|
|||
import {
|
||||
AuthResponse,
|
||||
DeptInfo,
|
||||
UserInfoSS
|
||||
UserInfoSS,
|
||||
SelectedDept
|
||||
} from '@ucap-webmessenger/protocol-query';
|
||||
|
||||
export interface State {
|
||||
|
@ -10,12 +11,25 @@ export interface State {
|
|||
|
||||
departmentInfoList: DeptInfo[] | null;
|
||||
|
||||
isSearch: boolean;
|
||||
selectedDepartmentProcessing: boolean;
|
||||
selectedDepartment: SelectedDept | null;
|
||||
|
||||
searchDepartmentUserInfoList: UserInfoSS[] | null;
|
||||
departmentUserInfoList: UserInfoSS[] | null;
|
||||
myDepartmentUserInfoList: UserInfoSS[] | null;
|
||||
}
|
||||
|
||||
export const initialState: State = {
|
||||
auth: null,
|
||||
departmentInfoList: null,
|
||||
|
||||
isSearch: false,
|
||||
selectedDepartmentProcessing: false,
|
||||
selectedDepartment: null,
|
||||
|
||||
searchDepartmentUserInfoList: null,
|
||||
departmentUserInfoList: null,
|
||||
myDepartmentUserInfoList: null
|
||||
};
|
||||
|
||||
|
@ -26,6 +40,25 @@ export function selectors<S>(selector: Selector<any, State>) {
|
|||
selector,
|
||||
(state: State) => state.departmentInfoList
|
||||
),
|
||||
|
||||
isSearch: createSelector(selector, (state: State) => state.isSearch),
|
||||
selectedDepartmentProcessing: createSelector(
|
||||
selector,
|
||||
(state: State) => state.selectedDepartmentProcessing
|
||||
),
|
||||
selectedDepartment: createSelector(
|
||||
selector,
|
||||
(state: State) => state.selectedDepartment
|
||||
),
|
||||
|
||||
searchDepartmentUserInfoList: createSelector(
|
||||
selector,
|
||||
(state: State) => state.searchDepartmentUserInfoList
|
||||
),
|
||||
departmentUserInfoList: createSelector(
|
||||
selector,
|
||||
(state: State) => state.myDepartmentUserInfoList
|
||||
),
|
||||
myDepartmentUserInfoList: createSelector(
|
||||
selector,
|
||||
(state: State) => state.myDepartmentUserInfoList
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import { DeptType } from '../types/dept.type';
|
||||
|
||||
export interface SelectedDept {
|
||||
/** 부서SEQ */
|
||||
seq: number;
|
||||
/** 부서명 */
|
||||
name: string;
|
||||
/** 부서명(영어) */
|
||||
nameEn: string;
|
||||
/** 부서명(중국어) */
|
||||
nameCn: string;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
export * from './lib/models/dept-info';
|
||||
export * from './lib/models/selected-dept';
|
||||
export * from './lib/models/user-info-dn';
|
||||
export * from './lib/models/user-info-f';
|
||||
export * from './lib/models/user-info-ss';
|
||||
|
|
Loading…
Reference in New Issue
Block a user