refactoring of organization

This commit is contained in:
richard-loafle 2020-02-04 11:27:48 +09:00
parent af582b0c8e
commit b314a72bad
11 changed files with 256 additions and 186 deletions

View File

@ -32,6 +32,7 @@ import { UCapSyncProtocolModule } from '@ucap-webmessenger/protocol-sync';
import { UCapUiModule } from '@ucap-webmessenger/ui'; import { UCapUiModule } from '@ucap-webmessenger/ui';
import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account'; import { UCapUiAccountModule } from '@ucap-webmessenger/ui-account';
import { UCapUiOrganizationModule } from '@ucap-webmessenger/ui-organization';
import { UCapDaesangModule } from '@ucap-webmessenger/daesang'; import { UCapDaesangModule } from '@ucap-webmessenger/daesang';
@ -86,6 +87,7 @@ import { environment } from '../environments/environment';
UCapUiModule.forRoot(), UCapUiModule.forRoot(),
UCapUiAccountModule.forRoot(), UCapUiAccountModule.forRoot(),
UCapUiOrganizationModule.forRoot(),
UCapWebStorageModule.forRoot(), UCapWebStorageModule.forRoot(),

View File

@ -67,6 +67,7 @@ import {
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { StringFormatterPhonePipe } from 'projects/ucap-webmessenger-ui/src/lib/pipes/string.pipe'; import { StringFormatterPhonePipe } from 'projects/ucap-webmessenger-ui/src/lib/pipes/string.pipe';
import { VirtualScrollerComponent } from 'ngx-virtual-scroller'; import { VirtualScrollerComponent } from 'ngx-virtual-scroller';
import { OrganizationService } from '@ucap-webmessenger/ui-organization';
@Component({ @Component({
selector: 'app-layout-chat-left-sidenav-organization', selector: 'app-layout-chat-left-sidenav-organization',
@ -132,17 +133,17 @@ export class OrganizationComponent
companyCode: string; companyCode: string;
departmentInfoList$: Observable<DeptInfo[]>; departmentInfoList$: Observable<DeptInfo[]>;
selectedDepartmentUserInfoList: UserInfoSS[] = []; selectedDepartmentUserInfoList: UserInfoSS[];
selectedDepartmentUserInfoListSubscription: Subscription;
selectedDepartmentStatus$: Observable<DeptUserResponse>;
selectedDepartmentProcessing = false; selectedDepartmentProcessing = false;
selectedDepartmentProcessingSubscription: Subscription;
selectedDepartmentName: { selectedDepartmentName: {
name: string; name: string;
nameEn: string; nameEn: string;
nameCn: string; nameCn: string;
}; };
myDepartmentUserInfoList: UserInfoSS[] = [];
myDepartmentUserInfoListSubscription: Subscription;
loginInfo: LoginInfo; loginInfo: LoginInfo;
loginRes: LoginResponse; loginRes: LoginResponse;
sessionVerinfo: VersionInfo2Response; sessionVerinfo: VersionInfo2Response;
@ -159,6 +160,7 @@ export class OrganizationComponent
private store: Store<any>, private store: Store<any>,
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
private queryProtocolService: QueryProtocolService, private queryProtocolService: QueryProtocolService,
private organizationService: OrganizationService,
private dialogService: DialogService, private dialogService: DialogService,
private translateService: TranslateService, private translateService: TranslateService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
@ -184,41 +186,25 @@ export class OrganizationComponent
select(AppStore.MessengerSelector.QuerySelector.departmentInfoList) select(AppStore.MessengerSelector.QuerySelector.departmentInfoList)
); );
this.selectedDepartmentProcessingSubscription = this.store this.myDepartmentUserInfoListSubscription = this.store
.pipe( .pipe(
delay(0),
select( select(
AppStore.MessengerSelector.QuerySelector.selectedDepartmentProcessing AppStore.MessengerSelector.QuerySelector.myDepartmentUserInfoList
),
tap(processing => {
this.selectedDepartmentProcessing = processing;
})
) )
.subscribe(); )
.subscribe(list => {
this.selectedDepartmentUserInfoListSubscription = this.store this.myDepartmentUserInfoList = list;
.pipe( if (!this.selectedDepartmentUserInfoList) {
select(
AppStore.MessengerSelector.QuerySelector
.selectedDepartmentUserInfoList
),
map(list => {
this.selectedDepartmentUserInfoList = list; this.selectedDepartmentUserInfoList = list;
}), }
tap(() => {
if (!!this.vsDeptUser) { if (!!this.vsDeptUser) {
this.vsDeptUser.scrollToIndex(0, true, 0, 0); this.vsDeptUser.scrollToIndex(0, true, 0, 0);
} }
if (!!this.psDirectiveRef) { if (!!this.psDirectiveRef) {
this.psDirectiveRef.update(); this.psDirectiveRef.update();
} }
}) });
)
.subscribe();
this.selectedDepartmentStatus$ = this.store.pipe(
select(AppStore.MessengerSelector.QuerySelector.selectedDepartmentStatus)
);
this.store this.store
.pipe( .pipe(
@ -226,7 +212,7 @@ export class OrganizationComponent
select(AppStore.AccountSelector.AuthenticationSelector.loginRes), select(AppStore.AccountSelector.AuthenticationSelector.loginRes),
map(loginRes => { map(loginRes => {
this.store.dispatch( this.store.dispatch(
QueryStore.deptUser({ QueryStore.myDeptUser({
divCd: 'ORG', divCd: 'ORG',
companyCode: this.loginInfo.companyCode, companyCode: this.loginInfo.companyCode,
seq: loginRes.departmentCode, seq: loginRes.departmentCode,
@ -263,11 +249,8 @@ export class OrganizationComponent
} }
ngOnDestroy(): void { ngOnDestroy(): void {
if (!!this.selectedDepartmentUserInfoListSubscription) { if (!!this.myDepartmentUserInfoListSubscription) {
this.selectedDepartmentUserInfoListSubscription.unsubscribe(); this.myDepartmentUserInfoListSubscription.unsubscribe();
}
if (!!this.selectedDepartmentProcessingSubscription) {
this.selectedDepartmentProcessingSubscription.unsubscribe();
} }
} }
@ -279,9 +262,9 @@ export class OrganizationComponent
if (params.searchWord.trim().length > 1) { if (params.searchWord.trim().length > 1) {
this.isShowSearch = true; this.isShowSearch = true;
this.selectedDepartmentProcessing = true; this.selectedDepartmentProcessing = true;
const searchUserInfos: UserInfoSS[] = [];
this.queryProtocolService this.organizationService
.deptUser({ .getDeptUser({
divCd: 'GRP', divCd: 'GRP',
companyCode: params.companyCode, companyCode: params.companyCode,
searchRange: DeptSearchType.All, searchRange: DeptSearchType.All,
@ -289,22 +272,10 @@ export class OrganizationComponent
senderCompanyCode: params.companyCode, senderCompanyCode: params.companyCode,
senderEmployeeType: this.loginRes.userInfo.employeeType senderEmployeeType: this.loginRes.userInfo.employeeType
}) })
.pipe( .pipe(take(1))
map(res => { .subscribe(
switch (res.SSVC_TYPE) { datas => {
case SSVC_TYPE_QUERY_DEPT_USER_DATA: this.searchUserInfos = datas.userInfos;
const userInfos = (res as DeptUserData).userInfos;
// searchUserInfos.push(
// ...userInfos.filter(
// userInfo => userInfo.seq !== this.loginRes.userSeq
// )
// );
searchUserInfos.push(...userInfos);
break;
case SSVC_TYPE_QUERY_DEPT_USER_RES:
{
// 검색 결과 처리.
this.searchUserInfos = searchUserInfos;
this.selectedDepartmentProcessing = false; this.selectedDepartmentProcessing = false;
if (!!this.vsDeptSearchUser) { if (!!this.vsDeptSearchUser) {
@ -313,16 +284,59 @@ export class OrganizationComponent
if (!!this.psDirectiveRef) { if (!!this.psDirectiveRef) {
this.psDirectiveRef.update(); this.psDirectiveRef.update();
} }
} },
break; error => {
} this.logger.error(error);
}), },
catchError(error => { () => {
this.selectedDepartmentProcessing = false; this.selectedDepartmentProcessing = false;
return of(this.logger.error(error)); }
}) );
)
.subscribe(); // 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:
// const userInfos = (res as DeptUserData).userInfos;
// // searchUserInfos.push(
// // ...userInfos.filter(
// // userInfo => userInfo.seq !== this.loginRes.userSeq
// // )
// // );
// searchUserInfos.push(...userInfos);
// break;
// case SSVC_TYPE_QUERY_DEPT_USER_RES:
// {
// // 검색 결과 처리.
// this.searchUserInfos = searchUserInfos;
// this.selectedDepartmentProcessing = false;
// if (!!this.vsDeptSearchUser) {
// this.vsDeptSearchUser.scrollToIndex(0);
// }
// if (!!this.psDirectiveRef) {
// this.psDirectiveRef.update();
// }
// }
// break;
// }
// }),
// catchError(error => {
// this.selectedDepartmentProcessing = false;
// return of(this.logger.error(error));
// })
// )
// .subscribe();
} }
} }
/** 검색 취소 */ /** 검색 취소 */
@ -334,13 +348,16 @@ export class OrganizationComponent
onSelectedOrganization(deptInfo: DeptInfo) { onSelectedOrganization(deptInfo: DeptInfo) {
this.onClickCancel(); this.onClickCancel();
this.selectedDepartmentName = deptInfo;
this.selectedDepartmentProcessing = true;
this.store this.store
.pipe( .pipe(
take(1), take(1),
select(AppStore.AccountSelector.AuthenticationSelector.loginRes), select(AppStore.AccountSelector.AuthenticationSelector.loginRes)
map(loginRes => { )
this.store.dispatch( .subscribe(loginRes => {
QueryStore.deptUser({ this.organizationService
.getDeptUser({
divCd: 'ORG', divCd: 'ORG',
companyCode: this.loginInfo.companyCode, companyCode: this.loginInfo.companyCode,
seq: deptInfo.seq, seq: deptInfo.seq,
@ -349,13 +366,50 @@ export class OrganizationComponent
senderCompanyCode: this.loginInfo.companyCode, senderCompanyCode: this.loginInfo.companyCode,
senderEmployeeType: loginRes.userInfo.employeeType senderEmployeeType: loginRes.userInfo.employeeType
}) })
.pipe(take(1))
.subscribe(
datas => {
// this.logger.debug('onSelectedOrganization', datas);
this.selectedDepartmentUserInfoList = datas.userInfos;
if (!!this.vsDeptUser) {
this.vsDeptUser.scrollToIndex(0, true, 0, 0);
}
if (!!this.psDirectiveRef) {
this.psDirectiveRef.update();
}
},
error => {
this.logger.error(error);
},
() => {
this.selectedDepartmentProcessing = false;
}
); );
}), });
map(() => {
this.selectedDepartmentName = deptInfo; // this.store
}) // .pipe(
) // take(1),
.subscribe(); // select(AppStore.AccountSelector.AuthenticationSelector.loginRes),
// map(loginRes => {
// this.store.dispatch(
// QueryStore.deptUser({
// divCd: 'ORG',
// companyCode: this.loginInfo.companyCode,
// seq: deptInfo.seq,
// search: '',
// searchRange: DeptSearchType.All,
// senderCompanyCode: this.loginInfo.companyCode,
// senderEmployeeType: loginRes.userInfo.employeeType
// })
// );
// }),
// map(() => {
// this.selectedDepartmentName = deptInfo;
// })
// )
// .subscribe();
} }
/** 전체 체크여부 */ /** 전체 체크여부 */

View File

@ -39,22 +39,17 @@ export const deptFailure = createAction(
'[Messenger::Query] Dept Failure', '[Messenger::Query] Dept Failure',
props<{ error: any }>() props<{ error: any }>()
); );
export const deptUser = createAction( export const myDeptUser = createAction(
'[Messenger::Query] Dept User', '[Messenger::Query] My Dept User',
props<DeptUserRequest>() props<DeptUserRequest>()
); );
export const deptUserSuccess = createAction(
'[Messenger::Query] Dept User Success',
props<{ userInfos: UserInfoSS[]; res: DeptUserResponse }>()
);
export const deptUserFailure = createAction(
'[Messenger::Query] Dept User Failure',
props<{ error: any }>()
);
export const myDeptUserSuccess = createAction( export const myDeptUserSuccess = createAction(
'[Messenger::Query] My Dept User Success', '[Messenger::Query] My Dept User Success',
props<{ userInfos: UserInfoSS[] }>() props<{ userInfos: UserInfoSS[] }>()
); );
export const myDeptUserFailure = createAction(
'[Messenger::Query] My Dept User Failure',
props<{ error: any }>()
);

View File

@ -9,10 +9,9 @@ import {
dept, dept,
deptSuccess, deptSuccess,
deptFailure, deptFailure,
deptUser, myDeptUserSuccess,
deptUserSuccess, myDeptUser,
deptUserFailure, myDeptUserFailure
myDeptUserSuccess
} from './actions'; } from './actions';
import { import {
@ -71,12 +70,12 @@ export class Effects {
{ dispatch: false } { dispatch: false }
); );
deptUser$ = createEffect( myDeptUser$ = createEffect(
() => { () => {
let userInfos: UserInfoSS[]; let userInfos: UserInfoSS[];
return this.actions$.pipe( return this.actions$.pipe(
ofType(deptUser), ofType(myDeptUser),
tap(() => { tap(() => {
userInfos = []; userInfos = [];
}), }),
@ -100,28 +99,15 @@ export class Effects {
: 0 : 0
); );
this.store.dispatch(
deptUserSuccess({
userInfos,
res: res as DeptUserResponse
})
);
const loginResInfo: LoginResponse = this.sessionStorageService.get<
LoginResponse
>(KEY_LOGIN_RES_INFO);
if (req.seq === loginResInfo.departmentCode) {
this.store.dispatch( this.store.dispatch(
myDeptUserSuccess({ myDeptUserSuccess({
userInfos userInfos
}) })
); );
}
break; break;
} }
}), }),
catchError(error => of(deptUserFailure({ error }))) catchError(error => of(myDeptUserFailure({ error })))
); );
}) })
); );

View File

@ -1,13 +1,6 @@
import { createReducer, on } from '@ngrx/store'; import { createReducer, on } from '@ngrx/store';
import { initialState } from './state'; import { initialState } from './state';
import { import { authSuccess, deptSuccess, myDeptUserSuccess } from './actions';
authSuccess,
deptSuccess,
deptUserSuccess,
deptUser,
deptUserFailure,
myDeptUserSuccess
} from './actions';
import * as AuthenticationStore from '@app/store/account/authentication'; import * as AuthenticationStore from '@app/store/account/authentication';
@ -27,29 +20,6 @@ export const reducer = createReducer(
}; };
}), }),
on(deptUser, (state, action) => {
return {
...state,
selectedDepartmentProcessing: true
};
}),
on(deptUserSuccess, (state, action) => {
return {
...state,
selectedDepartmentUserInfoList: action.userInfos,
selectedDepartmentStatus: action.res,
selectedDepartmentProcessing: false
};
}),
on(deptUserFailure, (state, action) => {
return {
...state,
selectedDepartmentProcessing: false
};
}),
on(myDeptUserSuccess, (state, action) => { on(myDeptUserSuccess, (state, action) => {
return { return {
...state, ...state,

View File

@ -2,8 +2,7 @@ import { Selector, createSelector } from '@ngrx/store';
import { import {
AuthResponse, AuthResponse,
DeptInfo, DeptInfo,
UserInfoSS, UserInfoSS
DeptUserResponse
} from '@ucap-webmessenger/protocol-query'; } from '@ucap-webmessenger/protocol-query';
export interface State { export interface State {
@ -11,19 +10,12 @@ export interface State {
departmentInfoList: DeptInfo[] | null; departmentInfoList: DeptInfo[] | null;
selectedDepartmentUserInfoList: UserInfoSS[] | null;
selectedDepartmentStatus: DeptUserResponse | null;
selectedDepartmentProcessing: boolean;
myDepartmentUserInfoList: UserInfoSS[] | null; myDepartmentUserInfoList: UserInfoSS[] | null;
} }
export const initialState: State = { export const initialState: State = {
auth: null, auth: null,
departmentInfoList: null, departmentInfoList: null,
selectedDepartmentUserInfoList: null,
selectedDepartmentStatus: null,
selectedDepartmentProcessing: false,
myDepartmentUserInfoList: null myDepartmentUserInfoList: null
}; };
@ -34,18 +26,6 @@ export function selectors<S>(selector: Selector<any, State>) {
selector, selector,
(state: State) => state.departmentInfoList (state: State) => state.departmentInfoList
), ),
selectedDepartmentUserInfoList: createSelector(
selector,
(state: State) => state.selectedDepartmentUserInfoList
),
selectedDepartmentStatus: createSelector(
selector,
(state: State) => state.selectedDepartmentStatus
),
selectedDepartmentProcessing: createSelector(
selector,
(state: State) => state.selectedDepartmentProcessing
),
myDepartmentUserInfoList: createSelector( myDepartmentUserInfoList: createSelector(
selector, selector,
(state: State) => state.myDepartmentUserInfoList (state: State) => state.myDepartmentUserInfoList

View File

@ -54,9 +54,6 @@ interface FlatNode {
] ]
}) })
export class TreeComponent implements OnInit, OnDestroy, AfterViewInit { export class TreeComponent implements OnInit, OnDestroy, AfterViewInit {
@Output()
selected = new EventEmitter<DeptInfo>();
@Input() @Input()
loginRes: LoginResponse; loginRes: LoginResponse;
@ -106,6 +103,9 @@ export class TreeComponent implements OnInit, OnDestroy, AfterViewInit {
this.dataSource.data = rootNodeList; this.dataSource.data = rootNodeList;
} }
@Output()
selected = new EventEmitter<DeptInfo>();
@ViewChild('cvsvOrganization', { static: false }) @ViewChild('cvsvOrganization', { static: false })
cvsvOrganization: CdkVirtualScrollViewport; cvsvOrganization: CdkVirtualScrollViewport;

View File

@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { OrganizationService } from './organization.service';
describe('UIOrganization::OrganizationService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: OrganizationService = TestBed.get(OrganizationService);
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,64 @@
import { Injectable } from '@angular/core';
import {
QueryProtocolService,
DeptUserRequest,
UserInfoSS,
DeptUserResponse,
SSVC_TYPE_QUERY_DEPT_USER_DATA,
DeptUserData,
SSVC_TYPE_QUERY_DEPT_USER_RES
} from '@ucap-webmessenger/protocol-query';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class OrganizationService {
constructor(private queryProtocolService: QueryProtocolService) {}
getDeptUser(
req: DeptUserRequest
): Observable<{ userInfos: UserInfoSS[]; res: DeptUserResponse }> {
return new Observable<{ userInfos: UserInfoSS[]; res: DeptUserResponse }>(
subscriber => {
const userInfos: UserInfoSS[] = [];
this.queryProtocolService
.deptUser(req)
.pipe()
.subscribe(
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
);
subscriber.next({ userInfos, res: res as DeptUserResponse });
break;
}
},
error => {
subscriber.error(error);
},
() => {
subscriber.complete();
}
);
}
);
}
}

View File

@ -15,14 +15,18 @@ import { MatSelectModule } from '@angular/material/select';
import { MatTreeModule } from '@angular/material/tree'; import { MatTreeModule } from '@angular/material/tree';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar'; import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
import { VirtualScrollerModule } from 'ngx-virtual-scroller';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { UCapUiModule } from '@ucap-webmessenger/ui'; import { UCapUiModule } from '@ucap-webmessenger/ui';
import { TenantSearchComponent } from './components/tenant-search.component'; import { TenantSearchComponent } from './components/tenant-search.component';
import { TreeComponent } from './components/tree.component'; import { TreeComponent } from './components/tree.component';
import { OrganizationService } from './services/organization.service';
const COMPONENTS = [TenantSearchComponent, TreeComponent]; const COMPONENTS = [TenantSearchComponent, TreeComponent];
const SERVICES = []; const SERVICES = [OrganizationService];
const DIRECTIVES = [];
@NgModule({ @NgModule({
imports: [ imports: [
@ -42,11 +46,12 @@ const SERVICES = [];
TranslateModule, TranslateModule,
PerfectScrollbarModule, PerfectScrollbarModule,
VirtualScrollerModule,
UCapUiModule UCapUiModule
], ],
exports: [...COMPONENTS], exports: [...COMPONENTS, ...DIRECTIVES],
declarations: [...COMPONENTS] declarations: [...COMPONENTS, ...DIRECTIVES]
}) })
export class UCapUiOrganizationModule { export class UCapUiOrganizationModule {
public static forRoot(): ModuleWithProviders<UCapUiOrganizationModule> { public static forRoot(): ModuleWithProviders<UCapUiOrganizationModule> {

View File

@ -4,4 +4,6 @@
export * from './lib/components/tenant-search.component'; export * from './lib/components/tenant-search.component';
export * from './lib/components/tree.component'; export * from './lib/components/tree.component';
export * from './lib/services/organization.service';
export * from './lib/ucap-ui-organization.module'; export * from './lib/ucap-ui-organization.module';