import { Subject } from 'rxjs'; import { takeUntil, take } from 'rxjs/operators'; import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, EventEmitter, NgZone } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { SortOrder } from '@ucap/core'; import { VersionInfo2Response } from '@ucap/api-public'; import { LoginResponse } from '@ucap/protocol-authentication'; import { UserInfoSS, DeptSearchType, DeptUserRequest } from '@ucap/protocol-query'; import { LogService } from '@ucap/ng-logger'; import { LoginSelector, ConfigurationSelector } from '@ucap/ng-store-authentication'; import { QueryProtocolService } from '@ucap/ng-protocol-query'; import { DepartmentActions, DepartmentSelector, PresenceActions } from '@ucap/ng-store-organization'; import { SearchData } from '../models/search-data'; const DEPT_ORDER_PROPERTY = 'order'; interface CheckedInfo { checked: boolean; userInfo: UserInfoSS; } @Component({ selector: 'app-organization-profile-list', templateUrl: './profile-list.component.html', styleUrls: ['./profile-list.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush }) export class ProfileListComponent implements OnInit, OnDestroy { @Input() set searchData(data: SearchData) { if (!this.loginRes) { this._searchData = data; return; } this.searchMember(data); } // tslint:disable-next-line: variable-name private _searchData: SearchData; @Input() selectedUser: UserInfoSS[]; @Input() /** Cycle order of sorting by use ascending: undefined -> true -> false */ set sortOrder(value: SortOrder) { this._sortOrder = value; this.userInfos = this.sort(this.userInfos); } get sortOrder() { return this._sortOrder; } // tslint:disable-next-line: variable-name _sortOrder: SortOrder = { property: 'name', ascending: undefined }; @Output() searched: EventEmitter = new EventEmitter(); @Output() changedCheck: EventEmitter = new EventEmitter(); set userInfos(userInfos: UserInfoSS[]) { this._userInfos = userInfos; this.searched.emit(userInfos); } get userInfos() { return this._userInfos; } // tslint:disable-next-line: variable-name _userInfos: UserInfoSS[] = []; loginRes: LoginResponse; versionInfo2Res: VersionInfo2Response; processing = false; private ngOnDestroySubject: Subject = new Subject(); private myDeptDestroySubject: Subject; constructor( private queryProtocolService: QueryProtocolService, private store: Store, private changeDetectorRef: ChangeDetectorRef, private logService: LogService ) {} ngOnInit(): void { this.store .pipe( takeUntil(this.ngOnDestroySubject), select(ConfigurationSelector.versionInfo2Response) ) .subscribe((versionInfo2Res) => { this.versionInfo2Res = versionInfo2Res; }); this.store .pipe(takeUntil(this.ngOnDestroySubject), select(LoginSelector.loginRes)) .subscribe((loginRes) => { this.loginRes = loginRes; if (!!this._searchData) { this.searchMember(this._searchData); this._searchData = undefined; } }); } ngOnDestroy(): void { if (!!this.ngOnDestroySubject) { this.ngOnDestroySubject.next(); this.ngOnDestroySubject.complete(); } } checkAll() { if (!this.userInfos || 0 === this.userInfos.length) { return; } const checked: CheckedInfo[] = []; this.userInfos.forEach((u) => { checked.push({ checked: true, userInfo: u }); }); this.changedCheck.emit(checked); } uncheckAll() { if (!this.userInfos || 0 === this.userInfos.length) { return; } const unchecked: CheckedInfo[] = []; this.userInfos.forEach((u) => { unchecked.push({ checked: false, userInfo: u }); }); this.changedCheck.emit(unchecked); } /** 개별 체크여부 */ getCheckedUser(userInfo: UserInfoSS) { if (!!this.selectedUser && this.selectedUser.length > 0) { return ( this.selectedUser.filter((item) => item.seq === userInfo.seq).length > 0 ); } return false; } /** 개별선택(토글) 이벤트 */ onChangeCheckUser(param: { checked: boolean; userInfo: UserInfoSS }) { this.changedCheck.emit([param]); } onOpenProfile(userInfo: UserInfoSS): void { alert('Open Profile'); } private getMyDeptMember() { this.myDeptDestroySubject = new Subject(); const req: DeptUserRequest = { divCd: 'ORG', companyCode: this.loginRes.companyCode, seq: this.loginRes.departmentCode, search: '', searchRange: DeptSearchType.All, senderCompanyCode: this.loginRes.companyCode, senderEmployeeType: this.loginRes.userInfo.employeeType }; this.processing = true; this.store .pipe( takeUntil(this.myDeptDestroySubject), select(DepartmentSelector.myDepartmentUserInfoList) ) .subscribe( (myDepartmentUserInfoList) => { if (!myDepartmentUserInfoList) { this.store.dispatch(DepartmentActions.myDeptUser({ req })); return; } this._refreshUserInfos(myDepartmentUserInfoList); this.myDeptDestroySubject.next(); this.myDeptDestroySubject.complete(); this.myDeptDestroySubject = undefined; }, (error) => {}, () => { this.processing = false; } ); } private sort(userInfos: UserInfoSS[]): UserInfoSS[] { if (!userInfos || 0 === userInfos.length) { return userInfos; } const property = this.sortOrder.property; const ascending = this.sortOrder.ascending; let deptA: any; let deptB: any; let c: any; let d: any; return userInfos.slice().sort((a, b) => { try { deptA = a[DEPT_ORDER_PROPERTY]; deptB = b[DEPT_ORDER_PROPERTY]; if (undefined === ascending) { return deptA < deptB ? -1 : deptA > deptB ? 1 : a[property] < b[property] ? -1 : a[property] > b[property] ? 1 : 0; } c = ascending ? a[property] : b[property]; d = ascending ? b[property] : a[property]; return c < d ? -1 : c > d ? 1 : 0; } catch (error) { console.log(error); } }); } private searchMember(searchData: SearchData) { if ( !searchData || (!searchData.bySearch && undefined === searchData.deptSeq) ) { this.getMyDeptMember(); return; } if (!!this.myDeptDestroySubject) { this.myDeptDestroySubject.next(); this.myDeptDestroySubject.complete(); this.myDeptDestroySubject = undefined; } let req: DeptUserRequest; if (searchData.bySearch) { req = { divCd: 'ORGS', companyCode: searchData.companyCode, searchRange: DeptSearchType.All, search: searchData.searchWord, senderCompanyCode: this.loginRes.userInfo.companyCode, senderEmployeeType: this.loginRes.userInfo.employeeType }; } else { req = { divCd: 'ORG', companyCode: this.loginRes.companyCode, seq: Number(searchData.deptSeq), search: '', searchRange: DeptSearchType.All, senderCompanyCode: this.loginRes.companyCode, senderEmployeeType: this.loginRes.userInfo.employeeType }; } this.processing = true; this.queryProtocolService .deptUser(req) .pipe(take(1)) .subscribe( (data) => { this._refreshUserInfos(data.userInfos); }, (error) => {}, () => { this.processing = false; } ); } private _refreshUserInfos(userInfos: UserInfoSS[]) { this.userInfos = this.sort(userInfos); // 검색 결과에 따른 프레즌스 조회. const userSeqList: string[] = userInfos.map((user) => user.seq); if (userSeqList.length > 0) { this.store.dispatch( PresenceActions.bulkInfo({ divCd: 'orgSrch', userSeqs: userSeqList }) ); } } } import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input } from '@angular/core'; import { Store, select } from '@ngrx/store'; import { VersionInfo2Response } from '@ucap/api-public'; import { UserInfoSS } from '@ucap/protocol-query'; import { LogService } from '@ucap/ng-logger'; import { PresenceSelector } from '@ucap/ng-store-organization'; import { StatusBulkInfo } from '@ucap/protocol-status'; @Component({ selector: 'app-organization-profile-image-01', templateUrl: './profile-image-01.component.html', styleUrls: ['./profile-image-01.component.scss'] }) export class ProfileImage01Component implements OnInit, OnDestroy { @Input() set userInfo(userInfo: UserInfoSS) { this._userInfo = userInfo; } get userInfo(): UserInfoSS { return this._userInfo; } _userInfo: UserInfoSS; @Input() versionInfo: VersionInfo2Response; presenceInfo: StatusBulkInfo; private ngOnDestroySubject: Subject = new Subject(); constructor( private store: Store, private changeDetectorRef: ChangeDetectorRef, private logService: LogService ) {} ngOnInit(): void { this.store .pipe( takeUntil(this.ngOnDestroySubject), select( PresenceSelector.selectStatusBulkInfo, Number(this.userInfo?.seq) ) ) .subscribe((status) => { this.presenceInfo = status; }); } ngOnDestroy(): void { if (!!this.ngOnDestroySubject) { this.ngOnDestroySubject.next(); this.ngOnDestroySubject.complete(); } } } label, contextmenu, profile, group confirm, error, { "label": { "organization": "조직도", "selectedUsers": "선택한 대화상대", "addGroup": "그룹추가", "chat": "대화", "message": "쪽지", "call": "전화", "videoConference": "화상", "searchResult": "검색결과", "sortName": "이름" }, "presence": { "offline": "오프라인", "online": "온라인", "away": "부재중", "statusMessage1": "다른용무중", "statusMessage2": "회의중", "statusMessage3": "집중근무중" } } { "label": { "confirmRemoveBuddy": "선택한 멤버를 삭제하시겠습니까?\n해당 그룹에서만 선택하신 멤버가 삭제됩니다." }, "category": { "favorite": "즐겨찾기", "default": "기본", "myDept": "소속부서" }, "moreMenu": { "show": { "all": "전체 보기", "onlineBuddy": "접속한 동료만 보기", "onOff": "온/오프라인 보기" }, "group": { "addNew": "새 그룹 추가", "expandMore": "그룹 전체 열기", "expandLess": "그룹 전체 닫기", "changeOrder": "그룹 순서 바꾸기", "startChatWithGroup": "그룹 대화하기", "sendMessageToGroup": "그룹 쪽지 보내기", "groupMemberManagement": "그룹 멤버 관리", "changeGroupName": "그룹 이름 바꾸기", "removeGroup": "그룹 삭제" }, "profile": { "open": "프로필 보기", "unfavorite": "즐겨찾기 해제", "favorite": "즐겨찾기 등록", "nickname": "닉네임 설정", "moveBuddy": "대화상대 이동", "copyBuddy": "대화상대 복사", "removeBuddy": "이 그룹에서 삭제" }, "confirm": { "removeGroup": "그룹을 삭제하시겠습니까?
그룹 멤버는 해당 그룹에서만 삭제됩니다." }, "error": { "label": "그룹 에러", "requireName": "그룹명은 필수입력입니다.", "invalidName": "유효하지 않은 그룹명입니다.", "invalidSelectedUser": "선택된 유저가 존재하지 않습니다." } }, "profile": { "labels": { "myProfile": "내 프로필", "company": "회사", "email": "이메일", "linePhoneNumber": "사무실", "mobilePhoneNumber": "핸드폰", "department": "부서", "mytalk": "MyTalk", "setting": "환경설정", "chat": "대화", "sms": "SMS", "videoConference": "화상회의", "message": "쪽지", "nickname": "닉네임 미설정" }, "fields": { "intro": "인트로" }, "errors": {} } }