통합검색에 전화 연결기능 추가.

This commit is contained in:
leejinho 2020-03-09 17:32:11 +09:00
parent 906bbdcf2c
commit 111eb42c92
11 changed files with 351 additions and 21 deletions

View File

@ -162,6 +162,8 @@
(toggleAllUser)="onToggleAllUser($event)" (toggleAllUser)="onToggleAllUser($event)"
(toggleUser)="onToggleUser($event)" (toggleUser)="onToggleUser($event)"
(gotoDeptTree)="onClickGotoDeptTree($event)" (gotoDeptTree)="onClickGotoDeptTree($event)"
(sendCall)="onClickCall($event)"
(sendSms)="onClickSMS($event)"
class="detail-table" class="detail-table"
></ucap-organization-detail-table> ></ucap-organization-detail-table>
</div> </div>
@ -224,6 +226,16 @@
{{ 'organization.startVideoConference' | translate }} {{ 'organization.startVideoConference' | translate }}
</button> </button>
</li> </li>
<li>
<button
mat-flat-button
[disabled]="selectedUserList.length > 0 ? 'false' : 'true'"
(click)="onClickMessage()"
class="mat-primary"
>
{{ 'organization.startMessage' | translate }}
</button>
</li>
</ul> </ul>
</div> </div>
</mat-expansion-panel> </mat-expansion-panel>

View File

@ -5,7 +5,9 @@ import {
OnDestroy, OnDestroy,
Output, Output,
EventEmitter, EventEmitter,
ViewChild ViewChild,
NgZone,
Inject
} from '@angular/core'; } from '@angular/core';
import { import {
SelectedDept, SelectedDept,
@ -14,7 +16,15 @@ import {
} from '@ucap-webmessenger/protocol-query'; } from '@ucap-webmessenger/protocol-query';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; import { TranslateService, LangChangeEvent } from '@ngx-translate/core';
import { DialogService } from '@ucap-webmessenger/ui'; import {
DialogService,
ConfirmDialogComponent,
ConfirmDialogResult,
ConfirmDialogData,
AlertDialogComponent,
AlertDialogResult,
AlertDialogData
} from '@ucap-webmessenger/ui';
import { SessionStorageService } from '@ucap-webmessenger/web-storage'; import { SessionStorageService } from '@ucap-webmessenger/web-storage';
import { Store, select } from '@ngrx/store'; import { Store, select } from '@ngrx/store';
@ -23,14 +33,20 @@ import * as SettingsStore from '@app/store/messenger/settings';
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 { Observable, Subscription, BehaviorSubject, merge } from 'rxjs'; import { Observable, Subscription, BehaviorSubject, merge, of } from 'rxjs';
import { PresenceType, StatusCode } from '@ucap-webmessenger/core'; import { PresenceType, StatusCode } from '@ucap-webmessenger/core';
import { StatusBulkInfo } from '@ucap-webmessenger/protocol-status'; import { StatusBulkInfo } from '@ucap-webmessenger/protocol-status';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { KEY_VER_INFO, KEY_AUTH_INFO, MainMenu } from '@app/types'; import {
KEY_VER_INFO,
KEY_AUTH_INFO,
MainMenu,
EnvironmentsInfo,
KEY_ENVIRONMENTS_INFO
} from '@app/types';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { tap } from 'rxjs/operators'; import { tap, take, map, catchError } from 'rxjs/operators';
import { import {
SelectGroupDialogComponent, SelectGroupDialogComponent,
SelectGroupDialogData, SelectGroupDialogData,
@ -41,6 +57,17 @@ import { TranslateService as UCapTranslateService } from '@ucap-webmessenger/ui'
import { FormControl } from '@angular/forms'; import { FormControl } from '@angular/forms';
import { MatSelect } from '@angular/material/select'; import { MatSelect } from '@angular/material/select';
import { MatOption } from '@angular/material/core'; import { MatOption } from '@angular/material/core';
import {
MessageWriteDialogComponent,
MessageWriteDialogResult,
MessageWriteDialogData
} from '../../dialogs/message/message-write.dialog.component';
import {
PromptMessageStatusCode,
CallService
} from '@ucap-webmessenger/api-prompt';
import { SmsUtils } from '@ucap-webmessenger/daesang';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
@Component({ @Component({
selector: 'app-layout-messenger-organization', selector: 'app-layout-messenger-organization',
@ -84,6 +111,7 @@ export class OrganizationComponent implements OnInit, OnDestroy {
loginRes: LoginResponse; loginRes: LoginResponse;
loginResSubscription: Subscription; loginResSubscription: Subscription;
environmentsInfo: EnvironmentsInfo;
sessionVerinfo: VersionInfo2Response; sessionVerinfo: VersionInfo2Response;
authInfo: AuthResponse; authInfo: AuthResponse;
ucapLangChangeSubscription: Subscription; ucapLangChangeSubscription: Subscription;
@ -109,14 +137,21 @@ export class OrganizationComponent implements OnInit, OnDestroy {
StatusCode = StatusCode; StatusCode = StatusCode;
constructor( constructor(
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
private store: Store<any>, private store: Store<any>,
private sessionStorageService: SessionStorageService, private sessionStorageService: SessionStorageService,
private dialogService: DialogService, private dialogService: DialogService,
private translateService: TranslateService, private translateService: TranslateService,
private ucapTranslateService: UCapTranslateService, private ucapTranslateService: UCapTranslateService,
private callService: CallService,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private logger: NGXLogger private logger: NGXLogger,
private ngZone: NgZone
) { ) {
this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
KEY_ENVIRONMENTS_INFO
);
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>( this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO KEY_VER_INFO
); );
@ -324,9 +359,124 @@ export class OrganizationComponent implements OnInit, OnDestroy {
const targetUserSeqs = this.selectedUserList.map(userInfo => userInfo.seq); const targetUserSeqs = this.selectedUserList.map(userInfo => userInfo.seq);
this.createConference.emit(targetUserSeqs); this.createConference.emit(targetUserSeqs);
} }
onClickMessage() {
this.ngZone.run(() => {
const receiverList: UserInfoSS[] = this.selectedUserList.slice();
if (receiverList.length > 0) {
this.dialogService.open<
MessageWriteDialogComponent,
MessageWriteDialogData,
MessageWriteDialogResult
>(MessageWriteDialogComponent, {
width: '600px',
height: '600px',
disableClose: true,
hasBackdrop: false,
data: {
loginRes: this.loginRes,
environmentsInfo: this.environmentsInfo,
receiverList
}
});
}
});
}
onClickOpenProfile(userSeq: number) { onClickOpenProfile(userSeq: number) {
this.openProfile.emit(userSeq); this.openProfile.emit(userSeq);
} }
async onClickCall(calleeNumber: string) {
const madn = this.loginRes.madn;
if (!madn || madn.trim().length === 0) {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: this.translateService.instant('call.errors.label'),
html: this.translateService.instant('call.errors.cannotCallToUser')
}
});
return false;
}
calleeNumber = calleeNumber.replace(/\D/g, '');
if (!!calleeNumber && calleeNumber.length > 0) {
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
width: '360px',
data: {
title: this.translateService.instant('call.callTo'),
html: this.translateService.instant('call.callWithNumber', {
phoneNumber: calleeNumber
})
}
});
if (!!result && !!result.choice && result.choice) {
this.callService
.sendCall({
userSeq: this.loginRes.userSeq,
deviceType: this.environmentsInfo.deviceType,
tokenKey: this.loginRes.tokenString,
calleeNumber
})
.pipe(
take(1),
map(res => {
if (res.responseCode === PromptMessageStatusCode.Success) {
this.logger.debug('SUCCESS');
this.logger.debug(res);
} else {
this.logger.error(res);
}
}),
catchError(error => of(this.logger.debug(error)))
)
.subscribe();
}
} else {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: this.translateService.instant('call.errors.label'),
html: this.translateService.instant(
'call.errors.cannotCallToUserWithoutPhomeNumber'
)
}
});
}
}
onClickSMS(employeeNum: string) {
const smsUtil = new SmsUtils(
this.sessionStorageService,
this.nativeService
);
if (!smsUtil.getAuthSms()) {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: this.translateService.instant('sms.errors.label'),
html: this.translateService.instant('sms.errors.haveNoPermission')
}
});
return false;
}
smsUtil.openSendSms(this.loginRes.tokenString, employeeNum);
}
onClickGotoDeptTree(deptSeq: number) { onClickGotoDeptTree(deptSeq: number) {
this.gotoDeptTree.emit(deptSeq); this.gotoDeptTree.emit(deptSeq);
} }

View File

@ -39,7 +39,8 @@
(openProfile)="onClickOpenProfile($event)" (openProfile)="onClickOpenProfile($event)"
(toggleAllUser)="onToggleAllUser($event)" (toggleAllUser)="onToggleAllUser($event)"
(toggleUser)="onToggleUser($event)" (toggleUser)="onToggleUser($event)"
class="detail-table" (sendCall)="onClickCall($event)"
class="integrate-search-org detail-table"
></ucap-organization-detail-table> ></ucap-organization-detail-table>
</div> </div>
<div class="footer-fix search-result-footer"> <div class="footer-fix search-result-footer">
@ -105,6 +106,18 @@
{{ 'organization.startVideoConference' | translate }} {{ 'organization.startVideoConference' | translate }}
</button> </button>
</li> </li>
<li>
<button
mat-flat-button
[disabled]="
selectedUserList.length > 0 ? 'false' : 'true'
"
(click)="onClickMessage()"
class="mat-primary"
>
{{ 'organization.startMessage' | translate }}
</button>
</li>
</ul> </ul>
</div> </div>
</mat-expansion-panel> </mat-expansion-panel>
@ -115,12 +128,12 @@
<ul> <ul>
<li> <li>
<button mat-flat-button (click)="onCancel()" class="mat-primary"> <button mat-flat-button (click)="onCancel()" class="mat-primary">
검색 초기화 & 닫기 {{ 'search.clearAndColse' | translate }}
</button> </button>
</li> </li>
<li> <li>
<button mat-flat-button (click)="onClickHide()" class="mat-primary"> <button mat-flat-button (click)="onClickHide()" class="mat-primary">
접어두기 {{ 'search.fold' | translate }}
</button> </button>
</li> </li>
</ul> </ul>

View File

@ -10,7 +10,3 @@
color: #444444; color: #444444;
} }
} }
.hideDialog {
display: none;
}

View File

@ -3,7 +3,8 @@ import {
OnInit, OnInit,
Inject, Inject,
OnDestroy, OnDestroy,
ChangeDetectorRef ChangeDetectorRef,
NgZone
} from '@angular/core'; } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { KEY_VER_INFO, MainMenu, KEY_AUTH_INFO } from '@app/types'; import { KEY_VER_INFO, MainMenu, KEY_AUTH_INFO } from '@app/types';
@ -18,8 +19,8 @@ import * as SyncStore from '@app/store/messenger/sync';
import { UserInfoSS, AuthResponse } from '@ucap-webmessenger/protocol-query'; import { UserInfoSS, AuthResponse } from '@ucap-webmessenger/protocol-query';
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication'; import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
import { map, take, tap } from 'rxjs/operators'; import { map, take, tap, catchError } from 'rxjs/operators';
import { Subscription, Observable, BehaviorSubject } from 'rxjs'; import { Subscription, Observable, BehaviorSubject, of } from 'rxjs';
import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types'; import { EnvironmentsInfo, KEY_ENVIRONMENTS_INFO } from '@app/types';
import { NGXLogger } from 'ngx-logger'; import { NGXLogger } from 'ngx-logger';
import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native'; import { NativeService, UCAP_NATIVE_SERVICE } from '@ucap-webmessenger/native';
@ -27,7 +28,15 @@ import { environment } from '../../../../../environments/environment';
import { StatusBulkInfo } from '@ucap-webmessenger/protocol-status'; import { StatusBulkInfo } from '@ucap-webmessenger/protocol-status';
import { VersionInfo2Response } from '@ucap-webmessenger/api-public'; import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
import { DaesangProtocolService } from '@ucap-webmessenger/daesang'; import { DaesangProtocolService } from '@ucap-webmessenger/daesang';
import { DialogService } from '@ucap-webmessenger/ui'; import {
DialogService,
AlertDialogComponent,
AlertDialogData,
AlertDialogResult,
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
} from '@ucap-webmessenger/ui';
import { import {
ProfileDialogComponent, ProfileDialogComponent,
ProfileDialogData, ProfileDialogData,
@ -40,7 +49,16 @@ import {
} from '../group/select-group.dialog.component'; } from '../group/select-group.dialog.component';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { GroupDetailData } from '@ucap-webmessenger/protocol-sync'; import { GroupDetailData } from '@ucap-webmessenger/protocol-sync';
import { ConferenceService } from '@ucap-webmessenger/api-prompt'; import {
ConferenceService,
PromptMessageStatusCode,
CallService
} from '@ucap-webmessenger/api-prompt';
import {
MessageWriteDialogComponent,
MessageWriteDialogResult,
MessageWriteDialogData
} from '../message/message-write.dialog.component';
export interface IntegratedSearchDialogData { export interface IntegratedSearchDialogData {
keyword: string; keyword: string;
@ -88,10 +106,12 @@ export class IntegratedSearchDialogComponent implements OnInit, OnDestroy {
private dialogService: DialogService, private dialogService: DialogService,
private translateService: TranslateService, private translateService: TranslateService,
private conferenceService: ConferenceService, private conferenceService: ConferenceService,
private callService: CallService,
private store: Store<any>, private store: Store<any>,
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private logger: NGXLogger private logger: NGXLogger,
private ngZone: NgZone
) { ) {
this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>( this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
KEY_ENVIRONMENTS_INFO KEY_ENVIRONMENTS_INFO
@ -282,6 +302,29 @@ export class IntegratedSearchDialogComponent implements OnInit, OnDestroy {
}); });
} }
} }
onClickMessage() {
this.ngZone.run(() => {
const receiverList: UserInfoSS[] = this.selectedUserList.slice();
if (receiverList.length > 0) {
this.dialogService.open<
MessageWriteDialogComponent,
MessageWriteDialogData,
MessageWriteDialogResult
>(MessageWriteDialogComponent, {
width: '600px',
height: '600px',
disableClose: true,
hasBackdrop: false,
data: {
loginRes: this.loginRes,
environmentsInfo: this.environmentsInfo,
receiverList
}
});
}
});
}
onClickOpenProfile(userSeq: number) { onClickOpenProfile(userSeq: number) {
if (!userSeq || userSeq < 0) { if (!userSeq || userSeq < 0) {
return; return;
@ -318,6 +361,77 @@ export class IntegratedSearchDialogComponent implements OnInit, OnDestroy {
) )
.subscribe(); .subscribe();
} }
async onClickCall(calleeNumber: string) {
const madn = this.loginRes.madn;
if (!madn || madn.trim().length === 0) {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: this.translateService.instant('call.errors.label'),
html: this.translateService.instant('call.errors.cannotCallToUser')
}
});
return false;
}
calleeNumber = calleeNumber.replace(/\D/g, '');
if (!!calleeNumber && calleeNumber.length > 0) {
const result = await this.dialogService.open<
ConfirmDialogComponent,
ConfirmDialogData,
ConfirmDialogResult
>(ConfirmDialogComponent, {
width: '360px',
data: {
title: this.translateService.instant('call.callTo'),
html: this.translateService.instant('call.callWithNumber', {
phoneNumber: calleeNumber
})
}
});
if (!!result && !!result.choice && result.choice) {
this.callService
.sendCall({
userSeq: this.loginRes.userSeq,
deviceType: this.environmentsInfo.deviceType,
tokenKey: this.loginRes.tokenString,
calleeNumber
})
.pipe(
take(1),
map(res => {
if (res.responseCode === PromptMessageStatusCode.Success) {
this.logger.debug('SUCCESS');
this.logger.debug(res);
} else {
this.logger.error(res);
}
}),
catchError(error => of(this.logger.debug(error)))
)
.subscribe();
}
} else {
this.dialogService.open<
AlertDialogComponent,
AlertDialogData,
AlertDialogResult
>(AlertDialogComponent, {
data: {
title: this.translateService.instant('call.errors.label'),
html: this.translateService.instant(
'call.errors.cannotCallToUserWithoutPhomeNumber'
)
}
});
}
}
onClickHide(): void { onClickHide(): void {
this.dialogRef.addPanelClass('hideDialog'); this.dialogRef.addPanelClass('hideDialog');

View File

@ -77,6 +77,9 @@
"search": { "search": {
"label": "User search", "label": "User search",
"searchFormPlaceholder": "Name, department, position, phone number, email", "searchFormPlaceholder": "Name, department, position, phone number, email",
"fold": "Folding",
"unfold": "Unfolding",
"clearAndColse": "Data clear & Close",
"fieldProfile": "Profile", "fieldProfile": "Profile",
"fieldName": "Name", "fieldName": "Name",
"fieldDeptartment": "Department", "fieldDeptartment": "Department",
@ -279,6 +282,8 @@
"addToGroup": "Add to group", "addToGroup": "Add to group",
"startChat": "Chat", "startChat": "Chat",
"startVideoConference": "Video conference", "startVideoConference": "Video conference",
"startMessage": "Message",
"startSMS": "SMS",
"makeExtensionCall": "Make extension call", "makeExtensionCall": "Make extension call",
"makeMobileCall": "Make mobile call", "makeMobileCall": "Make mobile call",
"sendMessage": "Send message", "sendMessage": "Send message",

View File

@ -77,6 +77,9 @@
"search": { "search": {
"label": "사용자 검색", "label": "사용자 검색",
"searchFormPlaceholder": "이름, 부서, 직위, 전화번호, 이메일", "searchFormPlaceholder": "이름, 부서, 직위, 전화번호, 이메일",
"fold": "접어두기",
"unfold": "펼쳐보기",
"clearAndColse": "검색 초기화 & 닫기",
"fieldProfile": "프로필", "fieldProfile": "프로필",
"fieldName": "이름", "fieldName": "이름",
"fieldDeptartment": "부서", "fieldDeptartment": "부서",
@ -279,6 +282,8 @@
"addToGroup": "그룹에 추가", "addToGroup": "그룹에 추가",
"startChat": "대화", "startChat": "대화",
"startVideoConference": "화상회의", "startVideoConference": "화상회의",
"startMessage": "쪽지",
"startSMS": "SMS",
"makeExtensionCall": "내선번호 전화걸기", "makeExtensionCall": "내선번호 전화걸기",
"makeMobileCall": "모바일 전화걸기", "makeMobileCall": "모바일 전화걸기",
"sendMessage": "쪽지 보내기", "sendMessage": "쪽지 보내기",

View File

@ -89,7 +89,7 @@
<div class="companyName"> <div class="companyName">
{{ element.companyName }} {{ element.companyName }}
</div> </div>
<div class="hpNumber"> <div class="hpNumber" (click)="onClickCall('MOBILE', element)">
{{ element.hpNumber | ucapStringFormatterPhone }} {{ element.hpNumber | ucapStringFormatterPhone }}
</div> </div>
</td> </td>
@ -107,7 +107,7 @@
<div class="workplace"> <div class="workplace">
{{ element.workplace }} {{ element.workplace }}
</div> </div>
<div class="lineNumber"> <div class="lineNumber" (click)="onClickCall('LINE', element)">
{{ element.lineNumber | ucapStringFormatterPhone }} {{ element.lineNumber | ucapStringFormatterPhone }}
</div> </div>
</td> </td>

View File

@ -90,6 +90,8 @@ td.mat-cell {
} }
&.profileInfo { &.profileInfo {
cursor: pointer;
.baseInfo { .baseInfo {
display: flex; display: flex;
width: 200px; width: 200px;
@ -103,6 +105,13 @@ td.mat-cell {
} }
} }
} }
.hpNumber {
cursor: pointer;
}
.lineNumber {
cursor: pointer;
}
} }
.work-status { .work-status {
@ -127,3 +136,11 @@ td.mat-cell {
justify-items: center; justify-items: center;
font-size: 1.1em; font-size: 1.1em;
} }
::ng-deep .integrate-search-org {
td.mat-cell {
&.profileInfo {
cursor: initial !important;
}
}
}

View File

@ -43,6 +43,10 @@ export class DetailTableComponent implements OnInit, OnDestroy {
@Output() @Output()
gotoDeptTree = new EventEmitter<number>(); gotoDeptTree = new EventEmitter<number>();
@Output() @Output()
sendCall = new EventEmitter<string>();
@Output()
sendSms = new EventEmitter<string>();
@Output()
toggleAllUser = new EventEmitter<{ toggleAllUser = new EventEmitter<{
isChecked: boolean; isChecked: boolean;
userInfos: UserInfoSS[]; userInfos: UserInfoSS[];
@ -287,4 +291,17 @@ export class DetailTableComponent implements OnInit, OnDestroy {
event.stopPropagation(); event.stopPropagation();
this.gotoDeptTree.emit(Number(deptSeq)); this.gotoDeptTree.emit(Number(deptSeq));
} }
onClickCall(type: string, userInfo: UserInfoSS) {
let calleeNumber = '';
if (type === 'LINE') {
calleeNumber = userInfo.lineNumber;
} else {
calleeNumber = userInfo.hpNumber;
}
this.sendCall.emit(calleeNumber);
}
onClickSMS(userInfo: UserInfoSS) {
this.sendSms.emit(userInfo.employeeNum);
}
} }

View File

@ -15,6 +15,7 @@
class="icon-img" class="icon-img"
*ngIf="isShowOpenIcon" *ngIf="isShowOpenIcon"
matSuffix matSuffix
matTooltip="{{ 'search.unfold' | translate }}"
(click)="onClickShowDialog()" (click)="onClickShowDialog()"
> >
<i class="mid mdi-open-in-new"></i> <i class="mid mdi-open-in-new"></i>