대화 내용 내보내기 구현. For CSV

This commit is contained in:
leejinho 2020-03-04 11:26:03 +09:00
parent 921af8f5bb
commit e41f44ca38
9 changed files with 209 additions and 16 deletions

View File

@ -0,0 +1,40 @@
import { DeviceType } from '@ucap-webmessenger/core';
import {
APIRequest,
APIEncoder,
ParameterUtil,
APIFormDataEncoder
} from '@ucap-webmessenger/api';
import { FileDownloadItem } from '../../../../ucap-webmessenger-api/src/lib/models/file-download-item';
export interface EventDownloadRequest extends APIRequest {
userSeq: number;
deviceType: DeviceType;
token: string;
roomSeq: string;
}
const eventDownloadEncodeMap = {
userSeq: 'userSeq',
deviceType: 'deviceType',
token: 'tokenKey',
roomSeq: 'roomSeq'
};
export const encodeEventDownload: APIEncoder<EventDownloadRequest> = (
req: EventDownloadRequest
) => {
const extraParams: any = {};
extraParams.roomSeq = Number(req.roomSeq);
return ParameterUtil.encode(eventDownloadEncodeMap, req, extraParams);
};
export const encodeFormDataEventDownload: APIFormDataEncoder<EventDownloadRequest> = (
req: EventDownloadRequest
) => {
const extraParams: any = {};
extraParams.roomSeq = Number(req.roomSeq);
return ParameterUtil.encodeFormData(eventDownloadEncodeMap, req, extraParams);
};

View File

@ -47,4 +47,7 @@ export interface Urls {
/** 공지 조회 */ /** 공지 조회 */
retrieveNoticeList: string; retrieveNoticeList: string;
/** Event Download */
eventDownload: string;
} }

View File

@ -7,7 +7,7 @@ import {
HttpEventType HttpEventType
} from '@angular/common/http'; } from '@angular/common/http';
import { Observable } from 'rxjs'; import { Observable, Subject } from 'rxjs';
import { map, filter } from 'rxjs/operators'; import { map, filter } from 'rxjs/operators';
import { _MODULE_CONFIG } from '../config/token'; import { _MODULE_CONFIG } from '../config/token';
@ -97,6 +97,10 @@ import {
encodeRetrieveNotice, encodeRetrieveNotice,
decodeRetrieveNotice decodeRetrieveNotice
} from '../apis/notice'; } from '../apis/notice';
import {
EventDownloadRequest,
encodeFormDataEventDownload
} from '../apis/event-download';
@Injectable({ @Injectable({
providedIn: 'root' providedIn: 'root'
@ -357,4 +361,27 @@ export class MessageApiService {
}) })
.pipe(map(res => decodeRetrieveNotice(res))); .pipe(map(res => decodeRetrieveNotice(res)));
} }
/** Event Download for Room */
public eventDownload(req: EventDownloadRequest): Observable<Blob> {
const httpReq = new HttpRequest(
'POST',
this.urls.eventDownload,
encodeFormDataEventDownload(req),
{ reportProgress: true, responseType: 'blob' }
);
return this.httpClient.request(httpReq).pipe(
filter(event => {
if (event instanceof HttpResponse) {
return true;
} else if (HttpEventType.DownloadProgress === event.type) {
}
return false;
}),
map((event: HttpResponse<any>) => {
return event.body;
})
);
}
} }

View File

@ -4,6 +4,7 @@
export * from './lib/apis/del'; export * from './lib/apis/del';
export * from './lib/apis/detail'; export * from './lib/apis/detail';
export * from './lib/apis/edit-reservation-ex'; export * from './lib/apis/edit-reservation-ex';
export * from './lib/apis/event-download';
export * from './lib/apis/my-message'; export * from './lib/apis/my-message';
export * from './lib/apis/notice'; export * from './lib/apis/notice';
export * from './lib/apis/retrieve'; export * from './lib/apis/retrieve';

View File

@ -310,6 +310,13 @@
> >
{{ 'chat.searchEventByText' | translate }} {{ 'chat.searchEventByText' | translate }}
</button> </button>
<button
mat-menu-item
*ngIf="getShowContextMenu('CHAT_EXPORT')"
(click)="onClickContextMenu('CHAT_EXPORT')"
>
{{ 'chat.eventDownload' | translate }}
</button>
<button <button
mat-menu-item mat-menu-item
*ngIf="getShowContextMenu('OPEN_ROOM_USER')" *ngIf="getShowContextMenu('OPEN_ROOM_USER')"

View File

@ -8,7 +8,8 @@ import {
EventEmitter, EventEmitter,
Inject, Inject,
ChangeDetectorRef, ChangeDetectorRef,
ChangeDetectionStrategy ChangeDetectionStrategy,
NgZone
} from '@angular/core'; } from '@angular/core';
import { import {
ucapAnimations, ucapAnimations,
@ -73,7 +74,7 @@ import {
RoomType, RoomType,
UserInfoShort UserInfoShort
} from '@ucap-webmessenger/protocol-room'; } from '@ucap-webmessenger/protocol-room';
import { take, map, catchError, tap } from 'rxjs/operators'; import { take, map, catchError, tap, finalize } from 'rxjs/operators';
import { import {
FormComponent as UCapUiChatFormComponent, FormComponent as UCapUiChatFormComponent,
MessagesComponent as UCapUiChatMessagesComponent, MessagesComponent as UCapUiChatMessagesComponent,
@ -101,7 +102,7 @@ import {
FileViewerDialogData, FileViewerDialogData,
FileViewerDialogResult FileViewerDialogResult
} from '@app/layouts/common/dialogs/file-viewer.dialog.component'; } from '@app/layouts/common/dialogs/file-viewer.dialog.component';
import { FileUtil, StickerFilesInfo } from '@ucap-webmessenger/core'; import { FileUtil, StickerFilesInfo, MimeUtil } from '@ucap-webmessenger/core';
import { StatusCode } from '@ucap-webmessenger/api'; import { StatusCode } from '@ucap-webmessenger/api';
import { import {
@ -137,6 +138,11 @@ import {
} from '../dialogs/conference/conference-detail.dialog.component'; } from '../dialogs/conference/conference-detail.dialog.component';
import { ConferenceService } from '@ucap-webmessenger/api-prompt'; import { ConferenceService } from '@ucap-webmessenger/api-prompt';
import { AuthResponse } from '@ucap-webmessenger/protocol-query'; import { AuthResponse } from '@ucap-webmessenger/protocol-query';
import {
MessageApiService,
EventDownloadRequest
} from '@ucap-webmessenger/api-message';
import moment from 'moment';
@Component({ @Component({
selector: 'app-layout-messenger-messages', selector: 'app-layout-messenger-messages',
@ -256,7 +262,9 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
private snackBarService: SnackBarService, private snackBarService: SnackBarService,
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService, @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
private appFileService: AppFileService, private appFileService: AppFileService,
private logger: NGXLogger private messageApiService: MessageApiService,
private logger: NGXLogger,
private ngZone: NgZone
) { ) {
this.sessionVerInfo = this.sessionStorageService.get<VersionInfo2Response>( this.sessionVerInfo = this.sessionStorageService.get<VersionInfo2Response>(
KEY_VER_INFO KEY_VER_INFO
@ -578,6 +586,20 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
) { ) {
return false; return false;
} }
} else if (['CHAT_EXPORT'].some(v => v === menuType)) {
if (
!this.roomInfoSubject.value ||
!this.roomInfoSubject.value.roomType ||
[
RoomType.Allim,
RoomType.Bot,
RoomType.Link,
RoomType.Allim_Elephant,
RoomType.Allim_TMS
].some(v => v === this.roomInfoSubject.value.roomType)
) {
return false;
}
} }
return true; return true;
@ -1549,6 +1571,11 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
this.onShowToggleSearchArea(); this.onShowToggleSearchArea();
} }
break; break;
case 'CHAT_EXPORT':
{
this.onExportChatEvent();
}
break;
case 'OPEN_ROOM_USER': case 'OPEN_ROOM_USER':
{ {
this.store.dispatch( this.store.dispatch(
@ -1938,6 +1965,90 @@ export class MessagesComponent implements OnInit, OnDestroy, AfterViewInit {
} }
} }
/** About Chat Export */
onExportChatEvent() {
let roomName = this.roomInfoSubject.value.roomName;
if (!roomName || roomName.trim().length === 0) {
roomName = this.getRoomNameByRoomUser(this._roomUserInfos);
}
const date = moment().format('YYYYMMDDHHmmss');
const fileName = `${roomName}_${date}${this.roomInfoSubject.value.roomSeq}.csv`;
const fileTalkDownloadError = (reason: any) => {
this.logger.warn(reason);
this.snackBarService.openFromComponent<
AlertSnackbarComponent,
AlertSnackbarData
>(AlertSnackbarComponent, {
data: {
html: this.translateService.instant('common.file.errors.failToSave'),
buttonText: this.translateService.instant('common.file.errors.label')
}
});
};
this.messageApiService
.eventDownload({
userSeq: this.loginResSubject.value.userSeq,
deviceType: this.environmentsInfo.deviceType,
token: this.loginResSubject.value.tokenString,
roomSeq: this.roomInfoSubject.value.roomSeq
})
.pipe(
take(1),
map(rawBlob => {
const mimeType = MimeUtil.getMimeFromExtension(
FileUtil.getExtension(fileName)
);
const blob = rawBlob.slice(0, rawBlob.size, mimeType);
FileUtil.fromBlobToBuffer(blob)
.then(buffer => {
this.nativeService
.saveFile(buffer, fileName, mimeType)
.then(filePath => {
if (!!filePath) {
const snackBarRef = this.snackBarService.open(
this.translateService.instant(
'common.file.results.savedToPath',
{
path: filePath
}
),
this.translateService.instant('common.file.open'),
{
duration: 3000,
verticalPosition: 'bottom',
horizontalPosition: 'center'
}
);
snackBarRef.onAction().subscribe(() => {
snackBarRef.dismiss();
this.ngZone.runOutsideAngular(() => {
this.nativeService
.openTargetItem(filePath)
.catch(reason => {
this.logger.warn(reason);
});
});
});
} else {
fileTalkDownloadError('fail');
}
})
.catch(reason => {
fileTalkDownloadError(reason);
});
})
.catch(reason => {
fileTalkDownloadError(reason);
});
}),
finalize(() => {}),
catchError(error => of(error))
)
.subscribe();
}
/** About Translation */ /** About Translation */
onShowToggleTranslation() { onShowToggleTranslation() {
this.isShowTranslation = !this.isShowTranslation; this.isShowTranslation = !this.isShowTranslation;

View File

@ -197,6 +197,7 @@
"newChat": "New Chat", "newChat": "New Chat",
"startChat": "Chat", "startChat": "Chat",
"openRoom": "Open room", "openRoom": "Open room",
"eventDownload": "export chat",
"listOfRoomMember": "List of room member", "listOfRoomMember": "List of room member",
"settingsOfRoom": "Settings of room", "settingsOfRoom": "Settings of room",
"turnOnRoomAlert": "Turn on room alert", "turnOnRoomAlert": "Turn on room alert",

View File

@ -197,6 +197,7 @@
"newChat": "새로운 대화", "newChat": "새로운 대화",
"startChat": "대화하기", "startChat": "대화하기",
"openRoom": "대화방 열기", "openRoom": "대화방 열기",
"eventDownload": "대화 내용 내보내기",
"listOfRoomMember": "대화 참여자 목록", "listOfRoomMember": "대화 참여자 목록",
"settingsOfRoom": "대화방 설정", "settingsOfRoom": "대화방 설정",
"turnOnRoomAlert": "대화방 알람 켜기", "turnOnRoomAlert": "대화방 알람 켜기",
@ -364,16 +365,16 @@
} }
}, },
"conference": { "conference": {
"detailView": "상세 보기", "detailView": "상세 보기",
"videoConferenceTypeNow": "[화상회의] 개설", "videoConferenceTypeNow": "[화상회의] 개설",
"videoConferenceTypeNew": "[화상회의] 예약", "videoConferenceTypeNew": "[화상회의] 예약",
"videoConferenceTypeUpdate": "[화상회의] 수정", "videoConferenceTypeUpdate": "[화상회의] 수정",
"videoConferenceTypeDelete": "[화상회의] 삭제", "videoConferenceTypeDelete": "[화상회의] 삭제",
"videoConferenceRegister": "개설자", "videoConferenceRegister": "개설자",
"videoConferenceAttendee": "참여자", "videoConferenceAttendee": "참여자",
"videoConferenceDate": "날짜", "videoConferenceDate": "날짜",
"videoConferenceRoom": "회의실", "videoConferenceRoom": "회의실",
"videoConferenceEnjoy": "참석하기" "videoConferenceEnjoy": "참석하기"
}, },
"update": { "update": {
"label": "업데이트" "label": "업데이트"

View File

@ -167,7 +167,9 @@ export const messageApiUrls: MessageApiUrls = {
retrieveUnreadCount: '/uCapMsg/msg/retrieveUnreadCount.do', retrieveUnreadCount: '/uCapMsg/msg/retrieveUnreadCount.do',
retrieveNoticeList: '/uCapMsg/notice/retrieveNoticeList.do' retrieveNoticeList: '/uCapMsg/notice/retrieveNoticeList.do',
eventDownload: '/uCapMsg/event/download'
}; };
export const promptUrls: PromptUrls = { export const promptUrls: PromptUrls = {
sendCall: '/uCapPrompt/api/call/clicktocall', sendCall: '/uCapPrompt/api/call/clicktocall',