0220 업무 번들이미지 뷰어 작업
This commit is contained in:
parent
ef603030ef
commit
41499618ea
|
@ -3,9 +3,166 @@
|
|||
모바일로 테스트 하지 못할경우
|
||||
JSON 데이터 만들어서 테스트 진행
|
||||
state
|
||||
|
||||
reducer
|
||||
|
||||
action
|
||||
sync-service
|
||||
테스트 후 수정
|
||||
PhoneBookData 추가
|
||||
|
||||
파일 뷰어
|
||||
common-api-service.ts
|
||||
file-viewer.dialog.component.html
|
||||
file-viewer.dialog.component.ts
|
||||
messages.component.ts ucap-webmessenger-app/layouts/messenger/component
|
||||
file.servic.ts ucap-webmessenger-app/service
|
||||
bundle-image.event-json.ts
|
||||
file.event-json.ts
|
||||
mass-text.event-json.ts
|
||||
mass-translation.event-json.ts
|
||||
plan.event-json.ts
|
||||
video-confrence.event-json.ts
|
||||
file-info.ts ucap-webmessenger-protocol-file/src/lib/models
|
||||
public-api.ts ucap-webmessenger-ui/src
|
||||
ucap-ui.module.ts ucap-webmessenger-ui/src/lib
|
||||
file-viewer.compoent.html
|
||||
file-viewer.compoent.ts
|
||||
media-viewe.component.html
|
||||
media-viewe.component.scss
|
||||
media-viewe.component.spec.ts
|
||||
media-viewe.component.ts
|
||||
binary-viewe.component.html
|
||||
binary-viewe.component.ts
|
||||
document-viewer.component.ts
|
||||
image-viewer.component.html
|
||||
image-viewer.component.ts
|
||||
sound-viewer.component.html
|
||||
sound-viewer.component.ts
|
||||
video-viewer.component.html
|
||||
video-viewer.component.ts
|
||||
select-file-info.ts
|
||||
message-box.component.ts
|
||||
messages.component.ts ucap-webmessenger-ui-chat/src /lib/component
|
||||
bundle-image.component.html
|
||||
bundle-image.component.ts
|
||||
file.component.ts ucap-webmessenger-ui-chat/src/lib/component/message-box
|
||||
|
||||
요구사항
|
||||
이미지 뷰어 묶음 파일 출력 기능
|
||||
기존 이미지 타입에 영향 주지 않아야 한다.
|
||||
이미지 뷰어 묶음 파일 다운로드 기능
|
||||
이미지 뷰어 이전/다음 기능
|
||||
|
||||
메세지 출력
|
||||
메세지 박스 출력
|
||||
메세지 파일 출력
|
||||
|
||||
기존 파일 뷰어 분석
|
||||
app->messages.component 호출
|
||||
파일 클릭 이벤트 정의()
|
||||
room-info 서브젝트 생성
|
||||
이벤트 리스트 서브젝트 생성
|
||||
fileviewer 클릭 이벤트 생성
|
||||
ui-chat->messages.component 호출
|
||||
room-info 서브젝트 전달
|
||||
이벤트 서브젝트 전달
|
||||
fileviewer 클릭 이벤트 전달
|
||||
[for message.length]
|
||||
ui-chat->message-box.component 호출
|
||||
message 정보 전달
|
||||
room-info 전달
|
||||
파일저장 클릭 이벤트 전달
|
||||
fileviewer 클릭 이벤트 전달(FileEventJson)
|
||||
ui-chat->message-box.component.html
|
||||
EventType.File
|
||||
ucap-chat-message-box-file 호출
|
||||
room-info 전달
|
||||
fileviewer 클릭 이벤트 전달 (FileEventJson)
|
||||
EventType.BundleImage
|
||||
ucap-chat-message-box-bundle-image 호출
|
||||
room-info 전달
|
||||
파일 클릭 이벤트 실행(FileEventJson)
|
||||
file-viewer.dialog.component.ts 호출
|
||||
fileInfo, downloadUrl, userSeq, deviceType, token 전달
|
||||
download 클릭 이벤트 정의
|
||||
file-viewer.component.ts 호출
|
||||
fileInfo 전달
|
||||
fileDownloadUrl 전달
|
||||
download 클릭 이벤트 전달()
|
||||
클로즈 이벤트 전달
|
||||
file-viewer.component.html
|
||||
FileViewerType 구분
|
||||
ucap-image-viewer
|
||||
fileInfo 전달
|
||||
fileDownloadUrl 전달
|
||||
closed 이벤트 클릭 전달
|
||||
download 이벤트 클릭 전달
|
||||
|
||||
수정 파일 뷰어 분석
|
||||
app->messages.component 호출
|
||||
파일 정보 리스트 서브젝트 생성
|
||||
선택 파일 정보 맵핑
|
||||
이벤트 정의(선택 파일)
|
||||
이미지 뷰어 다이얼로그 호출
|
||||
ui-chat->messages.component 호출
|
||||
파일 클릭 이벤트(상위호출)
|
||||
|
||||
|
||||
|
||||
시작
|
||||
layout/messages.component.ts
|
||||
ui-chat/messages.compoent
|
||||
ui-chat/message-box.component
|
||||
message-box/file.component.ts
|
||||
image.component
|
||||
|
||||
onFileViewer(fileInfo)
|
||||
layout/messages.component.ts-> onFileViewer(fileInfo) 실행
|
||||
layout/common/dialog/file-view.dialog.component.ts
|
||||
ui/file-viewer.component
|
||||
ui/document-viewer.component.ts
|
||||
ui/image-viewer.component.ts
|
||||
ui/sound-viewer.component.ts
|
||||
ui/video-viewer.compoent.ts
|
||||
ui/binary-viewer.component.ts
|
||||
끝
|
||||
|
||||
있는것
|
||||
파일정보 리스트
|
||||
방정보
|
||||
사용자 정보
|
||||
|
||||
없는것
|
||||
|
||||
추가 기능
|
||||
대화방 미디어 이미지 이전/다음 처리
|
||||
메세지 박스 번들이미지 클릭 처리
|
||||
미디어 이미지 뷰어 (이미지, 번들 이미지, 사운드 이미지, 비디오 이미지) 처리
|
||||
번들이미지 다운로드 처리
|
||||
|
||||
정보
|
||||
대화방 전체 파일정보 리스트
|
||||
현재 사용자 선택 파일 정보
|
||||
|
||||
file-viewer.dialog.component.ts
|
||||
현재파일 정보
|
||||
|
||||
번들이미지 다운로드 처리
|
||||
|
||||
대화방 전체 파일정보 변경에 대한 구독 등록
|
||||
|
||||
|
||||
미디어 뷰어 컴포넌트 생성
|
||||
ui/image-viewer.component.ts
|
||||
ui/sound-viewer.component.ts
|
||||
ui/video-viewer.compoent.ts
|
||||
|
||||
|
||||
layout/messages.component.ts
|
||||
|
||||
|
||||
TODO
|
||||
설정->쪽지 알림 메뉴 삭제 (주석)
|
||||
설정->원격 지원 메뉴 삭제 (주석)
|
||||
left-menu->전화걸기 메뉴 삭제 (주석)
|
30
documents/업무/2월/3째주/0221.txt
Normal file
30
documents/업무/2월/3째주/0221.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
추가 기능
|
||||
대화방 미디어 이미지 이전/다음 처리
|
||||
메세지 박스 번들이미지 클릭 처리
|
||||
미디어 이미지 뷰어 (이미지, 번들 이미지, 사운드 이미지, 비디오 이미지) 처리
|
||||
번들이미지 다운로드 처리
|
||||
|
||||
|
||||
TODO
|
||||
설정->쪽지 알림 메뉴 삭제 (주석)
|
||||
설정->원격 지원 메뉴 삭제 (주석)
|
||||
left-menu->전화걸기 메뉴 삭제 (주석)
|
||||
|
||||
|
||||
시작
|
||||
layout/messages.component.ts
|
||||
ui-chat/messages.compoent
|
||||
ui-chat/message-box.component
|
||||
message-box/file.component.ts
|
||||
image.component
|
||||
|
||||
onFileViewer(fileInfo)
|
||||
layout/messages.component.ts-> onFileViewer(fileInfo) 실행
|
||||
layout/common/dialog/file-view.dialog.component.ts
|
||||
ui/file-viewer.component
|
||||
ui/document-viewer.component.ts
|
||||
ui/image-viewer.component.ts
|
||||
ui/sound-viewer.component.ts
|
||||
ui/video-viewer.compoent.ts
|
||||
ui/binary-viewer.component.ts
|
||||
끝
|
|
@ -0,0 +1,23 @@
|
|||
<div
|
||||
class="bubble-main"
|
||||
(mouseenter)="mouseEnter($event)"
|
||||
(mouseleave)="mouseLeave($event)"
|
||||
>
|
||||
<div *ngIf="showExpired" class="expired-text">
|
||||
<span>{{ 'common.file.errors.expired' | translate }}</span>
|
||||
</div>
|
||||
<mat-grid-list
|
||||
cols="6"
|
||||
rowHeight="100px"
|
||||
gutterSize="3px"
|
||||
style="width: 300px;"
|
||||
>
|
||||
<mat-grid-tile
|
||||
*ngFor="let tile of tiles; let i = index"
|
||||
[colspan]="tile.colspan"
|
||||
(click)="onClickFileViewer(i)"
|
||||
>
|
||||
<img src="{{ tile.imgSrc }}" />
|
||||
</mat-grid-tile>
|
||||
</mat-grid-list>
|
||||
</div>
|
123
documents/업무/2월/3째주/file-viewer-prj/bundle-image.component.ts
Normal file
123
documents/업무/2월/3째주/file-viewer-prj/bundle-image.component.ts
Normal file
|
@ -0,0 +1,123 @@
|
|||
import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core';
|
||||
import { BundleImageEventJson, Info } from '@ucap-webmessenger/protocol-event';
|
||||
import { FileDownloadItem } from '@ucap-webmessenger/api';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { RoomInfo } from '@ucap-webmessenger/protocol-room';
|
||||
import { SelectFileInfo } from '@ucap-webmessenger/ui';
|
||||
|
||||
export interface Tile {
|
||||
colspan?: number;
|
||||
imgSrc?: string;
|
||||
}
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-bundle-image',
|
||||
templateUrl: './bundle-image.component.html',
|
||||
styleUrls: ['./bundle-image.component.scss']
|
||||
})
|
||||
export class BundleImageComponent implements OnInit {
|
||||
@Input()
|
||||
set message(m: Info<BundleImageEventJson>) {
|
||||
this._message = m;
|
||||
|
||||
this.makeTileGrid();
|
||||
}
|
||||
get message() {
|
||||
return this._message;
|
||||
}
|
||||
// tslint:disable-next-line: variable-name
|
||||
_message: Info<BundleImageEventJson>;
|
||||
|
||||
@Input()
|
||||
roomInfo: RoomInfo;
|
||||
|
||||
@Output()
|
||||
save = new EventEmitter<{
|
||||
fileInfo: BundleImageEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
}>();
|
||||
@Output()
|
||||
fileViewer = new EventEmitter<SelectFileInfo>();
|
||||
|
||||
showExpired = false;
|
||||
tiles: Tile[] = [];
|
||||
|
||||
constructor(private logger: NGXLogger) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.makeTileGrid();
|
||||
}
|
||||
|
||||
makeTileGrid() {
|
||||
if (
|
||||
!this.message.sentMessageJson.thumbUrls ||
|
||||
0 === this.message.sentMessageJson.thumbUrls.length ||
|
||||
1 > this.message.sentMessageJson.fileCount
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const fileCount = Number(this.message.sentMessageJson.fileCount);
|
||||
|
||||
this.tiles = [];
|
||||
|
||||
const remainder = fileCount % 3;
|
||||
const quotient = Math.floor(fileCount / 3);
|
||||
|
||||
let checkCount: number;
|
||||
|
||||
if (remainder === 1 && fileCount > 1) {
|
||||
checkCount = quotient - 1;
|
||||
} else if (remainder === 2 && fileCount > 1) {
|
||||
checkCount = quotient;
|
||||
}
|
||||
|
||||
this.message.sentMessageJson.thumbUrls.forEach((v, idx) => {
|
||||
const tile: Tile = {};
|
||||
|
||||
if (checkCount <= Math.floor(idx / 3)) {
|
||||
tile.colspan = 3;
|
||||
} else if (fileCount === 1) {
|
||||
tile.colspan = 6;
|
||||
} else {
|
||||
tile.colspan = 2;
|
||||
}
|
||||
tile.imgSrc = this.message.sentMessageJson.baseUrl + v;
|
||||
this.tiles.push(tile);
|
||||
});
|
||||
}
|
||||
|
||||
mouseEnter(event: MouseEvent): void {
|
||||
if (!this.roomInfo || this.roomInfo.expiredFileStdSeq > this.message.seq) {
|
||||
this.showExpired = true;
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
mouseLeave(event: MouseEvent): void {
|
||||
if (!this.roomInfo || this.roomInfo.expiredFileStdSeq > this.message.seq) {
|
||||
this.showExpired = false;
|
||||
}
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
getExpiredFile() {
|
||||
if (
|
||||
!!this.roomInfo &&
|
||||
this.roomInfo.expiredFileStdSeq <= this.message.seq
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
onClickFileViewer(index: number) {
|
||||
if (!this.getExpiredFile()) {
|
||||
this.fileViewer.emit({
|
||||
attachmentSeq: this._message.sentMessageJson.attachmentSeq,
|
||||
index
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import { StatusCode, JsonAnalization } from '@ucap-webmessenger/api';
|
||||
import { EventJsonDecoder } from './event-json';
|
||||
|
||||
export interface BundleImageEventJson {
|
||||
statusCode?: StatusCode;
|
||||
errorMessage?: string;
|
||||
roomSeq?: number;
|
||||
attachmentSeq?: number;
|
||||
fileCount?: number;
|
||||
baseUrl?: string;
|
||||
thumbUrls?: string[];
|
||||
}
|
||||
|
||||
export const decodeBundleImageEventJson: EventJsonDecoder<BundleImageEventJson> = (
|
||||
message: string
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(message);
|
||||
|
||||
return {
|
||||
statusCode: json.StatusCode,
|
||||
errorMessage: json.ErrorMessage,
|
||||
roomSeq: Number(json.RoomID),
|
||||
attachmentSeq: Number(json.AttSEQ),
|
||||
fileCount: Number(json.FileCount),
|
||||
baseUrl: json.BaseURL,
|
||||
thumbUrls: json.ThumbURL
|
||||
} as BundleImageEventJson;
|
||||
} catch (e) {
|
||||
return {
|
||||
statusCode: StatusCode.Fail,
|
||||
errorMessage: e.toString()
|
||||
} as BundleImageEventJson;
|
||||
}
|
||||
};
|
409
documents/업무/2월/3째주/file-viewer-prj/common-api.service.ts
Normal file
409
documents/업무/2월/3째주/file-viewer-prj/common-api.service.ts
Normal file
|
@ -0,0 +1,409 @@
|
|||
import { Injectable, Inject } from '@angular/core';
|
||||
import {
|
||||
HttpClient,
|
||||
HttpEventType,
|
||||
HttpResponse,
|
||||
HttpRequest
|
||||
} from '@angular/common/http';
|
||||
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { map, filter } from 'rxjs/operators';
|
||||
|
||||
import {
|
||||
FileProfileSaveRequest,
|
||||
FileProfileSaveResponse,
|
||||
encodeFileProfileSave,
|
||||
decodeFileProfileSave
|
||||
} from '../apis/file-profile-save';
|
||||
import {
|
||||
FileTalkDownloadRequest,
|
||||
encodeFileTalkDownload,
|
||||
encodeFormDataFileTalkDownload
|
||||
} from '../apis/file-talk-download';
|
||||
import {
|
||||
FileTalkSaveRequest,
|
||||
FileTalkSaveResponse,
|
||||
encodeFileTalkSave,
|
||||
decodeFileTalkSave
|
||||
} from '../apis/file-talk-save';
|
||||
import {
|
||||
FileTalkSaveMultiRequest,
|
||||
FileTalkSaveMultiResponse,
|
||||
encodeFileTalkSaveMulti,
|
||||
decodeFileTalkSaveMulti
|
||||
} from '../apis/file-talk-save-multi';
|
||||
import {
|
||||
FileTalkShareRequest,
|
||||
FileTalkShareResponse,
|
||||
encodeFileTalkShare,
|
||||
decodeFileTalkShare
|
||||
} from '../apis/file-talk-share';
|
||||
import {
|
||||
MassTalkDownloadRequest,
|
||||
MassTalkDownloadResponse,
|
||||
encodeMassTalkDownload,
|
||||
decodeMassTalkDownload
|
||||
} from '../apis/mass-talk-download';
|
||||
import {
|
||||
MassTalkSaveRequest,
|
||||
MassTalkSaveResponse,
|
||||
encodeMassTalkSave,
|
||||
decodeMassTalkSave
|
||||
} from '../apis/mass-talk-save';
|
||||
import {
|
||||
TransMassTalkDownloadRequest,
|
||||
TransMassTalkDownloadResponse,
|
||||
encodeTransMassTalkDownload,
|
||||
decodeTransMassTalkDownload
|
||||
} from '../apis/trans-mass-talk-download';
|
||||
import {
|
||||
TransMassTalkSaveRequest,
|
||||
TransMassTalkSaveResponse,
|
||||
encodeTransMassTalkSave,
|
||||
decodeTransMassTalkSave
|
||||
} from '../apis/trans-mass-talk-save';
|
||||
import {
|
||||
TranslationReqRequest,
|
||||
TranslationReqResponse,
|
||||
encodeTranslationReq,
|
||||
decodeTranslationReq
|
||||
} from '../apis/translation-req';
|
||||
import {
|
||||
TranslationSaveRequest,
|
||||
TranslationSaveResponse,
|
||||
encodeTranslationSave,
|
||||
decodeTranslationSave
|
||||
} from '../apis/translation-save';
|
||||
|
||||
import { _MODULE_CONFIG } from '../config/token';
|
||||
import { ModuleConfig } from '../config/module-config';
|
||||
import { Urls } from '../config/urls';
|
||||
import { UrlConfig } from '@ucap-webmessenger/core';
|
||||
import { FileDownloadItem } from '@ucap-webmessenger/api';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CommonApiService {
|
||||
readonly urls: Urls;
|
||||
|
||||
constructor(
|
||||
@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
|
||||
private httpClient: HttpClient
|
||||
) {
|
||||
this.urls = UrlConfig.getUrls(
|
||||
this.moduleConfig.hostConfig,
|
||||
this.moduleConfig.urls
|
||||
);
|
||||
}
|
||||
|
||||
public fileProfileSave(
|
||||
req: FileProfileSaveRequest,
|
||||
fileProfileSaveUrl?: string
|
||||
): Observable<FileProfileSaveResponse> {
|
||||
const httpReq = new HttpRequest(
|
||||
'POST',
|
||||
!!fileProfileSaveUrl ? fileProfileSaveUrl : this.urls.fileProfileSave,
|
||||
encodeFileProfileSave(req),
|
||||
{ reportProgress: true, responseType: 'text' as 'json' }
|
||||
);
|
||||
|
||||
const progress = req.fileUploadItem.uploadStart();
|
||||
|
||||
return this.httpClient.request(httpReq).pipe(
|
||||
filter(event => {
|
||||
if (event instanceof HttpResponse) {
|
||||
return true;
|
||||
} else if (HttpEventType.UploadProgress === event.type) {
|
||||
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map((event: HttpResponse<any>) => {
|
||||
req.fileUploadItem.uploadComplete();
|
||||
return decodeFileProfileSave(event.body);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public urlForFileTalkDownload(
|
||||
req: FileTalkDownloadRequest,
|
||||
fileTalkDownloadUrl?: string
|
||||
): string {
|
||||
const httpReq = new HttpRequest(
|
||||
'GET',
|
||||
!!fileTalkDownloadUrl ? fileTalkDownloadUrl : this.urls.fileTalkDownload,
|
||||
{},
|
||||
{
|
||||
params: encodeFileTalkDownload(req)
|
||||
}
|
||||
);
|
||||
|
||||
return httpReq.urlWithParams;
|
||||
}
|
||||
|
||||
public fileTalkDownload(
|
||||
req: FileTalkDownloadRequest,
|
||||
fileTalkDownloadUrl?: string
|
||||
): Observable<Blob> {
|
||||
const httpReq = new HttpRequest(
|
||||
'POST',
|
||||
!!fileTalkDownloadUrl ? fileTalkDownloadUrl : this.urls.fileTalkDownload,
|
||||
encodeFormDataFileTalkDownload(req),
|
||||
{ reportProgress: true, responseType: 'blob' }
|
||||
);
|
||||
|
||||
let progress: Subject<number>;
|
||||
if (!!req.fileDownloadItem) {
|
||||
progress = req.fileDownloadItem.downloadStart();
|
||||
}
|
||||
|
||||
return this.httpClient.request(httpReq).pipe(
|
||||
filter(event => {
|
||||
if (event instanceof HttpResponse) {
|
||||
return true;
|
||||
} else if (HttpEventType.DownloadProgress === event.type) {
|
||||
if (!!progress) {
|
||||
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map((event: HttpResponse<any>) => {
|
||||
if (!!progress) {
|
||||
req.fileDownloadItem.downloadComplete();
|
||||
}
|
||||
return event.body;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public fileTalkSave(
|
||||
req: FileTalkSaveRequest,
|
||||
fileTalkSaveUrl?: string
|
||||
): Observable<FileTalkSaveResponse> {
|
||||
const httpReq = new HttpRequest(
|
||||
'POST',
|
||||
!!fileTalkSaveUrl ? fileTalkSaveUrl : this.urls.fileTalkSave,
|
||||
encodeFileTalkSave(req),
|
||||
{ reportProgress: true, responseType: 'text' as 'json' }
|
||||
);
|
||||
|
||||
const progress = req.fileUploadItem.uploadStart();
|
||||
|
||||
return this.httpClient.request(httpReq).pipe(
|
||||
filter(event => {
|
||||
if (event instanceof HttpResponse) {
|
||||
return true;
|
||||
} else if (HttpEventType.UploadProgress === event.type) {
|
||||
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map((event: HttpResponse<any>) => {
|
||||
req.fileUploadItem.uploadComplete();
|
||||
return decodeFileTalkSave(event.body);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public fileTalkSaveMulti(
|
||||
req: FileTalkSaveMultiRequest,
|
||||
fileTalkSaveMultiUrl?: string
|
||||
): Observable<FileTalkSaveMultiResponse> {
|
||||
const httpReq = new HttpRequest(
|
||||
'POST',
|
||||
!!fileTalkSaveMultiUrl
|
||||
? fileTalkSaveMultiUrl
|
||||
: this.urls.fileTalkSaveMulti,
|
||||
encodeFileTalkSaveMulti(req),
|
||||
{ reportProgress: true, responseType: 'text' as 'json' }
|
||||
);
|
||||
|
||||
const progress = req.fileUploadItem.uploadStart();
|
||||
|
||||
return this.httpClient.request(httpReq).pipe(
|
||||
filter(event => {
|
||||
if (event instanceof HttpResponse) {
|
||||
return true;
|
||||
} else if (HttpEventType.UploadProgress === event.type) {
|
||||
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map((event: HttpResponse<any>) => {
|
||||
req.fileUploadItem.uploadComplete();
|
||||
return decodeFileTalkSaveMulti(event.body);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public acceptableExtensionForFileTalk(
|
||||
extensions: string[]
|
||||
): { accept: boolean; reject: string[] } {
|
||||
let accept = true;
|
||||
const reject: string[] = [];
|
||||
for (const extension of extensions) {
|
||||
if (
|
||||
-1 ===
|
||||
this.moduleConfig.acceptableFileExtensions.indexOf(
|
||||
extension.toLowerCase()
|
||||
)
|
||||
) {
|
||||
reject.push(extension);
|
||||
accept = false;
|
||||
}
|
||||
}
|
||||
return {
|
||||
accept,
|
||||
reject
|
||||
};
|
||||
}
|
||||
|
||||
public fileTalkShare(
|
||||
req: FileTalkShareRequest
|
||||
): Observable<FileTalkShareResponse> {
|
||||
return this.httpClient
|
||||
.post<any>(
|
||||
this.urls.fileTalkShare,
|
||||
{},
|
||||
{
|
||||
params: encodeFileTalkShare(req)
|
||||
}
|
||||
)
|
||||
.pipe(map(res => decodeFileTalkShare(res)));
|
||||
}
|
||||
|
||||
public massTalkDownload(
|
||||
req: MassTalkDownloadRequest
|
||||
): Observable<MassTalkDownloadResponse> {
|
||||
return this.httpClient
|
||||
.post<any>(
|
||||
this.urls.massTalkDownload,
|
||||
{},
|
||||
{
|
||||
params: encodeMassTalkDownload(req),
|
||||
responseType: 'text' as 'json'
|
||||
}
|
||||
)
|
||||
.pipe(map(res => decodeMassTalkDownload(res)));
|
||||
}
|
||||
|
||||
public massTalkSave(
|
||||
req: MassTalkSaveRequest
|
||||
): Observable<MassTalkSaveResponse> {
|
||||
const httpReq = new HttpRequest(
|
||||
'POST',
|
||||
this.urls.massTalkSave,
|
||||
encodeMassTalkSave(req),
|
||||
{ reportProgress: true, responseType: 'text' as 'json' }
|
||||
);
|
||||
|
||||
return this.httpClient.request(httpReq).pipe(
|
||||
filter(event => {
|
||||
if (event instanceof HttpResponse) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map(res => decodeMassTalkSave((res as HttpResponse<any>).body))
|
||||
);
|
||||
}
|
||||
|
||||
public transMassTalkDownload(
|
||||
req: TransMassTalkDownloadRequest
|
||||
): Observable<TransMassTalkDownloadResponse> {
|
||||
return this.httpClient
|
||||
.post<any>(
|
||||
this.urls.transMassTalkDownload,
|
||||
{},
|
||||
{
|
||||
params: encodeTransMassTalkDownload(req)
|
||||
}
|
||||
)
|
||||
.pipe(map(res => decodeTransMassTalkDownload(res)));
|
||||
}
|
||||
|
||||
public transMassTalkSave(
|
||||
req: TransMassTalkSaveRequest
|
||||
): Observable<TransMassTalkSaveResponse> {
|
||||
return this.httpClient
|
||||
.post<any>(
|
||||
this.urls.transMassTalkSave,
|
||||
{},
|
||||
{
|
||||
params: encodeTransMassTalkSave(req)
|
||||
}
|
||||
)
|
||||
.pipe(map(res => decodeTransMassTalkSave(res)));
|
||||
}
|
||||
|
||||
public translationReq(
|
||||
req: TranslationReqRequest
|
||||
): Observable<TranslationReqResponse> {
|
||||
return this.httpClient
|
||||
.post<any>(
|
||||
this.urls.translationReq,
|
||||
{},
|
||||
{
|
||||
params: encodeTranslationReq(req)
|
||||
}
|
||||
)
|
||||
.pipe(map(res => decodeTranslationReq(res)));
|
||||
}
|
||||
|
||||
public translationSave(
|
||||
req: TranslationSaveRequest
|
||||
): Observable<TranslationSaveResponse> {
|
||||
const httpReq = new HttpRequest(
|
||||
'POST',
|
||||
this.urls.translationSave,
|
||||
encodeTranslationSave(req),
|
||||
{ reportProgress: true }
|
||||
);
|
||||
|
||||
return this.httpClient.request(httpReq).pipe(
|
||||
filter(event => {
|
||||
if (event instanceof HttpResponse) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map(res => decodeTranslationSave((res as HttpResponse<any>).body))
|
||||
);
|
||||
}
|
||||
|
||||
public fileDownload(
|
||||
fileDownloadUrl: string,
|
||||
fileDownloadItem: FileDownloadItem
|
||||
): Observable<Blob> {
|
||||
const httpReq = new HttpRequest('GET', fileDownloadUrl, null, {
|
||||
reportProgress: true,
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
let progress: Subject<number>;
|
||||
if (!!fileDownloadItem) {
|
||||
progress = fileDownloadItem.downloadStart();
|
||||
}
|
||||
|
||||
return this.httpClient.request(httpReq).pipe(
|
||||
filter(event => {
|
||||
if (event instanceof HttpResponse) {
|
||||
return true;
|
||||
} else if (HttpEventType.DownloadProgress === event.type) {
|
||||
if (!!progress) {
|
||||
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map((event: HttpResponse<any>) => {
|
||||
if (!!progress) {
|
||||
fileDownloadItem.downloadComplete();
|
||||
}
|
||||
return event.body;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
43
documents/업무/2월/3째주/file-viewer-prj/file-info.ts
Normal file
43
documents/업무/2월/3째주/file-viewer-prj/file-info.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { FileType } from '../types/file.type';
|
||||
import { FileEventJson } from '@ucap-webmessenger/protocol-event';
|
||||
|
||||
export interface FileInfo {
|
||||
// 대화방SEQ
|
||||
roomSeq: string;
|
||||
// 이벤트SEQ
|
||||
eventSeq: number;
|
||||
// 파일SEQ
|
||||
seq: number;
|
||||
// 송신자SEQ
|
||||
senderSeq: number;
|
||||
// 파일타입
|
||||
type: FileType;
|
||||
// 파일이름
|
||||
name: string;
|
||||
// 파일URL
|
||||
url: string;
|
||||
// 파일크기(byte)
|
||||
size: number;
|
||||
// 전송일시
|
||||
sendDate: string;
|
||||
// 수신완료자수
|
||||
receivedUserCount: number;
|
||||
// 수신자수
|
||||
receiverCount: number;
|
||||
// 발신내용
|
||||
sentMessage: string;
|
||||
// 발신내용 For Json
|
||||
sentMessageJson?: FileEventJson;
|
||||
}
|
||||
|
||||
export function isMedia(fileInfo: FileInfo): boolean {
|
||||
return (
|
||||
[FileType.Image, FileType.Sound, FileType.Video, FileType.Bundle].some(
|
||||
v => v === fileInfo.type
|
||||
) || isSound(fileInfo)
|
||||
);
|
||||
}
|
||||
|
||||
export function isSound(fileInfo: FileInfo): boolean {
|
||||
return -1 !== ['mp3'].indexOf(fileInfo.sentMessageJson.fileExt);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<ng-container *ngIf="!!currentFileInfo">
|
||||
<ucap-file-viewer
|
||||
*ngIf="!isMediaType"
|
||||
[fileInfo]="fileInfo"
|
||||
[fileDownloadUrl]="fileDownloadUrl"
|
||||
(download)="onDownload($event)"
|
||||
(closed)="onClosedViewer()"
|
||||
></ucap-file-viewer>
|
||||
|
||||
<ucap-media-viewer
|
||||
*ngIf="isMediaType"
|
||||
[fileInfo]="fileInfo"
|
||||
[fileDownloadUrl]="fileDownloadUrl"
|
||||
(download)="onDownload($event)"
|
||||
(closed)="onClosedViewer()"
|
||||
></ucap-media-viewer>
|
||||
</ng-container>
|
|
@ -0,0 +1,111 @@
|
|||
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
|
||||
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { DeviceType } from '@ucap-webmessenger/core';
|
||||
import { FileDownloadItem } from '@ucap-webmessenger/api';
|
||||
import { CommonApiService } from '@ucap-webmessenger/api-common';
|
||||
import { AppFileService } from '@app/services/file.service';
|
||||
import { FileInfo, isMedia } from '@ucap-webmessenger/protocol-file';
|
||||
import { SelectFileInfo } from '@ucap-webmessenger/ui';
|
||||
|
||||
export interface FileViewerDialogData {
|
||||
fileInfos: FileInfo[];
|
||||
selectFileInfo: SelectFileInfo;
|
||||
downloadUrl: string;
|
||||
userSeq: number;
|
||||
deviceType: DeviceType;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface FileViewerDialogResult {}
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-common-file-viewer',
|
||||
templateUrl: './file-viewer.dialog.component.html',
|
||||
styleUrls: ['./file-viewer.dialog.component.scss']
|
||||
})
|
||||
export class FileViewerDialogComponent implements OnInit, OnDestroy {
|
||||
isMediaType: boolean;
|
||||
fileInfo: {
|
||||
fileInfos: FileInfo[];
|
||||
selectFileInfo: SelectFileInfo;
|
||||
};
|
||||
|
||||
currentFileInfo: FileInfo;
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<
|
||||
FileViewerDialogData,
|
||||
FileViewerDialogResult
|
||||
>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: FileViewerDialogData,
|
||||
private commonApiService: CommonApiService,
|
||||
private appFileService: AppFileService,
|
||||
private logger: NGXLogger
|
||||
) {
|
||||
this.currentFileInfo = this.data.fileInfos.find(
|
||||
f => f.seq === this.data.selectFileInfo.attachmentSeq
|
||||
);
|
||||
|
||||
if (!this.currentFileInfo) {
|
||||
this.logger.warn(
|
||||
'file info is exist',
|
||||
this.data.fileInfos,
|
||||
this.data.selectFileInfo
|
||||
);
|
||||
this.dialogRef.close();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isMediaType = isMedia(this.currentFileInfo);
|
||||
|
||||
this.fileInfo = {
|
||||
fileInfos: this.data.fileInfos.filter(f => {
|
||||
const i = isMedia(f);
|
||||
return this.isMediaType ? i : !i;
|
||||
}),
|
||||
selectFileInfo: this.data.selectFileInfo
|
||||
};
|
||||
}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngOnDestroy(): void {}
|
||||
|
||||
onDownload(info: {
|
||||
attachmentSeq?: number;
|
||||
downloadUrl?: string;
|
||||
fileName: string;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
}): void {
|
||||
this.appFileService.fileTalkDownlod({
|
||||
req: {
|
||||
userSeq: this.data.userSeq,
|
||||
deviceType: this.data.deviceType,
|
||||
token: this.data.token,
|
||||
attachmentsSeq: info.attachmentSeq,
|
||||
fileDownloadItem: info.fileDownloadItem
|
||||
},
|
||||
directDownloadUrl: info.downloadUrl,
|
||||
fileName: info.fileName,
|
||||
fileDownloadUrl: this.data.downloadUrl
|
||||
});
|
||||
}
|
||||
|
||||
onClosedViewer(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
fileDownloadUrl = (attachmentSeq: number) => {
|
||||
return this.commonApiService.urlForFileTalkDownload(
|
||||
{
|
||||
userSeq: this.data.userSeq,
|
||||
deviceType: this.data.deviceType,
|
||||
token: this.data.token,
|
||||
attachmentsSeq: attachmentSeq
|
||||
},
|
||||
this.data.downloadUrl
|
||||
);
|
||||
};
|
||||
}
|
73
documents/업무/2월/3째주/file-viewer-prj/file.component.ts
Normal file
73
documents/업무/2월/3째주/file-viewer-prj/file.component.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core';
|
||||
import { Info, FileEventJson } from '@ucap-webmessenger/protocol-event';
|
||||
import { StatusCode, FileDownloadItem } from '@ucap-webmessenger/api';
|
||||
import { FileType } from '@ucap-webmessenger/protocol-file';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { RoomInfo } from '@ucap-webmessenger/protocol-room';
|
||||
import { SelectFileInfo } from '@ucap-webmessenger/ui';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box-file',
|
||||
templateUrl: './file.component.html',
|
||||
styleUrls: ['./file.component.scss']
|
||||
})
|
||||
export class FileComponent implements OnInit {
|
||||
@Input()
|
||||
message: Info<FileEventJson>;
|
||||
@Input()
|
||||
roomInfo: RoomInfo;
|
||||
|
||||
@Output()
|
||||
save = new EventEmitter<{
|
||||
fileInfo: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
}>();
|
||||
@Output()
|
||||
fileViewer = new EventEmitter<SelectFileInfo>();
|
||||
|
||||
fileInfo?: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
errorMessage?: string;
|
||||
FileType = FileType;
|
||||
|
||||
constructor(private logger: NGXLogger) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (StatusCode.Success === this.message.sentMessageJson.statusCode) {
|
||||
this.fileInfo = this.message.sentMessageJson;
|
||||
} else {
|
||||
this.errorMessage =
|
||||
this.message.sentMessageJson.errorMessage || '[Error] System Error!!';
|
||||
}
|
||||
|
||||
this.fileDownloadItem = new FileDownloadItem();
|
||||
}
|
||||
|
||||
getExpiredFile() {
|
||||
if (
|
||||
!!this.roomInfo &&
|
||||
this.roomInfo.expiredFileStdSeq <= this.message.seq
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
onClickFileViewer(fileInfo: FileEventJson) {
|
||||
if (!this.getExpiredFile()) {
|
||||
this.fileViewer.emit({ attachmentSeq: this.fileInfo.attachmentSeq });
|
||||
}
|
||||
}
|
||||
|
||||
onSave(value: string) {
|
||||
if (!this.getExpiredFile()) {
|
||||
this.save.emit({
|
||||
fileInfo: this.fileInfo,
|
||||
fileDownloadItem: this.fileDownloadItem,
|
||||
type: value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
52
documents/업무/2월/3째주/file-viewer-prj/file.event-json.ts
Normal file
52
documents/업무/2월/3째주/file-viewer-prj/file.event-json.ts
Normal file
|
@ -0,0 +1,52 @@
|
|||
import { StatusCode, JsonAnalization } from '@ucap-webmessenger/api';
|
||||
import { FileType } from '@ucap-webmessenger/protocol-file';
|
||||
import { EventJsonDecoder } from './event-json';
|
||||
|
||||
export interface FileEventJson {
|
||||
statusCode?: StatusCode;
|
||||
errorMessage?: string;
|
||||
roomSeq?: number;
|
||||
fileName?: string;
|
||||
fileExt?: string;
|
||||
fileType?: FileType;
|
||||
thumbUrl?: string;
|
||||
attachmentSeq?: number;
|
||||
attachmentSize?: number;
|
||||
attachmentRegDate?: string;
|
||||
imageWidth?: number;
|
||||
imageHeight?: number;
|
||||
companyCode?: string;
|
||||
voiceTime?: string;
|
||||
synappKey?: string;
|
||||
}
|
||||
|
||||
export const decodeFileEventJson: EventJsonDecoder<FileEventJson> = (
|
||||
message: string
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(message);
|
||||
|
||||
return {
|
||||
statusCode: json.StatusCode,
|
||||
errorMessage: json.ErrorMessage,
|
||||
roomSeq: Number(json.RoomID),
|
||||
fileName: json.FileName,
|
||||
fileExt: json.FileExt,
|
||||
fileType: json.FileType,
|
||||
thumbUrl: json.ThumbURL,
|
||||
attachmentSeq: Number(json.AttSEQ),
|
||||
attachmentSize: Number(json.AttSize),
|
||||
attachmentRegDate: json.AttRegDate,
|
||||
imageWidth: Number(json.ImageWidth),
|
||||
imageHeight: Number(json.ImageHeight),
|
||||
companyCode: json.CompanyCode,
|
||||
voiceTime: json.VoiceTime,
|
||||
synappKey: json.SynappKey
|
||||
} as FileEventJson;
|
||||
} catch (e) {
|
||||
return {
|
||||
statusCode: StatusCode.Fail,
|
||||
errorMessage: e.toString()
|
||||
} as FileEventJson;
|
||||
}
|
||||
};
|
167
documents/업무/2월/3째주/file-viewer-prj/file.service.ts
Normal file
167
documents/업무/2월/3째주/file-viewer-prj/file.service.ts
Normal file
|
@ -0,0 +1,167 @@
|
|||
import { Injectable, Inject, NgZone } from '@angular/core';
|
||||
import {
|
||||
FileTalkDownloadRequest,
|
||||
CommonApiService
|
||||
} from '@ucap-webmessenger/api-common';
|
||||
import { map, take, finalize, catchError } from 'rxjs/operators';
|
||||
import { MimeUtil, FileUtil } from '@ucap-webmessenger/core';
|
||||
import { FileProtocolService } from '@ucap-webmessenger/protocol-file';
|
||||
import { UCAP_NATIVE_SERVICE, NativeService } from '@ucap-webmessenger/native';
|
||||
import {
|
||||
SnackBarService,
|
||||
AlertSnackbarComponent,
|
||||
AlertSnackbarData
|
||||
} from '@ucap-webmessenger/ui';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { of } from 'rxjs';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AppFileService {
|
||||
constructor(
|
||||
private commonApiService: CommonApiService,
|
||||
private fileProtocolService: FileProtocolService,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private snackBarService: SnackBarService,
|
||||
private translateService: TranslateService,
|
||||
private httpClient: HttpClient,
|
||||
private ngZone: NgZone,
|
||||
private logger: NGXLogger
|
||||
) {}
|
||||
|
||||
fileTalkDownlod(param: {
|
||||
req?: FileTalkDownloadRequest;
|
||||
directDownloadUrl?: string;
|
||||
fileName: string;
|
||||
fileDownloadUrl?: string;
|
||||
savePath?: string;
|
||||
}) {
|
||||
const req = param.req;
|
||||
const directDownloadUrl = param.directDownloadUrl;
|
||||
const fileName = param.fileName;
|
||||
const fileDownloadItem = req.fileDownloadItem;
|
||||
const fileDownloadUrl = param.fileDownloadUrl;
|
||||
const savePath = param.savePath;
|
||||
|
||||
if (!!req && !!req.attachmentsSeq) {
|
||||
this.commonApiService
|
||||
.fileTalkDownload(req, fileDownloadUrl)
|
||||
.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 => {
|
||||
/** download check */
|
||||
this.fileProtocolService
|
||||
.downCheck({
|
||||
seq: req.attachmentsSeq
|
||||
})
|
||||
.pipe(take(1))
|
||||
.subscribe();
|
||||
|
||||
this.saveFile(buffer, fileName, mimeType, savePath);
|
||||
})
|
||||
.catch(reason => {
|
||||
this.fileTalkDownloadError(reason);
|
||||
});
|
||||
}),
|
||||
finalize(() => {
|
||||
if (!!fileDownloadItem) {
|
||||
setTimeout(() => {
|
||||
fileDownloadItem.downloadingProgress$ = undefined;
|
||||
}, 1000);
|
||||
}
|
||||
}),
|
||||
catchError(error => of(error))
|
||||
)
|
||||
.subscribe();
|
||||
} else if (!!directDownloadUrl) {
|
||||
this.commonApiService
|
||||
.fileDownload(directDownloadUrl, fileDownloadItem)
|
||||
.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.saveFile(buffer, fileName, mimeType, savePath);
|
||||
})
|
||||
.catch(reason => {
|
||||
this.fileTalkDownloadError(reason);
|
||||
});
|
||||
}),
|
||||
finalize(() => {
|
||||
if (!!fileDownloadItem) {
|
||||
setTimeout(() => {
|
||||
fileDownloadItem.downloadingProgress$ = undefined;
|
||||
}, 1000);
|
||||
}
|
||||
}),
|
||||
catchError(error => of(error))
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private saveFile(
|
||||
buffer: Buffer,
|
||||
fileName: string,
|
||||
mimeType: string,
|
||||
savePath: string
|
||||
): void {
|
||||
this.nativeService
|
||||
.saveFile(buffer, fileName, mimeType, savePath)
|
||||
.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 {
|
||||
this.fileTalkDownloadError('fail');
|
||||
}
|
||||
})
|
||||
.catch(reason => {
|
||||
this.fileTalkDownloadError(reason);
|
||||
});
|
||||
}
|
||||
|
||||
private fileTalkDownloadError(reason: any): void {
|
||||
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')
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
33
documents/업무/2월/3째주/file-viewer-prj/mass-text.event-json.ts
Normal file
33
documents/업무/2월/3째주/file-viewer-prj/mass-text.event-json.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { StatusCode, JsonAnalization } from '@ucap-webmessenger/api';
|
||||
import { EventJsonDecoder } from './event-json';
|
||||
|
||||
export interface MassTextEventJson {
|
||||
statusCode?: StatusCode;
|
||||
errorMessage?: string;
|
||||
roomSeq?: number;
|
||||
massSeq?: number;
|
||||
regDate?: string;
|
||||
content?: string;
|
||||
}
|
||||
|
||||
export const decodeMassTextEventJson: EventJsonDecoder<MassTextEventJson> = (
|
||||
message: string
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(message);
|
||||
|
||||
return {
|
||||
statusCode: json.StatusCode,
|
||||
errorMessage: json.ErrorMessage,
|
||||
roomSeq: Number(json.RoomID),
|
||||
massSeq: Number(json.EventMassSeq),
|
||||
regDate: json.RegDate,
|
||||
content: json.Content
|
||||
} as MassTextEventJson;
|
||||
} catch (e) {
|
||||
return {
|
||||
statusCode: StatusCode.Fail,
|
||||
errorMessage: e.toString()
|
||||
} as MassTextEventJson;
|
||||
}
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
import { StatusCode, JsonAnalization } from '@ucap-webmessenger/api';
|
||||
import { EventJsonDecoder } from './event-json';
|
||||
|
||||
export interface MassTranslationEventJson {
|
||||
statusCode?: StatusCode;
|
||||
errorMessage?: string;
|
||||
translationSeq?: number;
|
||||
destLocale?: string;
|
||||
roomSeq?: number;
|
||||
regDate?: string;
|
||||
original?: string;
|
||||
translation?: string;
|
||||
}
|
||||
|
||||
export const decodeMassTranslationEventJson: EventJsonDecoder<MassTranslationEventJson> = (
|
||||
message: string
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(message);
|
||||
|
||||
return {
|
||||
statusCode: json.StatusCode,
|
||||
errorMessage: json.ErrorMessage,
|
||||
translationSeq: Number(json.EventTransSeq),
|
||||
destLocale: json.DestLocale,
|
||||
roomSeq: Number(json.RoomID),
|
||||
regDate: json.RegDate,
|
||||
original: json.Original,
|
||||
translation: json.Translation
|
||||
} as MassTranslationEventJson;
|
||||
} catch (e) {
|
||||
return {
|
||||
statusCode: StatusCode.Fail,
|
||||
errorMessage: e.toString()
|
||||
} as MassTranslationEventJson;
|
||||
}
|
||||
};
|
205
documents/업무/2월/3째주/file-viewer-prj/message-box.component.ts
Normal file
205
documents/업무/2월/3째주/file-viewer-prj/message-box.component.ts
Normal file
|
@ -0,0 +1,205 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
EventEmitter,
|
||||
Output,
|
||||
AfterViewInit,
|
||||
ElementRef,
|
||||
ViewChild,
|
||||
ChangeDetectorRef
|
||||
} from '@angular/core';
|
||||
|
||||
import { shakeAnimation } from 'angular-animations';
|
||||
|
||||
import {
|
||||
Info,
|
||||
EventType,
|
||||
InfoResponse,
|
||||
EventJson,
|
||||
FileEventJson,
|
||||
MassTranslationEventJson
|
||||
} from '@ucap-webmessenger/protocol-event';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import moment from 'moment';
|
||||
import { FileDownloadItem } from '@ucap-webmessenger/api';
|
||||
import { RoomInfo } from '@ucap-webmessenger/protocol-room';
|
||||
import { SelectFileInfo } from '@ucap-webmessenger/ui';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-message-box',
|
||||
templateUrl: './message-box.component.html',
|
||||
styleUrls: ['./message-box.component.scss'],
|
||||
animations: [shakeAnimation()]
|
||||
})
|
||||
export class MessageBoxComponent implements OnInit, AfterViewInit {
|
||||
@Input()
|
||||
message: Info<EventJson>;
|
||||
|
||||
@Input()
|
||||
mine = false;
|
||||
|
||||
@Input()
|
||||
highlight = false;
|
||||
|
||||
@Input()
|
||||
existReadToHere = false;
|
||||
|
||||
@Input()
|
||||
dateChanged = false;
|
||||
|
||||
@Input()
|
||||
senderName: string;
|
||||
|
||||
@Input()
|
||||
profileImageRoot: string;
|
||||
|
||||
@Input()
|
||||
profileImage: string;
|
||||
|
||||
@Input()
|
||||
roomInfo: RoomInfo;
|
||||
|
||||
@Input()
|
||||
translationSimpleview = false;
|
||||
|
||||
@Input()
|
||||
unreadCount: number;
|
||||
|
||||
@Output()
|
||||
openProfile = new EventEmitter<number>();
|
||||
|
||||
@Output()
|
||||
massDetail = new EventEmitter<number>();
|
||||
|
||||
@Output()
|
||||
massTranslationDetail = new EventEmitter<{
|
||||
message: Info<MassTranslationEventJson>;
|
||||
contentsType: string;
|
||||
}>();
|
||||
|
||||
@Output()
|
||||
fileViewer = new EventEmitter<SelectFileInfo>();
|
||||
|
||||
@Output()
|
||||
save = new EventEmitter<{
|
||||
fileInfo: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
}>();
|
||||
|
||||
@Output()
|
||||
contextMenu = new EventEmitter<{
|
||||
event: MouseEvent;
|
||||
message: Info<EventJson>;
|
||||
type?: string;
|
||||
}>();
|
||||
|
||||
@ViewChild('mbContainer', { static: true })
|
||||
mbContainer: ElementRef<HTMLElement>;
|
||||
|
||||
@ViewChild('mbChatRow', { static: true })
|
||||
mbChatRow: ElementRef<HTMLElement>;
|
||||
|
||||
EventType = EventType;
|
||||
|
||||
moment = moment;
|
||||
|
||||
firstEventSeq = 0;
|
||||
existReadHere = false;
|
||||
shakeIt = false;
|
||||
|
||||
get offsetTop() {
|
||||
return this.mbChatRow.nativeElement.offsetTop;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef<HTMLElement>,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private logger: NGXLogger
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.mbContainer.nativeElement.classList.add('hide');
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.elementRef.nativeElement.style.height = `${this.mbContainer.nativeElement.offsetHeight}px`;
|
||||
this.elementRef.nativeElement.style.maxHeight = `${this.mbContainer.nativeElement.offsetHeight}px`;
|
||||
this.mbContainer.nativeElement.classList.remove('hide');
|
||||
}
|
||||
|
||||
/**
|
||||
* 정보성 Event 인지 판단.
|
||||
* @description 정보성 event 일 경우 프로필, 일시 를 표현하지 않는다.
|
||||
* Edit with reducers.ts / sync / updateRoomForNewEventMessage
|
||||
*/
|
||||
isInformation(info: Info<EventJson>) {
|
||||
if (
|
||||
info.type === EventType.Join ||
|
||||
info.type === EventType.Exit ||
|
||||
info.type === EventType.ForcedExit ||
|
||||
info.type === EventType.RenameRoom ||
|
||||
info.type === EventType.NotificationForiOSCapture ||
|
||||
info.type === EventType.NotificationForTimerRoom ||
|
||||
info.type === EventType.GuideForRoomTimerChanged
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
onClickOpenProfile(event: MouseEvent, userSeq: number) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
this.openProfile.emit(userSeq);
|
||||
}
|
||||
|
||||
/** [Event] MassTalk Detail View */
|
||||
onMassDetail(value: number) {
|
||||
this.massDetail.emit(value);
|
||||
}
|
||||
|
||||
// onMassTranslationDetail(params: {
|
||||
// message: Info<MassTranslationEventJson>;
|
||||
// contentsType: string;
|
||||
// }) {
|
||||
// this.massTranslationDetail.emit(params);
|
||||
// }
|
||||
|
||||
/** [Event] Image Viewer */
|
||||
onFileViewer(fileInfo: SelectFileInfo) {
|
||||
this.fileViewer.emit(fileInfo);
|
||||
}
|
||||
|
||||
/** [Event] Attach File Save & Save As */
|
||||
onSave(value: {
|
||||
fileInfo: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
}) {
|
||||
this.save.emit(value);
|
||||
}
|
||||
|
||||
/** [Event] Context Menu */
|
||||
onContextMenu(event: any, message: Info<EventJson>) {
|
||||
if (
|
||||
message.type === EventType.Translation ||
|
||||
message.type === EventType.MassTranslation
|
||||
) {
|
||||
this.contextMenu.emit({ event: event.event, message, type: event.type });
|
||||
} else {
|
||||
this.contextMenu.emit({ event, message });
|
||||
}
|
||||
}
|
||||
|
||||
shake() {
|
||||
this.shakeIt = false;
|
||||
this.changeDetectorRef.detectChanges();
|
||||
setTimeout(() => {
|
||||
this.shakeIt = true;
|
||||
this.changeDetectorRef.detectChanges();
|
||||
}, 1);
|
||||
}
|
||||
}
|
2158
documents/업무/2월/3째주/file-viewer-prj/messages.component copy.ts
Normal file
2158
documents/업무/2월/3째주/file-viewer-prj/messages.component copy.ts
Normal file
File diff suppressed because it is too large
Load Diff
699
documents/업무/2월/3째주/file-viewer-prj/messages.component.ts
Normal file
699
documents/업무/2월/3째주/file-viewer-prj/messages.component.ts
Normal file
|
@ -0,0 +1,699 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
EventEmitter,
|
||||
Output,
|
||||
ViewChild,
|
||||
OnDestroy,
|
||||
ChangeDetectionStrategy,
|
||||
ElementRef,
|
||||
ChangeDetectorRef,
|
||||
ViewChildren,
|
||||
QueryList
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
Info,
|
||||
EventType,
|
||||
InfoResponse,
|
||||
EventJson,
|
||||
FileEventJson,
|
||||
MassTranslationEventJson
|
||||
} from '@ucap-webmessenger/protocol-event';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { UserInfo, RoomInfo, RoomType } from '@ucap-webmessenger/protocol-room';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
||||
import moment from 'moment';
|
||||
import { FileDownloadItem } from '@ucap-webmessenger/api';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { Observable, Subscription, timer } from 'rxjs';
|
||||
import { VirtualScrollerComponent, IPageInfo } from 'ngx-virtual-scroller';
|
||||
import { MessageBoxComponent } from './message-box.component';
|
||||
import { debounce } from 'rxjs/operators';
|
||||
import { SelectFileInfo } from '@ucap-webmessenger/ui';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-chat-messages',
|
||||
templateUrl: './messages.component.html',
|
||||
styleUrls: ['./messages.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class MessagesComponent implements OnInit, OnDestroy {
|
||||
@Input()
|
||||
loginRes$: Observable<LoginResponse>;
|
||||
@Input()
|
||||
roomInfo$: Observable<RoomInfo>;
|
||||
@Input()
|
||||
eventList$: Observable<Info<EventJson>[]>;
|
||||
@Input()
|
||||
newEventList$: Observable<Info<EventJson>[]>;
|
||||
@Input()
|
||||
searchedList$: Observable<Info<EventJson>[]>;
|
||||
@Input()
|
||||
eventInfoStatus$: Observable<InfoResponse>;
|
||||
@Input()
|
||||
eventRemained$: Observable<boolean>;
|
||||
@Input()
|
||||
sessionVerInfo: VersionInfo2Response;
|
||||
@Input()
|
||||
userInfos$: Observable<UserInfo[]>;
|
||||
|
||||
@Input()
|
||||
lock$: Observable<boolean>;
|
||||
|
||||
@Input()
|
||||
isShowUnreadCount = true;
|
||||
@Input()
|
||||
clearReadHere: boolean;
|
||||
@Input()
|
||||
minShowReadHere = 10;
|
||||
@Input()
|
||||
translationSimpleview = false;
|
||||
@Input()
|
||||
searchingMode = false;
|
||||
|
||||
@Output()
|
||||
openProfile = new EventEmitter<number>();
|
||||
@Output()
|
||||
moreEvent = new EventEmitter<number>();
|
||||
@Output()
|
||||
massDetail = new EventEmitter<number>();
|
||||
@Output()
|
||||
massTranslationDetail = new EventEmitter<{
|
||||
message: Info<MassTranslationEventJson>;
|
||||
contentsType: string;
|
||||
}>();
|
||||
@Output()
|
||||
fileViewer = new EventEmitter<SelectFileInfo>();
|
||||
@Output()
|
||||
save = new EventEmitter<{
|
||||
fileInfo: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
}>();
|
||||
@Output()
|
||||
contextMenu = new EventEmitter<{
|
||||
event: MouseEvent;
|
||||
message: Info<EventJson>;
|
||||
type?: string;
|
||||
}>();
|
||||
|
||||
@Output()
|
||||
scrollUp = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
yReachEnd = new EventEmitter<any>();
|
||||
@Output()
|
||||
yReachStart = new EventEmitter<any>();
|
||||
|
||||
@Output()
|
||||
existNewMessage = new EventEmitter<Info<EventJson>>();
|
||||
|
||||
@ViewChild('chatMessagesContainer', { static: false })
|
||||
chatMessagesContainer: ElementRef<HTMLElement>;
|
||||
|
||||
@ViewChild('chatMessagesBuffer', { static: false })
|
||||
chatMessagesBuffer: ElementRef<HTMLElement>;
|
||||
|
||||
@ViewChild('chatMessagesBufferContainer', { static: false })
|
||||
chatMessagesBufferContainer: ElementRef<HTMLElement>;
|
||||
|
||||
@ViewChild(VirtualScrollerComponent, { static: false })
|
||||
private virtualScroller: VirtualScrollerComponent;
|
||||
|
||||
@ViewChildren('chatMessageBox')
|
||||
chatMessageBoxList: QueryList<MessageBoxComponent>;
|
||||
|
||||
storedScrollItem: Info<EventJson>; // 이전대화를 불러올 경우 현재 스크롤 포지션 유지를 위한 값. 0 이면 초기로딩.
|
||||
storedScrollItemOffsetTop: number | undefined;
|
||||
scrollUpInitalized = false; // ps 에서 초기 로딩시 scroll reach start 이벤트 발생 버그를 우회하기 위한 init 값으로 scrollUp 에 의해 true 로 된다.
|
||||
firstCheckReadHere = true;
|
||||
initRoomLastEventSeq: number;
|
||||
baseEventSeq = 0;
|
||||
gotoEventSeq: number;
|
||||
|
||||
loginRes: LoginResponse;
|
||||
loginResSubscription: Subscription;
|
||||
roomInfo: RoomInfo;
|
||||
roomInfoSubscription: Subscription;
|
||||
eventList: Info<EventJson>[];
|
||||
eventListSubscription: Subscription;
|
||||
newEventList: Info<EventJson>[];
|
||||
newEventListSubscription: Subscription;
|
||||
searchedList: Info<EventJson>[];
|
||||
searchedListSubscription: Subscription;
|
||||
eventInfoStatus: InfoResponse;
|
||||
eventInfoStatusSubscription: Subscription;
|
||||
eventRemained: boolean;
|
||||
eventRemainedSubscription: Subscription;
|
||||
userInfos: UserInfo[];
|
||||
userInfosSubscription: Subscription;
|
||||
|
||||
EventType = EventType;
|
||||
profileImageRoot: string;
|
||||
moment = moment;
|
||||
|
||||
readToHereEvent: Info<EventJson>;
|
||||
existReadToHereEvent = true;
|
||||
hidden = false;
|
||||
swapped = false;
|
||||
initalized = false;
|
||||
|
||||
constructor(
|
||||
private logger: NGXLogger,
|
||||
private changeDetectorRef: ChangeDetectorRef,
|
||||
private translateService: TranslateService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.profileImageRoot =
|
||||
this.profileImageRoot || this.sessionVerInfo.profileRoot;
|
||||
|
||||
this.loginResSubscription = this.loginRes$.subscribe(loginRes => {
|
||||
this.loginRes = loginRes;
|
||||
});
|
||||
this.roomInfoSubscription = this.roomInfo$.subscribe(roomInfo => {
|
||||
this.roomInfo = roomInfo;
|
||||
this.initalized = false;
|
||||
|
||||
/** [S] initializing by changed room */
|
||||
// reset :: roomLastEventSeq
|
||||
if (!!roomInfo && !!roomInfo.finalEventSeq) {
|
||||
this.initRoomLastEventSeq = roomInfo.finalEventSeq;
|
||||
}
|
||||
// clear :: readToHearEvent object
|
||||
this.readToHereEvent = undefined;
|
||||
this.existReadToHereEvent = true;
|
||||
/** [E] initializing by changed room */
|
||||
|
||||
if (!this.roomInfo || this.roomInfo.roomSeq !== roomInfo.roomSeq) {
|
||||
this.initEventMore();
|
||||
}
|
||||
});
|
||||
this.eventListSubscription = this.eventList$
|
||||
.pipe(debounce(() => timer(100)))
|
||||
.subscribe(eventList => {
|
||||
this.eventList = eventList;
|
||||
|
||||
if (!!eventList && eventList.length > 0) {
|
||||
if (!this.readToHereEvent && this.existReadToHereEvent) {
|
||||
this.readToHereEvent = this.getReadHere();
|
||||
}
|
||||
|
||||
if (
|
||||
this.baseEventSeq > 0 &&
|
||||
!!this.roomInfo &&
|
||||
!!this.roomInfo.lastReadEventSeq &&
|
||||
this.baseEventSeq <= this.roomInfo.lastReadEventSeq
|
||||
) {
|
||||
// 기존 대화 내용이 있는 상태에서 추가로 조회된 내용중에 read here 가 있을 경우.
|
||||
this.firstCheckReadHere = false;
|
||||
}
|
||||
} else {
|
||||
this.readToHereEvent = undefined;
|
||||
}
|
||||
|
||||
this.changeDetectorRef.detectChanges();
|
||||
|
||||
if (this.searchingMode) {
|
||||
const baseseq = this.baseEventSeq;
|
||||
// setTimeout(() => {
|
||||
// this.doSearchTextInEvent(this.searchText, baseseq);
|
||||
// }, 800);
|
||||
this.baseEventSeq = eventList[0].seq;
|
||||
} else {
|
||||
if (!!eventList && eventList.length > 0) {
|
||||
this.baseEventSeq = eventList[0].seq;
|
||||
this.ready();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.newEventListSubscription = this.newEventList$.subscribe(
|
||||
newEventList => {
|
||||
this.newEventList = newEventList;
|
||||
}
|
||||
);
|
||||
this.searchedListSubscription = this.searchedList$.subscribe(
|
||||
searchedList => {
|
||||
this.searchedList = searchedList;
|
||||
}
|
||||
);
|
||||
this.eventInfoStatusSubscription = this.eventInfoStatus$.subscribe(
|
||||
eventInfoStatus => {
|
||||
this.eventInfoStatus = eventInfoStatus;
|
||||
}
|
||||
);
|
||||
this.eventRemainedSubscription = this.eventRemained$.subscribe(
|
||||
eventRemained => {
|
||||
this.eventRemained = eventRemained;
|
||||
}
|
||||
);
|
||||
this.userInfosSubscription = this.userInfos$.subscribe(userInfos => {
|
||||
this.userInfos = userInfos;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.loginResSubscription) {
|
||||
this.loginResSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.roomInfoSubscription) {
|
||||
this.roomInfoSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.eventListSubscription) {
|
||||
this.eventListSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.newEventListSubscription) {
|
||||
this.newEventListSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.searchedListSubscription) {
|
||||
this.searchedListSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.eventInfoStatusSubscription) {
|
||||
this.eventInfoStatusSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.eventRemainedSubscription) {
|
||||
this.eventRemainedSubscription.unsubscribe();
|
||||
}
|
||||
if (!!this.userInfosSubscription) {
|
||||
this.userInfosSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* UserInfo getter
|
||||
*/
|
||||
getUserName(seq: number): string {
|
||||
if (!this.userInfos) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const userInfo: UserInfo[] = this.userInfos.filter(
|
||||
user => user.seq === seq
|
||||
);
|
||||
if (!!userInfo && userInfo.length > 0) {
|
||||
return userInfo[0].name;
|
||||
}
|
||||
return '(알수없는 사용자)';
|
||||
}
|
||||
getUserProfile(seq: number): string {
|
||||
if (!this.userInfos) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const userInfo: UserInfo[] = this.userInfos.filter(
|
||||
user => user.seq === seq
|
||||
);
|
||||
if (!!userInfo && userInfo.length > 0) {
|
||||
return userInfo[0].profileImageFile;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
isHighlightedEvent(seq: number): boolean {
|
||||
return (
|
||||
!!this.searchedList &&
|
||||
this.searchedList.filter(event => event.seq === seq).length > 0
|
||||
);
|
||||
}
|
||||
|
||||
getUnreadCount(message: Info<EventJson>): string | number {
|
||||
// if (!this.userInfos || 0 === this.userInfos.length) {
|
||||
// return '';
|
||||
// }
|
||||
const unreadCnt = this.userInfos
|
||||
.filter(user => user.isJoinRoom && user.seq !== message.senderSeq)
|
||||
.filter(user => user.lastReadEventSeq < message.seq).length;
|
||||
return unreadCnt === 0 ? '' : unreadCnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 정보성 Event 인지 판단.
|
||||
* @description 정보성 event 일 경우 프로필, 일시 를 표현하지 않는다.
|
||||
* Edit with reducers.ts / sync / updateRoomForNewEventMessage
|
||||
*/
|
||||
getIsInformation(info: Info<EventJson>) {
|
||||
if (
|
||||
info.type === EventType.Join ||
|
||||
info.type === EventType.Exit ||
|
||||
info.type === EventType.ForcedExit ||
|
||||
info.type === EventType.RenameRoom ||
|
||||
info.type === EventType.NotificationForTimerRoom ||
|
||||
info.type === EventType.GuideForRoomTimerChanged
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Date Splitter show check */
|
||||
getDateSplitter(message: Info<EventJson>): boolean {
|
||||
const curIndex = this.eventList.findIndex(v => v.seq === message.seq);
|
||||
|
||||
if (curIndex === 0) {
|
||||
return true;
|
||||
}
|
||||
if (curIndex > 0) {
|
||||
if (!this.eventList[curIndex]) {
|
||||
return false;
|
||||
}
|
||||
return !moment(this.eventList[curIndex].sendDate).isSame(
|
||||
moment(this.eventList[curIndex - 1].sendDate),
|
||||
'day'
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getReadHere(): Info<EventJson> | undefined {
|
||||
if (
|
||||
!!this.roomInfo &&
|
||||
!!this.roomInfo.lastReadEventSeq &&
|
||||
this.initRoomLastEventSeq - this.roomInfo.lastReadEventSeq >
|
||||
this.minShowReadHere
|
||||
) {
|
||||
if (
|
||||
this.roomInfo.roomType === RoomType.Single ||
|
||||
this.roomInfo.roomType === RoomType.Multi
|
||||
) {
|
||||
if (!this.roomInfo.isTimeRoom) {
|
||||
return this.eventList.find(
|
||||
v => v.seq === this.roomInfo.lastReadEventSeq + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.existReadToHereEvent = false;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getStringReadHereMore(): string {
|
||||
let rtnStr = '';
|
||||
rtnStr = this.translateService.instant('chat.event.moreUnreadEventsWith', {
|
||||
countOfUnread: this.baseEventSeq - (this.roomInfo.lastReadEventSeq + 1)
|
||||
});
|
||||
return rtnStr;
|
||||
}
|
||||
|
||||
storeScrollPosition() {
|
||||
this.storedScrollItem = this.eventList[
|
||||
this.virtualScroller.viewPortInfo.startIndex
|
||||
];
|
||||
|
||||
const chatMessageBox = this.chatMessageBoxList.find(
|
||||
el =>
|
||||
el.message.seq ===
|
||||
this.eventList[this.virtualScroller.viewPortInfo.startIndex].seq
|
||||
);
|
||||
if (!!chatMessageBox) {
|
||||
this.storedScrollItemOffsetTop =
|
||||
chatMessageBox.offsetTop -
|
||||
this.virtualScroller.viewPortInfo.scrollStartPosition;
|
||||
} else {
|
||||
this.storedScrollItemOffsetTop = 0;
|
||||
}
|
||||
}
|
||||
|
||||
swapScrollTo(
|
||||
to: Info<EventJson>,
|
||||
preCallback: () => void,
|
||||
postCallback: () => void,
|
||||
useHide: boolean,
|
||||
useSwap: boolean,
|
||||
addtionalOffset?: number
|
||||
) {
|
||||
this.preSwapScroll(useHide, useSwap);
|
||||
if (!!preCallback) {
|
||||
preCallback();
|
||||
}
|
||||
|
||||
this.virtualScroller.scrollInto(
|
||||
to,
|
||||
true,
|
||||
undefined !== this.storedScrollItemOffsetTop
|
||||
? -this.storedScrollItemOffsetTop
|
||||
: undefined !== addtionalOffset
|
||||
? -addtionalOffset
|
||||
: 0,
|
||||
0,
|
||||
() => {
|
||||
setTimeout(() => {
|
||||
if (!!postCallback) {
|
||||
postCallback();
|
||||
}
|
||||
this.postSwapScroll(useHide, useSwap);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
preSwapScroll(useHide: boolean, useSwap: boolean) {
|
||||
if (useSwap && !this.swapped) {
|
||||
this.chatMessagesBuffer.nativeElement.innerHTML = this.chatMessagesContainer.nativeElement.innerHTML;
|
||||
this.chatMessagesBuffer.nativeElement.scrollTop = this.chatMessagesContainer.nativeElement.scrollTop;
|
||||
this.chatMessagesBufferContainer.nativeElement.classList.remove(
|
||||
'disappear'
|
||||
);
|
||||
this.swapped = true;
|
||||
}
|
||||
|
||||
if (useHide && !this.hidden) {
|
||||
this.chatMessagesContainer.nativeElement.classList.add('hide');
|
||||
this.hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
postSwapScroll(useHide: boolean, useSwap: boolean) {
|
||||
if (useSwap && this.swapped) {
|
||||
this.chatMessagesBuffer.nativeElement.innerHTML = '';
|
||||
this.chatMessagesBuffer.nativeElement.scrollTop = 0;
|
||||
this.chatMessagesBufferContainer.nativeElement.classList.add('disappear');
|
||||
this.swapped = false;
|
||||
}
|
||||
|
||||
if (useHide && this.hidden) {
|
||||
this.chatMessagesContainer.nativeElement.classList.remove('hide');
|
||||
this.hidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
ready(): void {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
scrollToBottom(): void {
|
||||
if (!!this.storedScrollItem) {
|
||||
if (!!this.readToHereEvent && this.firstCheckReadHere) {
|
||||
this.swapScrollTo(
|
||||
this.readToHereEvent,
|
||||
() => {},
|
||||
() => {
|
||||
this.firstCheckReadHere = false;
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
this.swapScrollTo(
|
||||
this.storedScrollItem,
|
||||
() => {},
|
||||
() => {
|
||||
this.storedScrollItem = undefined;
|
||||
this.storedScrollItemOffsetTop = undefined;
|
||||
},
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
} else if (this.scrollUpInitalized) {
|
||||
if (!!this.newEventList && this.newEventList.length > 0) {
|
||||
this.existNewMessage.emit(
|
||||
this.newEventList[this.newEventList.length - 1]
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (!!this.readToHereEvent && this.firstCheckReadHere) {
|
||||
this.swapScrollTo(
|
||||
this.readToHereEvent,
|
||||
() => {},
|
||||
() => {
|
||||
this.firstCheckReadHere = false;
|
||||
},
|
||||
false,
|
||||
false
|
||||
);
|
||||
} else {
|
||||
if (!this.eventList || 0 === this.eventList.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!!this.gotoEventSeq) {
|
||||
this.gotoPosition(this.gotoEventSeq);
|
||||
this.gotoEventSeq = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
const lastEvent =
|
||||
!!this.eventList && 0 < this.eventList.length
|
||||
? this.eventList[this.eventList.length - 1]
|
||||
: undefined;
|
||||
|
||||
if (undefined === lastEvent) {
|
||||
return;
|
||||
}
|
||||
const isInViewPortItems = this.isInViewPortItems(lastEvent.seq);
|
||||
this.swapScrollTo(
|
||||
this.eventList[this.eventList.length - 1],
|
||||
() => {},
|
||||
() => {
|
||||
this.initalized = true;
|
||||
},
|
||||
-1 === this.virtualScroller.viewPortInfo.endIndex ||
|
||||
!isInViewPortItems,
|
||||
!isInViewPortItems
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initEventMore(gotoEventSeq?: number) {
|
||||
// 방정보가 바뀌면 이전대화 보기 관련 값들을 초기화 한다.
|
||||
this.scrollUpInitalized = false;
|
||||
this.storedScrollItem = undefined;
|
||||
this.storedScrollItemOffsetTop = undefined;
|
||||
this.gotoEventSeq = gotoEventSeq;
|
||||
}
|
||||
|
||||
clear() {}
|
||||
|
||||
gotoPosition(eventSeq: number) {
|
||||
const isInViewPortItems = this.isInViewPortItems(eventSeq);
|
||||
|
||||
if (!!this.virtualScroller) {
|
||||
const e = this.eventList.find(v => v.seq === eventSeq);
|
||||
this.swapScrollTo(
|
||||
e,
|
||||
() => {},
|
||||
() => {
|
||||
const chatMessageBox = this.chatMessageBoxList.find(
|
||||
el => el.message.seq === eventSeq
|
||||
);
|
||||
if (!!chatMessageBox) {
|
||||
chatMessageBox.shake();
|
||||
}
|
||||
},
|
||||
!isInViewPortItems,
|
||||
!isInViewPortItems,
|
||||
50
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
isInViewPortItems(eventSeq: number): boolean {
|
||||
if (undefined === eventSeq) {
|
||||
return false;
|
||||
}
|
||||
const viewPortItemIndex = this.virtualScroller.viewPortItems.findIndex(
|
||||
v => v.seq === eventSeq
|
||||
);
|
||||
|
||||
const newEvent =
|
||||
!!this.newEventList &&
|
||||
-1 !== this.newEventList.findIndex(e => e.seq === eventSeq);
|
||||
|
||||
return -1 !== viewPortItemIndex || newEvent;
|
||||
}
|
||||
|
||||
onClickOpenProfile(userSeq: number) {
|
||||
this.openProfile.emit(userSeq);
|
||||
}
|
||||
|
||||
onClickMore(event: any) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (this.scrollUpInitalized && this.eventRemained) {
|
||||
this.virtualScroller.scrollToPosition(0);
|
||||
this.virtualScroller.invalidateCachedMeasurementAtIndex(0);
|
||||
|
||||
this.storeScrollPosition();
|
||||
|
||||
this.preSwapScroll(true, true);
|
||||
|
||||
this.moreEvent.emit(this.eventList[0].seq);
|
||||
}
|
||||
}
|
||||
|
||||
/** [Event] MassTalk Detail View */
|
||||
onMassDetail(value: number) {
|
||||
this.massDetail.emit(value);
|
||||
}
|
||||
|
||||
onMassTranslationDetail(params: {
|
||||
message: Info<MassTranslationEventJson>;
|
||||
contentsType: string;
|
||||
}) {
|
||||
this.massTranslationDetail.emit(params);
|
||||
}
|
||||
|
||||
/** [Event] Image Viewer */
|
||||
onFileViewer(fileInfo: SelectFileInfo) {
|
||||
this.fileViewer.emit(fileInfo);
|
||||
}
|
||||
|
||||
/** [Event] Attach File Save & Save As */
|
||||
onSave(value: {
|
||||
fileInfo: FileEventJson;
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
type: string;
|
||||
}) {
|
||||
this.save.emit(value);
|
||||
}
|
||||
|
||||
/** [Event] Context Menu */
|
||||
onContextMenu(event: {
|
||||
event: MouseEvent;
|
||||
message: Info<EventJson>;
|
||||
type?: string;
|
||||
}) {
|
||||
this.contextMenu.emit(event);
|
||||
}
|
||||
|
||||
onScrollup(event: any) {
|
||||
if (!this.eventList || 0 === this.eventList.length) {
|
||||
return;
|
||||
}
|
||||
this.scrollUpInitalized = true;
|
||||
this.scrollUp.emit(event);
|
||||
}
|
||||
onYReachStart(event: any) {
|
||||
this.yReachStart.emit(event);
|
||||
}
|
||||
onYReachEnd(event: any) {
|
||||
this.yReachEnd.emit(event);
|
||||
}
|
||||
|
||||
onVsChange(event: IPageInfo) {
|
||||
if (
|
||||
-1 === event.startIndex ||
|
||||
-1 === event.endIndex ||
|
||||
(0 === event.startIndex && 0 === event.endIndex)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// this.logger.debug('onVsChange', event);
|
||||
}
|
||||
|
||||
trackByEvent(index: number, info: Info<EventJson>): number {
|
||||
return info.seq;
|
||||
}
|
||||
|
||||
compareItemsFunc = (
|
||||
item1: Info<EventJson>,
|
||||
item2: Info<EventJson>
|
||||
// tslint:disable-next-line: semicolon
|
||||
): boolean => !!item1 && !!item2 && item1.seq === item2.seq;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export interface SelectFileInfo {
|
||||
attachmentSeq: number;
|
||||
index?: number;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export interface SelectFileInfo {
|
||||
attachmentSeq: number;
|
||||
index?: number;
|
||||
}
|
34
documents/업무/2월/3째주/file-viewer-prj/plan.event-json.ts
Normal file
34
documents/업무/2월/3째주/file-viewer-prj/plan.event-json.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { EventJsonDecoder } from './event-json';
|
||||
import { JsonAnalization } from '@ucap-webmessenger/api';
|
||||
|
||||
export interface PlanEventJson {
|
||||
planSeq?: number;
|
||||
title?: string;
|
||||
contents?: PlanContentType | string;
|
||||
date?: string;
|
||||
endDate?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
export enum PlanContentType {
|
||||
New = 'PLAN_CONTENTS_NEW',
|
||||
Update = 'PLAN_CONTENTS_UPDATE',
|
||||
Delete = 'PLAN_CONTENTS_DELETE'
|
||||
}
|
||||
|
||||
export const decodePlanEventJson: EventJsonDecoder<PlanEventJson> = (
|
||||
message: string
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(message);
|
||||
return {
|
||||
planSeq: Number(json.planSeq),
|
||||
title: json.title,
|
||||
contents: json.contents,
|
||||
date: json.date,
|
||||
endDate: json.endDate,
|
||||
active: !!json.activeYn && 'Y' === json.activeYn ? true : false
|
||||
} as PlanEventJson;
|
||||
} catch (e) {
|
||||
return {} as PlanEventJson;
|
||||
}
|
||||
};
|
49
documents/업무/2월/3째주/file-viewer-prj/public-api copy.ts
Normal file
49
documents/업무/2월/3째주/file-viewer-prj/public-api copy.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Public API Surface of ucap-webmessenger-ui
|
||||
*/
|
||||
|
||||
export * from './lib/animations/index';
|
||||
|
||||
export * from './lib/components/file-viewer/document-viewer.component';
|
||||
export * from './lib/components/file-viewer/image-viewer.component';
|
||||
export * from './lib/components/file-viewer/sound-viewer.component';
|
||||
export * from './lib/components/file-viewer/video-viewer.component';
|
||||
|
||||
export * from './lib/components/expansion-panel.component';
|
||||
export * from './lib/components/file-upload-queue.component';
|
||||
export * from './lib/components/file-viewer.component';
|
||||
export * from './lib/components/float-action-button.component';
|
||||
export * from './lib/components/pick-date.component';
|
||||
export * from './lib/components/pick-time.component';
|
||||
export * from './lib/components/step-input.component';
|
||||
export * from './lib/components/split-button.component';
|
||||
export * from './lib/components/sticker-selector.component';
|
||||
export * from './lib/components/inline-edit-input.component';
|
||||
|
||||
export * from './lib/data-source/virtual-scroll-tree-flat.data-source';
|
||||
|
||||
export * from './lib/dialogs/alert.dialog.component';
|
||||
export * from './lib/dialogs/confirm.dialog.component';
|
||||
|
||||
export * from './lib/directives/click-outside.directive';
|
||||
export * from './lib/directives/file-upload-for.directive';
|
||||
export * from './lib/directives/image.directive';
|
||||
|
||||
export * from './lib/services/bottom-sheet.service';
|
||||
export * from './lib/services/clipboard.service';
|
||||
export * from './lib/services/dialog.service';
|
||||
export * from './lib/services/snack-bar.service';
|
||||
export * from './lib/services/splash-screen.service';
|
||||
export * from './lib/services/translate.service';
|
||||
export * from './lib/services/date.service';
|
||||
export * from './lib/services/paginator-intl.service';
|
||||
|
||||
export * from './lib/snackbars/alert.snackbar.component';
|
||||
|
||||
export * from './lib/types/file-viewer.type';
|
||||
|
||||
export * from './lib/models/select-file-info';
|
||||
|
||||
export * from './lib/utils/string.util';
|
||||
|
||||
export * from './lib/ucap-ui.module';
|
49
documents/업무/2월/3째주/file-viewer-prj/public-api.ts
Normal file
49
documents/업무/2월/3째주/file-viewer-prj/public-api.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Public API Surface of ucap-webmessenger-ui
|
||||
*/
|
||||
|
||||
export * from './lib/animations/index';
|
||||
|
||||
export * from './lib/components/file-viewer/document-viewer.component';
|
||||
export * from './lib/components/file-viewer/image-viewer.component';
|
||||
export * from './lib/components/file-viewer/sound-viewer.component';
|
||||
export * from './lib/components/file-viewer/video-viewer.component';
|
||||
|
||||
export * from './lib/components/expansion-panel.component';
|
||||
export * from './lib/components/file-upload-queue.component';
|
||||
export * from './lib/components/file-viewer.component';
|
||||
export * from './lib/components/float-action-button.component';
|
||||
export * from './lib/components/pick-date.component';
|
||||
export * from './lib/components/pick-time.component';
|
||||
export * from './lib/components/step-input.component';
|
||||
export * from './lib/components/split-button.component';
|
||||
export * from './lib/components/sticker-selector.component';
|
||||
export * from './lib/components/inline-edit-input.component';
|
||||
|
||||
export * from './lib/data-source/virtual-scroll-tree-flat.data-source';
|
||||
|
||||
export * from './lib/dialogs/alert.dialog.component';
|
||||
export * from './lib/dialogs/confirm.dialog.component';
|
||||
|
||||
export * from './lib/directives/click-outside.directive';
|
||||
export * from './lib/directives/file-upload-for.directive';
|
||||
export * from './lib/directives/image.directive';
|
||||
|
||||
export * from './lib/services/bottom-sheet.service';
|
||||
export * from './lib/services/clipboard.service';
|
||||
export * from './lib/services/dialog.service';
|
||||
export * from './lib/services/snack-bar.service';
|
||||
export * from './lib/services/splash-screen.service';
|
||||
export * from './lib/services/translate.service';
|
||||
export * from './lib/services/date.service';
|
||||
export * from './lib/services/paginator-intl.service';
|
||||
|
||||
export * from './lib/snackbars/alert.snackbar.component';
|
||||
|
||||
export * from './lib/types/file-viewer.type';
|
||||
|
||||
export * from './lib/models/select-file-info';
|
||||
|
||||
export * from './lib/utils/string.util';
|
||||
|
||||
export * from './lib/ucap-ui.module';
|
185
documents/업무/2월/3째주/file-viewer-prj/ucap-ui.module copy.ts
Normal file
185
documents/업무/2월/3째주/file-viewer-prj/ucap-ui.module copy.ts
Normal file
|
@ -0,0 +1,185 @@
|
|||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatSliderModule } from '@angular/material/slider';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import {
|
||||
MatTabsModule,
|
||||
MatSelectModule,
|
||||
MatSlideToggleModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule
|
||||
} from '@angular/material';
|
||||
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { FileUploadQueueComponent } from './components/file-upload-queue.component';
|
||||
import { FloatActionButtonComponent } from './components/float-action-button.component';
|
||||
import { FileViewerComponent } from './components/file-viewer.component';
|
||||
import { MediaViewerComponent } from './components/media-viewer.component';
|
||||
import { ExpansionPanelComponent } from './components/expansion-panel.component';
|
||||
import { SplitButtonComponent } from './components/split-button.component';
|
||||
import { PickDateComponent } from './components/pick-date.component';
|
||||
import { PickTimeComponent } from './components/pick-time.component';
|
||||
import { StepInputComponent } from './components/step-input.component';
|
||||
import { StickerSelectorComponent } from './components/sticker-selector.component';
|
||||
import { InlineEditInputComponent } from './components/inline-edit-input.component';
|
||||
|
||||
import { BinaryViewerComponent } from './components/file-viewer/binary-viewer.component';
|
||||
import { DocumentViewerComponent } from './components/file-viewer/document-viewer.component';
|
||||
import { ImageViewerComponent } from './components/file-viewer/image-viewer.component';
|
||||
import { SoundViewerComponent } from './components/file-viewer/sound-viewer.component';
|
||||
import { VideoViewerComponent } from './components/file-viewer/video-viewer.component';
|
||||
|
||||
import { BottomSheetService } from './services/bottom-sheet.service';
|
||||
import { ClipboardService } from './services/clipboard.service';
|
||||
import { DialogService } from './services/dialog.service';
|
||||
import { SnackBarService } from './services/snack-bar.service';
|
||||
import { SplashScreenService } from './services/splash-screen.service';
|
||||
import { TranslateService } from './services/translate.service';
|
||||
import { DateService } from './services/date.service';
|
||||
import { PaginatorIntlService } from './services/paginator-intl.service';
|
||||
|
||||
import { ClickOutsideDirective } from './directives/click-outside.directive';
|
||||
import { FileUploadForDirective } from './directives/file-upload-for.directive';
|
||||
import { ImageDirective } from './directives/image.directive';
|
||||
import { CdkVirtualScrollViewportPatchDirective } from './directives/cdk-virtual-scroll-viewport-patch.directive';
|
||||
|
||||
import { AlertDialogComponent } from './dialogs/alert.dialog.component';
|
||||
import { ConfirmDialogComponent } from './dialogs/confirm.dialog.component';
|
||||
|
||||
import { BytesPipe } from './pipes/bytes.pipe';
|
||||
import { LinefeedToHtmlPipe, HtmlToLinefeedPipe } from './pipes/linefeed.pipe';
|
||||
import { SecondsToMinutesPipe } from './pipes/seconds-to-minutes.pipe';
|
||||
import { LinkyPipe } from './pipes/linky.pipe';
|
||||
import { TranslatePipe } from './pipes/translate.pipe';
|
||||
import { DatePipe } from './pipes/date.pipe';
|
||||
import { SafeHtmlPipe } from './pipes/safe-html.pipe';
|
||||
|
||||
import {
|
||||
StringEmptyCheckPipe,
|
||||
StringFormatterPhonePipe
|
||||
} from './pipes/string.pipe';
|
||||
import { ClickDebounceDirective } from './directives/click-debounce.directive';
|
||||
import { TranslationSectionComponent } from './components/translation-section.component';
|
||||
import { AlertSnackbarComponent } from './snackbars/alert.snackbar.component';
|
||||
import { IntegratedSearchFormComponent } from './components/integrated-search-form.component';
|
||||
import { IntegratedSearchComponent } from './components/integrated-search.component';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
|
||||
const COMPONENTS = [
|
||||
FileUploadQueueComponent,
|
||||
FloatActionButtonComponent,
|
||||
FileViewerComponent,
|
||||
ExpansionPanelComponent,
|
||||
StickerSelectorComponent,
|
||||
SplitButtonComponent,
|
||||
PickDateComponent,
|
||||
PickTimeComponent,
|
||||
StepInputComponent,
|
||||
TranslationSectionComponent,
|
||||
InlineEditInputComponent,
|
||||
IntegratedSearchComponent,
|
||||
IntegratedSearchFormComponent,
|
||||
|
||||
BinaryViewerComponent,
|
||||
DocumentViewerComponent,
|
||||
ImageViewerComponent,
|
||||
SoundViewerComponent,
|
||||
VideoViewerComponent,
|
||||
MediaViewerComponent
|
||||
];
|
||||
const DIALOGS = [
|
||||
AlertDialogComponent,
|
||||
ConfirmDialogComponent,
|
||||
AlertSnackbarComponent
|
||||
];
|
||||
const DIRECTIVES = [
|
||||
ClickOutsideDirective,
|
||||
FileUploadForDirective,
|
||||
ImageDirective,
|
||||
CdkVirtualScrollViewportPatchDirective,
|
||||
ClickDebounceDirective
|
||||
];
|
||||
const PIPES = [
|
||||
BytesPipe,
|
||||
LinefeedToHtmlPipe,
|
||||
HtmlToLinefeedPipe,
|
||||
SecondsToMinutesPipe,
|
||||
LinkyPipe,
|
||||
TranslatePipe,
|
||||
DatePipe,
|
||||
StringEmptyCheckPipe,
|
||||
StringFormatterPhonePipe,
|
||||
SafeHtmlPipe
|
||||
];
|
||||
const SERVICES = [
|
||||
BottomSheetService,
|
||||
ClipboardService,
|
||||
DialogService,
|
||||
SnackBarService,
|
||||
SplashScreenService,
|
||||
TranslateService,
|
||||
DateService,
|
||||
PaginatorIntlService
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
FlexLayoutModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
MatDialogModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatProgressBarModule,
|
||||
MatSliderModule,
|
||||
MatSnackBarModule,
|
||||
MatToolbarModule,
|
||||
MatTooltipModule,
|
||||
MatTabsModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonToggleModule,
|
||||
MatMenuModule,
|
||||
MatDatepickerModule,
|
||||
MatSelectModule,
|
||||
MatSlideToggleModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
|
||||
PerfectScrollbarModule,
|
||||
DragDropModule,
|
||||
TranslateModule
|
||||
],
|
||||
exports: [...COMPONENTS, ...DIRECTIVES, ...PIPES],
|
||||
declarations: [...COMPONENTS, ...DIALOGS, ...DIRECTIVES, ...PIPES],
|
||||
entryComponents: [...DIALOGS]
|
||||
})
|
||||
export class UCapUiModule {
|
||||
public static forRoot(): ModuleWithProviders<UCapUiModule> {
|
||||
return {
|
||||
ngModule: UCapUiModule,
|
||||
providers: [...SERVICES]
|
||||
};
|
||||
}
|
||||
}
|
185
documents/업무/2월/3째주/file-viewer-prj/ucap-ui.module.ts
Normal file
185
documents/업무/2월/3째주/file-viewer-prj/ucap-ui.module.ts
Normal file
|
@ -0,0 +1,185 @@
|
|||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { NgModule, ModuleWithProviders } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatSliderModule } from '@angular/material/slider';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatToolbarModule } from '@angular/material/toolbar';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatButtonToggleModule } from '@angular/material/button-toggle';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import {
|
||||
MatTabsModule,
|
||||
MatSelectModule,
|
||||
MatSlideToggleModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule
|
||||
} from '@angular/material';
|
||||
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
import { FileUploadQueueComponent } from './components/file-upload-queue.component';
|
||||
import { FloatActionButtonComponent } from './components/float-action-button.component';
|
||||
import { FileViewerComponent } from './components/file-viewer.component';
|
||||
import { MediaViewerComponent } from './components/media-viewer.component';
|
||||
import { ExpansionPanelComponent } from './components/expansion-panel.component';
|
||||
import { SplitButtonComponent } from './components/split-button.component';
|
||||
import { PickDateComponent } from './components/pick-date.component';
|
||||
import { PickTimeComponent } from './components/pick-time.component';
|
||||
import { StepInputComponent } from './components/step-input.component';
|
||||
import { StickerSelectorComponent } from './components/sticker-selector.component';
|
||||
import { InlineEditInputComponent } from './components/inline-edit-input.component';
|
||||
|
||||
import { BinaryViewerComponent } from './components/file-viewer/binary-viewer.component';
|
||||
import { DocumentViewerComponent } from './components/file-viewer/document-viewer.component';
|
||||
import { ImageViewerComponent } from './components/file-viewer/image-viewer.component';
|
||||
import { SoundViewerComponent } from './components/file-viewer/sound-viewer.component';
|
||||
import { VideoViewerComponent } from './components/file-viewer/video-viewer.component';
|
||||
|
||||
import { BottomSheetService } from './services/bottom-sheet.service';
|
||||
import { ClipboardService } from './services/clipboard.service';
|
||||
import { DialogService } from './services/dialog.service';
|
||||
import { SnackBarService } from './services/snack-bar.service';
|
||||
import { SplashScreenService } from './services/splash-screen.service';
|
||||
import { TranslateService } from './services/translate.service';
|
||||
import { DateService } from './services/date.service';
|
||||
import { PaginatorIntlService } from './services/paginator-intl.service';
|
||||
|
||||
import { ClickOutsideDirective } from './directives/click-outside.directive';
|
||||
import { FileUploadForDirective } from './directives/file-upload-for.directive';
|
||||
import { ImageDirective } from './directives/image.directive';
|
||||
import { CdkVirtualScrollViewportPatchDirective } from './directives/cdk-virtual-scroll-viewport-patch.directive';
|
||||
|
||||
import { AlertDialogComponent } from './dialogs/alert.dialog.component';
|
||||
import { ConfirmDialogComponent } from './dialogs/confirm.dialog.component';
|
||||
|
||||
import { BytesPipe } from './pipes/bytes.pipe';
|
||||
import { LinefeedToHtmlPipe, HtmlToLinefeedPipe } from './pipes/linefeed.pipe';
|
||||
import { SecondsToMinutesPipe } from './pipes/seconds-to-minutes.pipe';
|
||||
import { LinkyPipe } from './pipes/linky.pipe';
|
||||
import { TranslatePipe } from './pipes/translate.pipe';
|
||||
import { DatePipe } from './pipes/date.pipe';
|
||||
import { SafeHtmlPipe } from './pipes/safe-html.pipe';
|
||||
|
||||
import {
|
||||
StringEmptyCheckPipe,
|
||||
StringFormatterPhonePipe
|
||||
} from './pipes/string.pipe';
|
||||
import { ClickDebounceDirective } from './directives/click-debounce.directive';
|
||||
import { TranslationSectionComponent } from './components/translation-section.component';
|
||||
import { AlertSnackbarComponent } from './snackbars/alert.snackbar.component';
|
||||
import { IntegratedSearchFormComponent } from './components/integrated-search-form.component';
|
||||
import { IntegratedSearchComponent } from './components/integrated-search.component';
|
||||
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
|
||||
|
||||
const COMPONENTS = [
|
||||
FileUploadQueueComponent,
|
||||
FloatActionButtonComponent,
|
||||
FileViewerComponent,
|
||||
ExpansionPanelComponent,
|
||||
StickerSelectorComponent,
|
||||
SplitButtonComponent,
|
||||
PickDateComponent,
|
||||
PickTimeComponent,
|
||||
StepInputComponent,
|
||||
TranslationSectionComponent,
|
||||
InlineEditInputComponent,
|
||||
IntegratedSearchComponent,
|
||||
IntegratedSearchFormComponent,
|
||||
|
||||
BinaryViewerComponent,
|
||||
DocumentViewerComponent,
|
||||
ImageViewerComponent,
|
||||
SoundViewerComponent,
|
||||
VideoViewerComponent,
|
||||
MediaViewerComponent
|
||||
];
|
||||
const DIALOGS = [
|
||||
AlertDialogComponent,
|
||||
ConfirmDialogComponent,
|
||||
AlertSnackbarComponent
|
||||
];
|
||||
const DIRECTIVES = [
|
||||
ClickOutsideDirective,
|
||||
FileUploadForDirective,
|
||||
ImageDirective,
|
||||
CdkVirtualScrollViewportPatchDirective,
|
||||
ClickDebounceDirective
|
||||
];
|
||||
const PIPES = [
|
||||
BytesPipe,
|
||||
LinefeedToHtmlPipe,
|
||||
HtmlToLinefeedPipe,
|
||||
SecondsToMinutesPipe,
|
||||
LinkyPipe,
|
||||
TranslatePipe,
|
||||
DatePipe,
|
||||
StringEmptyCheckPipe,
|
||||
StringFormatterPhonePipe,
|
||||
SafeHtmlPipe
|
||||
];
|
||||
const SERVICES = [
|
||||
BottomSheetService,
|
||||
ClipboardService,
|
||||
DialogService,
|
||||
SnackBarService,
|
||||
SplashScreenService,
|
||||
TranslateService,
|
||||
DateService,
|
||||
PaginatorIntlService
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
FlexLayoutModule,
|
||||
MatButtonModule,
|
||||
MatCardModule,
|
||||
MatDialogModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatProgressBarModule,
|
||||
MatSliderModule,
|
||||
MatSnackBarModule,
|
||||
MatToolbarModule,
|
||||
MatTooltipModule,
|
||||
MatTabsModule,
|
||||
MatFormFieldModule,
|
||||
MatButtonToggleModule,
|
||||
MatMenuModule,
|
||||
MatDatepickerModule,
|
||||
MatSelectModule,
|
||||
MatSlideToggleModule,
|
||||
MatTableModule,
|
||||
MatPaginatorModule,
|
||||
|
||||
PerfectScrollbarModule,
|
||||
DragDropModule,
|
||||
TranslateModule
|
||||
],
|
||||
exports: [...COMPONENTS, ...DIRECTIVES, ...PIPES],
|
||||
declarations: [...COMPONENTS, ...DIALOGS, ...DIRECTIVES, ...PIPES],
|
||||
entryComponents: [...DIALOGS]
|
||||
})
|
||||
export class UCapUiModule {
|
||||
public static forRoot(): ModuleWithProviders<UCapUiModule> {
|
||||
return {
|
||||
ngModule: UCapUiModule,
|
||||
providers: [...SERVICES]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import { EventJsonDecoder } from './event-json';
|
||||
import { JsonAnalization } from '@ucap-webmessenger/api';
|
||||
import { VideoConferenceContentsType } from '@ucap-webmessenger/protocol-event';
|
||||
|
||||
export interface VideoConferenceEventJson {
|
||||
conferenceSeq?: number;
|
||||
title?: string;
|
||||
contents?: VideoConferenceContentsType;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
register?: string;
|
||||
attendee?: string;
|
||||
}
|
||||
|
||||
export const decodeVideoConferenceEventJson: EventJsonDecoder<VideoConferenceEventJson> = (
|
||||
message: string
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(message);
|
||||
|
||||
return {
|
||||
conferenceSeq: Number(json.confSeq),
|
||||
title: json.title,
|
||||
contents: json.contents,
|
||||
startDate: json.startDate,
|
||||
endDate: json.endDate,
|
||||
register: json.register,
|
||||
attendee: json.attendee
|
||||
} as VideoConferenceEventJson;
|
||||
} catch (e) {
|
||||
return {} as VideoConferenceEventJson;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue
Block a user