2월째주 업무
This commit is contained in:
parent
2db0103c0a
commit
8630261f42
|
@ -1,5 +1,5 @@
|
|||
묶음파일
|
||||
업로드
|
||||
업로드 (부분 완료)
|
||||
묶음파일 request 모델 정의
|
||||
userSeq: number;
|
||||
deviceType: DeviceType;
|
||||
|
@ -24,6 +24,12 @@
|
|||
이벤트 타입별 출력
|
||||
묶음파일 타입 그리드 썸네일 컴포넌트 정의
|
||||
그리드 알고리즘 작성
|
||||
썸네일 출력(완료)
|
||||
출력 가이드 라인
|
||||
최대 가로 출력 개수 3개
|
||||
다음행에 출력 개수가 홀수 일때
|
||||
빈 공간이 출력되지 않게 조정
|
||||
최대 width, 최소 height 테스트 후 결정
|
||||
앨범함
|
||||
묶음파일 타입 처리
|
||||
뷰어 컴포넌트 (슬라이드 기능) (진행)
|
||||
|
@ -33,13 +39,6 @@
|
|||
일반 이미지 출력
|
||||
동영상인 경우
|
||||
일반 동영상 썸네일 출력
|
||||
썸네일 출력
|
||||
출력 가이드 라인
|
||||
최대 가로 출력 개수 3개
|
||||
다음행에 출력 개수가 홀수 일때
|
||||
빈 공간이 출력되지 않게 조정
|
||||
최대 width, 최소 height 테스트 후 결정
|
||||
|
||||
카톡 벤치마킹
|
||||
묶음파일 전송 후
|
||||
1개의 이미지 전송
|
||||
|
@ -47,6 +46,7 @@
|
|||
동영상 전송
|
||||
동영상 썸네일 출력
|
||||
동영상은 묶음파일 지원안함
|
||||
묶음파일 기획은 카톡과 동일하게 진행
|
||||
|
||||
원본 출력
|
||||
//원본 파일 호출할 때 리플레이스
|
||||
|
@ -93,22 +93,52 @@
|
|||
기능 목록
|
||||
모바일 주소록 동기화
|
||||
기존방식 (데이터가 많은 경우 중간 서버에서 끊길 가능성이 농후)
|
||||
PC 서버 요청
|
||||
모바일 노티
|
||||
for
|
||||
모바일 주소록 서버 전송
|
||||
모바일 주소록 서버 응답
|
||||
서버가 주소록 리시브 노티
|
||||
1. PC -> Server
|
||||
모바일 주소록 동기화 시작
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ
|
||||
2. Server -> Mobile
|
||||
모바일 주소록 동기화 노티
|
||||
3. Mobile -> Server
|
||||
준비 완료 요청
|
||||
4. Server -> PC
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI
|
||||
5. PC -> Server
|
||||
모바일 주소록 받을 준비 완료 요청
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_REQ
|
||||
6.Server -> PC
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_RES //사용없음
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_NOTI
|
||||
PC가 모바일로부터 준비 확인 NOTI를 받는 처리를 수행
|
||||
7.Server -> PC
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_RES //사용없음
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI //실데이터받는 프로토콜
|
||||
박차장님이 제안한 방식
|
||||
PC 서버 요청
|
||||
모바일 노티
|
||||
모바일 주소록 JSON 으로 전송
|
||||
새로운 방식
|
||||
생각해봐야함
|
||||
서버에 개인주소록을 저장할 경우
|
||||
PC에서 동기화 완료 후 서버 데이터 삭제 고려
|
||||
서버에 개인주소록을 저장하지 않을 경우
|
||||
서버 부하 고려
|
||||
PC -> 서버
|
||||
개인 주소록 동기화 요청
|
||||
프로토콜 정의 협의
|
||||
서버 -> 모바일
|
||||
개인 주소록 동기화 요청에 대한 푸시
|
||||
모바일 -> 서버 (REST API)
|
||||
개인 주소록 POST 전송
|
||||
데이터 JSON 형태
|
||||
서버 -> 모바일 (REST API)
|
||||
개인 주소록 전송에 대한 응답
|
||||
(응답코드, 싱크번호, 시간, 사용자번호)
|
||||
모바일 -> 서버
|
||||
개인 주소록 전송 동기화 프로토콜 요청
|
||||
(싱크번호, 시간, 사용자번호)
|
||||
서버 -> 모바일
|
||||
개인 주소록 전송 동기화 프로토콜 요청에 대한 응답
|
||||
서버 -> PC
|
||||
개인 주소록 동기화 요청 프로토콜에 대한 푸시
|
||||
(싱크번호, 사용자번호)
|
||||
PC -> 서버 (REST API)
|
||||
개인 주소록 요청
|
||||
(싱크번호, 사용자번호)
|
||||
서버 -> PC
|
||||
개인 주소록 JSON
|
||||
(싱크번호, 시간, 사용자 번호)
|
||||
|
||||
모바일 주소록 초기화
|
||||
PC에 저장된 모바일 주소록을 삭제
|
||||
엑샐
|
||||
|
@ -116,3 +146,14 @@
|
|||
템플릿
|
||||
초기화
|
||||
MAC용 빌드
|
||||
|
||||
대화 저장
|
||||
두개다 대화내용 암호화?
|
||||
서버에서 대화내용을 제공
|
||||
프로토콜 협의
|
||||
PC에서 대화내용 조회후 제공
|
||||
서버 부하
|
||||
|
||||
협의 필요
|
||||
|
||||
|
||||
|
|
|
@ -34,3 +34,4 @@ tems[position].FILE_THUMB_URL
|
|||
.replace("WebFile", "AttFile")
|
||||
.replace(".thumb.jpg", "")
|
||||
클라이언트 참고 사항입니ㅏㄷ..실제 파일 열기 하실때는 실제 업로드된 파일경로로 접속하셔야 합니다.
|
||||
|
|
@ -64,6 +64,7 @@ projects\ucap-webmessenger-protocol-file\src\public-api.ts -> projects\ucap-webm
|
|||
|
||||
|
||||
1: "16F98292020-02-10 07:09:16{
|
||||
|
||||
↵"StatusCode":"200",
|
||||
↵"ErrorMessage":"",
|
||||
↵"RoomID":"76",
|
151
documents/업무/2월/2째주/0213.txt
Normal file
151
documents/업무/2월/2째주/0213.txt
Normal file
|
@ -0,0 +1,151 @@
|
|||
// 그리드 함수 백업
|
||||
|
||||
makeGrid() {
|
||||
const totalCount = this.bundleImageJson.fileCount;
|
||||
const remainder = totalCount % 3;
|
||||
const quotient = Math.floor(totalCount / 3);
|
||||
|
||||
let tile;
|
||||
|
||||
if (remainder === 0) {
|
||||
this.bundleImageJson.thumbUrls.forEach((v, idx) => {
|
||||
tile = {} as Tile;
|
||||
tile.cols = 2;
|
||||
this.getTile(tile, v);
|
||||
});
|
||||
} else if (remainder === 1) {
|
||||
if (quotient === 0) {
|
||||
tile = {} as Tile;
|
||||
this.bundleImageJson.thumbUrls.forEach(v => {
|
||||
this.getTile(tile, v);
|
||||
});
|
||||
tile.cols = 6;
|
||||
return;
|
||||
}
|
||||
|
||||
this.bundleImageJson.thumbUrls.forEach((v, idx) => {
|
||||
tile = {} as Tile;
|
||||
if (quotient <= idx / 3 + 1) {
|
||||
tile.cols = 3;
|
||||
} else {
|
||||
tile.cols = 2;
|
||||
}
|
||||
this.getTile(tile, v);
|
||||
});
|
||||
} else {
|
||||
this.bundleImageJson.thumbUrls.forEach((v, idx) => {
|
||||
tile = {} as Tile;
|
||||
if (quotient <= idx / 3) {
|
||||
tile.cols = 3;
|
||||
} else {
|
||||
tile.cols = 2;
|
||||
}
|
||||
this.getTile(tile, v);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private getTile(tile: Tile, v: string) {
|
||||
tile.imgSrc = this.baseURL + v;
|
||||
tile.color = 'white';
|
||||
this.tiles.push(tile);
|
||||
}
|
||||
|
||||
모바일 개인 주소록을 PC 버전에도 공유
|
||||
PC->Mobile
|
||||
주소록 요청
|
||||
PC<-Mobile
|
||||
주소록 전송
|
||||
PC->Mobile
|
||||
주소록 완료
|
||||
|
||||
주소록
|
||||
UI 구성
|
||||
검색 (이름, 전화번호)
|
||||
검색 결과
|
||||
리스트 출력
|
||||
모바일 주소록 동기화(PC-> Mobile 요청)
|
||||
모바일 주소록 초기화(PC에서 동기화된 주소록 초기화)
|
||||
엑샐 탬플릿 (주소록을 입력할 수 있는 액샐 템플릿을 제공)
|
||||
액샐 업로드 (주소록이 입력된 액샐 템플릿을 업로드 하여 PC 주소록 업데이트)
|
||||
액샐 데이터 초기화 (액샐 업로드 데이터 초기화)
|
||||
액셀 내려받기 (주소록 데이터 액셀로 다운로드)
|
||||
기능 목록
|
||||
모바일 주소록 동기화
|
||||
기존방식 (데이터가 많은 경우 중간 서버에서 끊길 가능성)
|
||||
1. PC -> Server
|
||||
모바일 주소록 동기화 시작
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ
|
||||
2. Server -> Mobile
|
||||
모바일 주소록 동기화 노티
|
||||
3. Mobile -> Server
|
||||
모바일 준비 완료 요청 및 데이터 전송 (추측)
|
||||
4. Server -> PC
|
||||
4. Server -> PC
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI
|
||||
5. PC -> Server
|
||||
PC 준비 완료 요청
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_REQ
|
||||
6.Server -> PC
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_RES //사용없음
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_NOTI
|
||||
PC가 모바일로부터 준비 확인 NOTI를 받는 처리를 수행
|
||||
7.Server -> PC
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_RES //사용없음
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI //실데이터받는 프로토콜
|
||||
박차장님이 제안한 방식
|
||||
PC -> 서버
|
||||
개인 주소록 동기화 요청
|
||||
프로토콜 정의 협의
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ
|
||||
(사용자번호)
|
||||
서버 -> 모바일
|
||||
개인 주소록 동기화 요청에 대한 푸시
|
||||
모바일 -> 서버 (REST API)
|
||||
개인 주소록 POST 전송
|
||||
데이터 JSON 형태
|
||||
서버 -> 모바일 (REST API)
|
||||
개인 주소록 전송에 대한 응답
|
||||
(응답코드, 싱크번호, 시간, 사용자번호)
|
||||
모바일 -> 서버
|
||||
개인 주소록 전송 동기화 프로토콜 요청
|
||||
(싱크번호, 시간, 사용자번호)
|
||||
서버 -> 모바일
|
||||
개인 주소록 전송 동기화 프로토콜 요청에 대한 응답
|
||||
서버 -> PC
|
||||
모바일 개인 주소록 전송 완료 노티
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI
|
||||
(싱크번호, 사용자번호)
|
||||
PC -> 서버 (REST API)
|
||||
개인 주소록 요청
|
||||
(싱크번호, 사용자번호)
|
||||
서버 -> PC
|
||||
개인 주소록 JSON
|
||||
(싱크번호, 시간, 사용자 번호)
|
||||
|
||||
모바일 주소록 초기화
|
||||
PC에 저장된 모바일 주소록을 삭제
|
||||
엑샐
|
||||
Export/Import
|
||||
템플릿
|
||||
초기화
|
||||
|
||||
대화방
|
||||
|
||||
TODO 완료
|
||||
대화 묶음파일 그리드 컴포넌트 리팩토링
|
||||
|
||||
파일 업로드 큐 컴포넌트 수정
|
||||
묶음파일 처리 추가
|
||||
|
||||
묶음파일 업로드 함수 리팩토링
|
||||
묶음파일 모델링 수정
|
||||
메세지 전송 컴포넌트 수정
|
||||
묶음파일 전송 UI 추가
|
||||
묶음파일 전송 로직 추가
|
||||
이벤트 타입 추가
|
||||
BundleImage = 'b';
|
||||
파일 타입 추가
|
||||
Bundle = 'b';
|
||||
앨범함 컴포넌트 수정
|
||||
묶음파일 타입 처리 추가
|
37
documents/업무/2월/2째주/0214.txt
Normal file
37
documents/업무/2월/2째주/0214.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
내일 TODO
|
||||
Call 컴포넌트 작성
|
||||
다이얼러 컴포넌트 작성
|
||||
주소록 컴포넌트 작성
|
||||
최근통화내역 컴포넌트 작성
|
||||
요구사항
|
||||
지역번호-3자리-4자리 /^(0(2|3[1-3]|4[1-4]|5[1-5]|6[1-4]))-(\d{3,4})-(\d{4})$/
|
||||
010-4자리-4자리 || 011,017,016-3자리-4자리 /^(?:(010-\d{4})|(01[1|6|7|8|9]-\d{3,4}))-(\d{4})$/
|
||||
기타번호4자리-4자리
|
||||
// 추후에 +국가코드3자리-
|
||||
입력번호, 출력번호
|
||||
숫자 버튼,
|
||||
통화 버튼,
|
||||
삭제 버튼
|
||||
|
||||
4행 * 3열 그리드 출력
|
||||
|
||||
번호 함수
|
||||
입력 이벤트 마다 지역번호, 핸드폰 번호 추출
|
||||
하이픈 넣기
|
||||
입력번호를 출력번호로 변환
|
||||
|
||||
삭제 함수
|
||||
이벤트 발생 마다
|
||||
입력번호 삭제
|
||||
번호함수 호출
|
||||
|
||||
통화 함수
|
||||
클릭투콜 API 호출
|
||||
|
||||
주간보고서 작성
|
||||
묶음파일 업로드 추가
|
||||
그리드 기능 추가
|
||||
앨범함 기능 추가
|
||||
묶음파일 전송 기능 추가
|
||||
파일 업로드 기능 수정
|
||||
|
34
documents/업무/2월/2째주/LF_개인주소록_프로토콜.txt
Normal file
34
documents/업무/2월/2째주/LF_개인주소록_프로토콜.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
SSVC_TYPE_SYNC_PHONEBOOK_READY_REQ = 21, || 모바일 주소록 씽크 준비 요청
|
||||
PC -> Server
|
||||
모바일 온라인 확인 단계 필요
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_RES = 22, || 모바일 주소록 씽크 준비 요청완료
|
||||
서버 -> PC
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI 프로토콜을 30초동안 기다림
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_NOTI = 23, || 모바일 주소록 씽크 준비 알림
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_REQ = 24, || 모바일 주소록 씽크 준비 확인 요청
|
||||
3
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_RES = 25, || 모바일 주소록 씽크 준비 확인 요청완료
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_READY_OK_NOTI = 26, || 모바일 주소록 씽크 준비 확인 알림
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_REQ = 31, || 모바일 주소록 씽크 요청
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_RES = 32, || 모바일 주소록 씽크 완료
|
||||
데이터는 M->PC 단방향 해당 RES는 PC 에서는 아무의미가 없다.
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_SND_NOTI = 33, || 모바일 주소록 씽크 알림
|
||||
해당 노티는 PC가 받는 노티(실데이터가 있음)
|
||||
|
||||
//** 모바일에서 사용하는 프로토콜 **//
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_RCV_REQ = 34, || 모바일 주소록 씽크 확인 요청
|
||||
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_RCV_RES = 35, || 모바일 주소록 씽크 확인 요청완료
|
||||
PC 사용 X
|
||||
SSVC_TYPE_SYNC_PHONEBOOK_RCV_NOTI = 36, || 모바일 주소록 씽크 확인 알림
|
||||
PC 사용 X
|
||||
모바일에서 사용한는 프로토콜
|
||||
//** 모바일에서 사용하는 프로토콜 **//
|
||||
|
182
documents/업무/2월/2째주/묵음파일백업/album-box.component.html
Normal file
182
documents/업무/2월/2째주/묵음파일백업/album-box.component.html
Normal file
|
@ -0,0 +1,182 @@
|
|||
<div fxLayout="column" class="rightDrawer-albumbox">
|
||||
<div>
|
||||
<mat-tab-group
|
||||
mat-stretch-tabs
|
||||
animationDuration="0ms"
|
||||
(selectedIndexChange)="onSelectedIndexChange($event)"
|
||||
>
|
||||
<mat-tab label="{{ 'common.file.type.images' | translate }}"></mat-tab>
|
||||
<mat-tab label="{{ 'common.file.type.video' | translate }}"></mat-tab>
|
||||
</mat-tab-group>
|
||||
</div>
|
||||
<div fxFlex="1 1 240px" class="select-filebox bg-accent-brightest">
|
||||
<ng-container *ngIf="!selectedFile">
|
||||
<div class="empty-msg" *ngIf="currentTabIndex === 0">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="butt"
|
||||
stroke-linejoin="round"
|
||||
aria-label="image"
|
||||
>
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" />
|
||||
<circle cx="8.5" cy="8.5" r="1.5" />
|
||||
<path d="M20.4 14.5L16 10 4 20" />
|
||||
</svg>
|
||||
<span>{{ 'common.file.selectFiles' | translate }}</span>
|
||||
</div>
|
||||
|
||||
<div class="empty-msg" *ngIf="currentTabIndex === 1">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="36"
|
||||
height="36"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="butt"
|
||||
stroke-linejoin="round"
|
||||
aria-label="video"
|
||||
>
|
||||
<rect x="2" y="2" width="20" height="20" rx="2.18" ry="2.18"></rect>
|
||||
<line x1="7" y1="2" x2="7" y2="22"></line>
|
||||
<line x1="17" y1="2" x2="17" y2="22"></line>
|
||||
<line x1="2" y1="12" x2="22" y2="12"></line>
|
||||
<line x1="2" y1="7" x2="7" y2="7"></line>
|
||||
<line x1="2" y1="17" x2="7" y2="17"></line>
|
||||
<line x1="17" y1="17" x2="22" y2="17"></line>
|
||||
<line x1="17" y1="7" x2="22" y2="7"></line>
|
||||
</svg>
|
||||
<span>{{ 'common.file.selectFiles' | translate }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="selectedFile">
|
||||
<div class="select-file">
|
||||
<img
|
||||
*ngIf="selectedFile.info.type === FileType.Image"
|
||||
[src]="getImageUrl(selectedFile)"
|
||||
class="preview-image"
|
||||
/>
|
||||
<video
|
||||
controls
|
||||
controlsList="nodownload nofullscreen"
|
||||
class="preview-video"
|
||||
#videoPlayer
|
||||
*ngIf="selectedFile.info.type === FileType.Video && playable"
|
||||
[src]="getImageUrl(selectedFile)"
|
||||
(loadeddata)="onLoadedDataVideo()"
|
||||
></video>
|
||||
<div
|
||||
*ngIf="selectedFile.info.type === FileType.Video && !playable"
|
||||
fxFlexFill
|
||||
class="guide-msg"
|
||||
>
|
||||
{{ 'common.file.errors.cantPlay' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<ul>
|
||||
<li class="name">{{ selectedFile.info.name }}</li>
|
||||
<li>
|
||||
<span class="text-accent-color">size :</span>
|
||||
{{ selectedFile.info.size | ucapBytes }}
|
||||
</li>
|
||||
<li>
|
||||
<span class="text-accent-color">date :</span>
|
||||
{{ selectedFile.info.sendDate | ucapDate: 'YYYY.MM.DD' }}
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
</div>
|
||||
<div class="search-list">
|
||||
<perfect-scrollbar class="album-scrollbar">
|
||||
<div
|
||||
*ngFor="let fileInfo of filteredList"
|
||||
class="img-item"
|
||||
(click)="onClickImage($event, fileInfo)"
|
||||
>
|
||||
<dl>
|
||||
<dt>
|
||||
<div
|
||||
*ngIf="fileInfo.fileDownloadItem.downloadingProgress$ | async"
|
||||
class="spinner"
|
||||
>
|
||||
<span class="mdi mdi-spin mdi-loading mdi-48px"></span>
|
||||
</div>
|
||||
<div
|
||||
*ngIf="
|
||||
!!fileInfo.info &&
|
||||
!!fileInfo.info.sentMessageJson &&
|
||||
!!fileInfo.info.sentMessageJson.thumbUrl;
|
||||
then thumb;
|
||||
else icon
|
||||
"
|
||||
></div>
|
||||
<ng-template #thumb>
|
||||
<img
|
||||
#thumbImg
|
||||
[src]="fileInfo.info.sentMessageJson.thumbUrl"
|
||||
[matTooltip]="fileInfo.info.name"
|
||||
(error)="onErrorThumbnail(thumbImg, fileInfo)"
|
||||
/>
|
||||
</ng-template>
|
||||
<ng-template #icon>
|
||||
<div
|
||||
[ngClass]="[
|
||||
'mime-icon',
|
||||
'light',
|
||||
'ico-' + getExtention(fileInfo.info.name)
|
||||
]"
|
||||
>
|
||||
<div class="ico"></div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</dt>
|
||||
<dd>
|
||||
<span class="checkbox">
|
||||
<mat-checkbox
|
||||
#checkbox
|
||||
[checked]="getCheckItem(fileInfo)"
|
||||
(change)="onCheckItem(checkbox.checked, fileInfo)"
|
||||
(click)="$event.stopPropagation()"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</span>
|
||||
<span class="btn-download">
|
||||
<button mat-button (click)="onClickDownload(fileInfo)">
|
||||
<mat-icon>vertical_align_bottom</mat-icon>
|
||||
</button>
|
||||
</span>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</perfect-scrollbar>
|
||||
</div>
|
||||
<div
|
||||
fxFlex="1 1 50px"
|
||||
fxLayout="row"
|
||||
fxLayoutAlign="center center"
|
||||
class="btn-box"
|
||||
>
|
||||
<button
|
||||
mat-flat-button
|
||||
[disabled]="selectedFileList.length > 0 ? 'false' : 'true'"
|
||||
class="mat-primary"
|
||||
(click)="onClickDownloadAll()"
|
||||
>
|
||||
{{ 'common.file.downloadSelected' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-flat-button
|
||||
class="mat-primary"
|
||||
(click)="onClickOpenDownloadFolder()"
|
||||
>
|
||||
{{ 'common.file.openDownloadFolder' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
264
documents/업무/2월/2째주/묵음파일백업/album-box.component.ts
Normal file
264
documents/업무/2월/2째주/묵음파일백업/album-box.component.ts
Normal file
|
@ -0,0 +1,264 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
OnDestroy,
|
||||
Inject,
|
||||
ElementRef,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import {
|
||||
FileInfo,
|
||||
FileDownloadInfo,
|
||||
FileType
|
||||
} from '@ucap-webmessenger/protocol-file';
|
||||
import { Subscription, combineLatest } from 'rxjs';
|
||||
import { Store, select } from '@ngrx/store';
|
||||
|
||||
import * as AppStore from '@app/store';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { FileUtil } from '@ucap-webmessenger/core';
|
||||
import { CommonApiService } from '@ucap-webmessenger/api-common';
|
||||
import { LoginResponse } from '@ucap-webmessenger/protocol-authentication';
|
||||
import { SessionStorageService } from '@ucap-webmessenger/web-storage';
|
||||
import { KEY_LOGIN_RES_INFO } from '@app/types/login-res-info.type';
|
||||
import {
|
||||
EnvironmentsInfo,
|
||||
KEY_ENVIRONMENTS_INFO,
|
||||
KEY_VER_INFO
|
||||
} from '@app/types';
|
||||
import { VersionInfo2Response } from '@ucap-webmessenger/api-public';
|
||||
import { UCAP_NATIVE_SERVICE, NativeService } from '@ucap-webmessenger/native';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { FileDownloadItem } from '@ucap-webmessenger/api';
|
||||
import { ModuleConfig } from '@ucap-webmessenger/api-common';
|
||||
import { _MODULE_CONFIG } from 'projects/ucap-webmessenger-api-common/src/lib/config/token';
|
||||
import { AppFileService } from '@app/services/file.service';
|
||||
|
||||
export interface FileInfoTotal {
|
||||
info: FileInfo;
|
||||
checkInfo: FileDownloadInfo[];
|
||||
fileDownloadItem: FileDownloadItem;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout-chat-right-drawer-album-box',
|
||||
templateUrl: './album-box.component.html',
|
||||
styleUrls: ['./album-box.component.scss']
|
||||
})
|
||||
export class AlbumBoxComponent implements OnInit, OnDestroy {
|
||||
@ViewChild('videoPlayer', { static: false })
|
||||
videoPlayer: ElementRef<HTMLVideoElement>;
|
||||
|
||||
filteredList: FileInfoTotal[] = [];
|
||||
fileInfoTotal: FileInfoTotal[];
|
||||
fileInfoList: FileInfo[];
|
||||
fileInfoListSubscription: Subscription;
|
||||
|
||||
selectedFile: FileInfoTotal;
|
||||
selectedFileList: FileInfoTotal[] = [];
|
||||
|
||||
loginRes: LoginResponse;
|
||||
environmentsInfo: EnvironmentsInfo;
|
||||
sessionVerinfo: VersionInfo2Response;
|
||||
|
||||
FileType = FileType;
|
||||
currentTabIndex = 0;
|
||||
|
||||
thumbBaseUrl: string;
|
||||
|
||||
playable = true;
|
||||
|
||||
constructor(
|
||||
private store: Store<any>,
|
||||
private sessionStorageService: SessionStorageService,
|
||||
private commonApiService: CommonApiService,
|
||||
@Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
|
||||
private appFileService: AppFileService,
|
||||
@Inject(_MODULE_CONFIG) private moduleConfig: ModuleConfig,
|
||||
private logger: NGXLogger
|
||||
) {
|
||||
this.loginRes = this.sessionStorageService.get<LoginResponse>(
|
||||
KEY_LOGIN_RES_INFO
|
||||
);
|
||||
this.environmentsInfo = this.sessionStorageService.get<EnvironmentsInfo>(
|
||||
KEY_ENVIRONMENTS_INFO
|
||||
);
|
||||
this.sessionVerinfo = this.sessionStorageService.get<VersionInfo2Response>(
|
||||
KEY_VER_INFO
|
||||
);
|
||||
|
||||
this.thumbBaseUrl = `${this.moduleConfig.hostConfig.protocol}://${
|
||||
this.moduleConfig.hostConfig.domain
|
||||
}:${String(this.moduleConfig.hostConfig.port)}`;
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.fileInfoListSubscription = combineLatest([
|
||||
this.store.pipe(select(AppStore.MessengerSelector.RoomSelector.roomInfo)),
|
||||
this.store.pipe(
|
||||
select(AppStore.MessengerSelector.EventSelector.selectAllFileInfoList)
|
||||
),
|
||||
this.store.pipe(
|
||||
select(
|
||||
AppStore.MessengerSelector.EventSelector.selectAllFileInfoCheckList
|
||||
)
|
||||
)
|
||||
])
|
||||
.pipe(
|
||||
tap(() => (this.fileInfoTotal = [])),
|
||||
tap(([roomInfo, fileInfoList, fileInfoCheckList]) => {
|
||||
this.fileInfoList = fileInfoList.filter(fileInfo => {
|
||||
if (
|
||||
!!roomInfo &&
|
||||
fileInfo.roomSeq === roomInfo.roomSeq &&
|
||||
(fileInfo.type === FileType.Image ||
|
||||
fileInfo.type === FileType.Video)
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
this.fileInfoList.map(fileInfo => {
|
||||
this.fileInfoTotal.push({
|
||||
info: fileInfo,
|
||||
checkInfo: fileInfoCheckList.filter(
|
||||
checkInfo => checkInfo.seq === fileInfo.seq
|
||||
),
|
||||
fileDownloadItem: new FileDownloadItem()
|
||||
});
|
||||
});
|
||||
|
||||
this.onSelectedIndexChange(this.currentTabIndex);
|
||||
})
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (!!this.fileInfoListSubscription) {
|
||||
this.fileInfoListSubscription.unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
getExtention(name: string): string {
|
||||
return FileUtil.getExtension(name);
|
||||
}
|
||||
|
||||
getImageUrl(fileInfo: FileInfoTotal): string {
|
||||
return this.commonApiService.urlForFileTalkDownload(
|
||||
{
|
||||
userSeq: this.loginRes.userSeq,
|
||||
deviceType: this.environmentsInfo.deviceType,
|
||||
token: this.loginRes.tokenString,
|
||||
attachmentsSeq: fileInfo.info.seq
|
||||
},
|
||||
this.sessionVerinfo.downloadUrl
|
||||
);
|
||||
}
|
||||
|
||||
onErrorThumbnail(el: HTMLElement, fileInfo: FileInfoTotal): void {
|
||||
const iconEl = document.createElement('div');
|
||||
iconEl.setAttribute(
|
||||
'class',
|
||||
'mime-icon light ico-' + this.getExtention(fileInfo.info.name)
|
||||
);
|
||||
iconEl.innerHTML = `<div class="ico"></div>`;
|
||||
el.replaceWith(iconEl);
|
||||
}
|
||||
|
||||
onSelectedIndexChange(index: number) {
|
||||
this.selectedFile = null;
|
||||
this.currentTabIndex = index;
|
||||
if (this.currentTabIndex === 0) {
|
||||
// Image
|
||||
this.filteredList = this.fileInfoTotal.filter(
|
||||
fileInfo => fileInfo.info.type === FileType.Image
|
||||
);
|
||||
} else {
|
||||
// Video
|
||||
this.filteredList = this.fileInfoTotal.filter(
|
||||
fileInfo => fileInfo.info.type === FileType.Video
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onClickImage(event: MouseEvent, fileInfo: FileInfoTotal) {
|
||||
if (!!event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
this.playable = true;
|
||||
this.selectedFile = fileInfo;
|
||||
}
|
||||
|
||||
getCheckItem(fileInfo: FileInfoTotal) {
|
||||
if (this.selectedFileList) {
|
||||
if (
|
||||
this.selectedFileList.filter(
|
||||
info => info.info.seq === fileInfo.info.seq
|
||||
).length > 0
|
||||
) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
onCheckItem(value: boolean, fileInfo: FileInfoTotal) {
|
||||
if (value) {
|
||||
this.onClickImage(undefined, fileInfo);
|
||||
this.selectedFileList.push(fileInfo);
|
||||
} else {
|
||||
this.selectedFileList = this.selectedFileList.filter(
|
||||
info => info.info.seq !== fileInfo.info.seq
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onClickDownload(fileInfo: FileInfoTotal) {
|
||||
this.appFileService.fileTalkDownlod({
|
||||
req: {
|
||||
userSeq: this.loginRes.userSeq,
|
||||
deviceType: this.environmentsInfo.deviceType,
|
||||
token: this.loginRes.tokenString,
|
||||
attachmentsSeq: fileInfo.info.seq,
|
||||
fileDownloadItem: fileInfo.fileDownloadItem
|
||||
},
|
||||
fileName: fileInfo.info.name
|
||||
});
|
||||
}
|
||||
|
||||
onClickDownloadAll(): void {
|
||||
this.selectedFileList.forEach(fileInfo => {
|
||||
this.onClickDownload(fileInfo);
|
||||
});
|
||||
}
|
||||
|
||||
onClickOpenDownloadFolder(): void {
|
||||
this.nativeService
|
||||
.openDefaultDownloadFolder()
|
||||
.then(result => {
|
||||
if (!!result) {
|
||||
} else {
|
||||
throw new Error('response Error');
|
||||
}
|
||||
})
|
||||
.catch(reason => {
|
||||
this.logger.error(reason);
|
||||
});
|
||||
}
|
||||
|
||||
onLoadedDataVideo(): void {
|
||||
if (
|
||||
0 === this.videoPlayer.nativeElement.videoWidth ||
|
||||
0 === this.videoPlayer.nativeElement.videoHeight
|
||||
) {
|
||||
this.playable = false;
|
||||
}
|
||||
}
|
||||
}
|
36
documents/업무/2월/2째주/묵음파일백업/bundle-image.event-json.ts
Normal file
36
documents/업무/2월/2째주/묵음파일백업/bundle-image.event-json.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { StatusCode, JsonAnalization } from '@ucap-webmessenger/api';
|
||||
import { FileType } from '@ucap-webmessenger/protocol-file';
|
||||
import { EventJsonDecoder } from './event-json';
|
||||
|
||||
export interface BundleImageEventJson {
|
||||
statusCode?: StatusCode;
|
||||
errorMessage?: string;
|
||||
roomSeq?: number;
|
||||
attachmentSeq?: number;
|
||||
fileCount?: number;
|
||||
baseUrl?: string;
|
||||
thumbUrls?: string[];
|
||||
fileType?: FileType;
|
||||
}
|
||||
|
||||
export const decodeBundleImageEventJson: EventJsonDecoder<BundleImageEventJson> = (
|
||||
message: string
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(message);
|
||||
|
||||
return {
|
||||
statusCode: json.StatusCode,
|
||||
errorMessage: json.ErrorMessage,
|
||||
roomSeq: json.RoomID,
|
||||
attachmentSeq: json.AttSEQ,
|
||||
fileCount: json.FileCount,
|
||||
thumbUrls: json.ThumbURL
|
||||
} as BundleImageEventJson;
|
||||
} catch (e) {
|
||||
return {
|
||||
statusCode: StatusCode.Fail,
|
||||
errorMessage: e.toString()
|
||||
} as BundleImageEventJson;
|
||||
}
|
||||
};
|
382
documents/업무/2월/2째주/묵음파일백업/common-api.service.ts
Normal file
382
documents/업무/2월/2째주/묵음파일백업/common-api.service.ts
Normal file
|
@ -0,0 +1,382 @@
|
|||
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';
|
||||
|
||||
@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 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 progressList: Subject<number>[] = [];
|
||||
for (const p of req.fileUploadItems) {
|
||||
progressList.push(p.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));
|
||||
for (const progress of progressList) {
|
||||
progress.next(Math.round((100 * event.loaded) / event.total));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
map((event: HttpResponse<any>) => {
|
||||
for (const p of req.fileUploadItems) {
|
||||
p.uploadComplete();
|
||||
}
|
||||
return decodeFileTalkSaveMulti(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 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))
|
||||
);
|
||||
}
|
||||
}
|
79
documents/업무/2월/2째주/묵음파일백업/file-talk-save-multi.ts
Normal file
79
documents/업무/2월/2째주/묵음파일백업/file-talk-save-multi.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { DeviceType } from '@ucap-webmessenger/core';
|
||||
import {
|
||||
APIRequest,
|
||||
APIResponse,
|
||||
APIEncoder,
|
||||
APIDecoder,
|
||||
ParameterUtil,
|
||||
StatusCode,
|
||||
JsonAnalization,
|
||||
APIFormDataEncoder
|
||||
} from '@ucap-webmessenger/api';
|
||||
import { FileUploadItem } from '../../../../ucap-webmessenger-api/src/lib/models/file-upload-item';
|
||||
|
||||
export interface FileTalkSaveMultiRequest extends APIRequest {
|
||||
userSeq: number;
|
||||
deviceType: DeviceType;
|
||||
token: string;
|
||||
files: File[];
|
||||
fileUploadItems: FileUploadItem[];
|
||||
roomSeq?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface FileTalkSaveMultiResponse extends APIResponse {
|
||||
roomSeq?: string;
|
||||
attachmentSeq?: string;
|
||||
fileCount?: string;
|
||||
baseUrl?: string;
|
||||
fileType?: string;
|
||||
thumbnailUrls?: string[];
|
||||
returnJson?: string;
|
||||
}
|
||||
|
||||
const fileTalkSaveEncodeMapTemp = {
|
||||
userSeq: 'p_user_seq',
|
||||
deviceType: 'p_device_type',
|
||||
token: 'p_token',
|
||||
roomSeq: 'p_room_id',
|
||||
files: 'file[]',
|
||||
type: 'p_type'
|
||||
};
|
||||
|
||||
export const encodeFileTalkSaveMulti: APIFormDataEncoder<FileTalkSaveMultiRequest> = (
|
||||
req: FileTalkSaveMultiRequest
|
||||
) => {
|
||||
const extraParams: any = {};
|
||||
extraParams.userSeq = String(req.userSeq);
|
||||
|
||||
return ParameterUtil.encodeFormData(
|
||||
fileTalkSaveEncodeMapTemp,
|
||||
req,
|
||||
extraParams
|
||||
);
|
||||
};
|
||||
|
||||
export const decodeFileTalkSaveMulti: APIDecoder<FileTalkSaveMultiResponse> = (
|
||||
res: any
|
||||
) => {
|
||||
try {
|
||||
const json = JsonAnalization.receiveAnalization(res);
|
||||
const fileTypeDefault =
|
||||
!json.fileType || json.fileType === '' ? 'b' : json.fileType;
|
||||
return {
|
||||
statusCode: json.StatusCode,
|
||||
roomSeq: json.RoomID,
|
||||
attachmentSeq: json.AttSEQ,
|
||||
fileCount: json.FileCount,
|
||||
fileType: fileTypeDefault,
|
||||
baseUrl: json.BaseURL,
|
||||
thumbnailUrls: json.ThumbURL,
|
||||
returnJson: res
|
||||
} as FileTalkSaveMultiResponse;
|
||||
} catch (e) {
|
||||
return {
|
||||
statusCode: StatusCode.Fail,
|
||||
errorMessage: e
|
||||
} as FileTalkSaveMultiResponse;
|
||||
}
|
||||
};
|
44
documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.html
Normal file
44
documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.html
Normal file
|
@ -0,0 +1,44 @@
|
|||
<div fxLayout="row wrap" fxFlex="100" class="ucap-file-upload-queue-container">
|
||||
<div *ngFor="let fileUploadItem of fileUploadItems" class="file-upload-item">
|
||||
<div fxLayout="row" class="file-upload-info">
|
||||
<!--<mat-icon>image</mat-icon>-->
|
||||
<!--파일이미지 svg-->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="butt"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"
|
||||
></path>
|
||||
</svg>
|
||||
|
||||
<div class="file-upload-name">{{ fileUploadItem.file.name }}</div>
|
||||
<!-- <div (click)="onClickClear(fileUploadItem)">
|
||||
<mat-icon>clear</mat-icon>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div fxLayout="row" class="file-upload-progress">
|
||||
<mat-progress-bar
|
||||
mode="determinate"
|
||||
[value]="fileUploadItem.uploadingProgress$ | async"
|
||||
>
|
||||
</mat-progress-bar>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="uploadItems" fxLayout="column" class="uploadItems">
|
||||
<div class="msg-guide">
|
||||
<span class="icon-img"><i class="mid mdi-arrow-expand-all"></i></span
|
||||
>{{ 'common.file.dropZoneForUpload' | translate }}
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
55
documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.scss
Normal file
55
documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.scss
Normal file
|
@ -0,0 +1,55 @@
|
|||
@mixin ellipsis($row) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@if $row == 1 {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
} @else if $row >= 2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: $row;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.ucap-file-upload-queue-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.file-upload-item {
|
||||
min-width: 200px;
|
||||
margin: 0 1%;
|
||||
margin-bottom: 10px;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #dddddd;
|
||||
.file-upload-info {
|
||||
padding: 10px;
|
||||
svg {
|
||||
margin-right: 6px;
|
||||
}
|
||||
.file-upload-name {
|
||||
height: 20px;
|
||||
@include ellipsis(2);
|
||||
}
|
||||
}
|
||||
.file-upload-progress {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
}
|
||||
.uploadItems {
|
||||
width: 100%;
|
||||
font-size: 0.9em;
|
||||
.msg-guide {
|
||||
display: flex;
|
||||
flex: row;
|
||||
color: #ffffff;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
.icon-img {
|
||||
margin-right: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.ts
Normal file
117
documents/업무/2월/2째주/묵음파일백업/file-upload-queue.component.ts
Normal file
|
@ -0,0 +1,117 @@
|
|||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
Input,
|
||||
ElementRef,
|
||||
AfterViewInit
|
||||
} from '@angular/core';
|
||||
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { FileUploadItem } from '@ucap-webmessenger/api';
|
||||
|
||||
@Component({
|
||||
selector: 'ucap-file-upload-queue',
|
||||
templateUrl: './file-upload-queue.component.html',
|
||||
styleUrls: ['./file-upload-queue.component.scss']
|
||||
})
|
||||
export class FileUploadQueueComponent implements OnInit, AfterViewInit {
|
||||
@Input()
|
||||
dropZoneIncludeParent = false;
|
||||
|
||||
fileUploadItems: FileUploadItem[];
|
||||
uploadItems: DataTransferItem[];
|
||||
|
||||
constructor(
|
||||
private elementRef: ElementRef<HTMLElement>,
|
||||
private logger: NGXLogger
|
||||
) {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
this.changeStyleDisplay(false);
|
||||
}
|
||||
|
||||
onDragEnter(items: DataTransferItemList): void {
|
||||
if (!items || 0 === items.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uploadItems: DataTransferItem[] = [];
|
||||
// tslint:disable-next-line: prefer-for-of
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
uploadItems.push(items[i]);
|
||||
}
|
||||
this.uploadItems = [...uploadItems];
|
||||
this.changeStyleDisplay(true);
|
||||
}
|
||||
|
||||
onDragLeave(): void {
|
||||
this.changeStyleDisplay(false);
|
||||
}
|
||||
|
||||
onDrop(fileUploadItems: FileUploadItem[]) {
|
||||
if (!fileUploadItems || 0 === fileUploadItems.length) {
|
||||
return;
|
||||
}
|
||||
this.fileUploadItems = fileUploadItems;
|
||||
this.uploadItems = undefined;
|
||||
}
|
||||
|
||||
onFileSelected(fileUploadItems: FileUploadItem[]): void {
|
||||
if (!fileUploadItems || 0 === fileUploadItems.length) {
|
||||
return;
|
||||
}
|
||||
this.fileUploadItems = fileUploadItems;
|
||||
this.uploadItems = undefined;
|
||||
this.changeStyleDisplay(true);
|
||||
}
|
||||
|
||||
onUploadComplete(): void {
|
||||
setTimeout(() => {
|
||||
this.fileUploadItems = undefined;
|
||||
this.changeStyleDisplay(false);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
isEventInElement(event: DragEvent): boolean {
|
||||
const rect = this.elementRef.nativeElement.getBoundingClientRect();
|
||||
// const rect: DOMRect = this.elementRef.nativeElement.getBoundingClientRect();
|
||||
|
||||
if (
|
||||
event.pageX >= rect.left &&
|
||||
event.pageX <= rect.left + rect.width &&
|
||||
event.pageY >= rect.top &&
|
||||
event.pageY <= rect.top + rect.height
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private changeStyleDisplay(show: boolean): void {
|
||||
if (show || (!!this.fileUploadItems && 0 < this.fileUploadItems.length)) {
|
||||
if (this.dropZoneIncludeParent) {
|
||||
this.elementRef.nativeElement.parentElement.style.display = '';
|
||||
} else {
|
||||
this.elementRef.nativeElement.style.display = '';
|
||||
}
|
||||
} else {
|
||||
if (this.dropZoneIncludeParent) {
|
||||
this.elementRef.nativeElement.parentElement.style.display = 'none';
|
||||
} else {
|
||||
this.elementRef.nativeElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// onClickClear(fileUploadItem: FileUploadItem) {
|
||||
// this.fileUploadItems = this.fileUploadItems.filter(f => {
|
||||
// return (
|
||||
// f.file.name !== fileUploadItem.file.name &&
|
||||
// f.file.path !== fileUploadItem.file.path
|
||||
// );
|
||||
// });
|
||||
// this.filesChange.emit(this.fileUploadItems);
|
||||
// }
|
||||
}
|
384
documents/업무/2월/2째주/묵음파일백업/messages.component.html
Normal file
384
documents/업무/2월/2째주/묵음파일백업/messages.component.html
Normal file
|
@ -0,0 +1,384 @@
|
|||
<!-- CHAT -->
|
||||
<div class="container" fxFlex fxLayout="column">
|
||||
<!-- CHAT TOOLBAR -->
|
||||
<mat-toolbar class="chat-toolbar">
|
||||
<div fxFlex fxLayout="row" class="chat-header">
|
||||
<div fxLayout="row" fxLayoutAlign="start center" class="profile-img">
|
||||
<!-- RESPONSIVE CHATS BUTTON-->
|
||||
<button
|
||||
mat-icon-button
|
||||
aria-label="chats button"
|
||||
class="responsive-chats-button"
|
||||
>
|
||||
<!--<mat-icon>chat</mat-icon>-->
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke-width="1.5"
|
||||
stroke-linecap="butt"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<g>
|
||||
<path
|
||||
d="M3,21.8c-0.2,0-0.4-0.1-0.5-0.2c-0.2-0.2-0.3-0.5-0.2-0.8l1.8-5.4c-0.6-1.2-0.8-2.5-0.8-3.9c0-3.5,2-6.7,5.1-8.3
|
||||
c1.3-0.6,2.7-0.9,4.1-1H13c4.7,0.3,8.5,4,8.7,8.7l0,0.5c0,1.4-0.3,2.9-1,4.1c-1.6,3.2-4.7,5.1-8.3,5.1c0,0,0,0,0,0
|
||||
c-1.3,0-2.6-0.3-3.8-0.8l-5.4,1.8C3.2,21.7,3.1,21.8,3,21.8z M12.5,3.8C11.3,3.8,10.1,4,9,4.6c-2.6,1.3-4.3,4-4.3,6.9
|
||||
c0,1.2,0.3,2.4,0.8,3.5c0.1,0.2,0.1,0.4,0,0.6l-1.4,4.3l4.3-1.4c0.2-0.1,0.4,0,0.6,0c1.1,0.5,2.3,0.8,3.5,0.8c3,0,5.6-1.6,6.9-4.3
|
||||
c0.5-1.1,0.8-2.3,0.8-3.5c0,0,0,0,0,0V11C20,7.1,16.9,4,13,3.7L12.5,3.8C12.5,3.8,12.5,3.8,12.5,3.8z"
|
||||
/>
|
||||
</g>
|
||||
<g>
|
||||
<circle cx="9" cy="12" r="1" />
|
||||
<circle cx="12.5" cy="12" r="1" />
|
||||
<circle cx="16" cy="12" r="1" />
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<!-- / RESPONSIVE CHATS BUTTON-->
|
||||
<button
|
||||
mat-icon-button
|
||||
aria-label="chats button"
|
||||
class="responsive-chats-button chat-timer"
|
||||
*ngIf="!!roomInfoSubject.value && roomInfoSubject.value.isTimeRoom"
|
||||
>
|
||||
<mat-icon>timer</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="room-info">
|
||||
<div
|
||||
*ngIf="roomInfoSubject.value && roomInfoSubject.value.isTimeRoom"
|
||||
class="room-type text-accent-color "
|
||||
>
|
||||
<span class="bg-accent-darkest"
|
||||
>{{ getConvertTimer(roomInfoSubject.value.timeRoomInterval) }}
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="room-name">
|
||||
<ng-container
|
||||
*ngIf="!roomInfoSubject.value || !userInfoListSubject.value"
|
||||
>
|
||||
{{ 'chat.getRoomNameInProgress' | translate }}
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngIf="!!roomInfoSubject.value && !!userInfoListSubject.value"
|
||||
>
|
||||
<ng-container [ngSwitch]="roomInfoSubject.value.roomType">
|
||||
<ng-container *ngSwitchCase="RoomType.Mytalk">
|
||||
MyTalk
|
||||
</ng-container>
|
||||
<ng-container
|
||||
*ngSwitchCase="
|
||||
RoomType.Bot ||
|
||||
RoomType.Allim ||
|
||||
RoomType.Allim_Elephant ||
|
||||
RoomType.Allim_TMS
|
||||
"
|
||||
>
|
||||
{{ _roomUserInfos | ucapTranslate: 'name':',' }}
|
||||
</ng-container>
|
||||
<ng-container *ngSwitchDefault>
|
||||
<ng-template
|
||||
[ngIf]="
|
||||
!!roomInfoSubject.value.roomName &&
|
||||
'' !== roomInfoSubject.value.roomName.trim()
|
||||
"
|
||||
[ngIfElse]="roomNameNotExist"
|
||||
>
|
||||
{{ roomInfoSubject.value.roomName }}
|
||||
</ng-template>
|
||||
<ng-template #roomNameNotExist>
|
||||
{{ getRoomNameByRoomUser(_roomUserInfos) }}
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</h3>
|
||||
<!-- Timer Room Info -->
|
||||
<!--<div
|
||||
*ngIf="roomInfoSubject.value && roomInfoSubject.value.isTimeRoom"
|
||||
class="room-type text-accent-color "
|
||||
>
|
||||
<span class="bg-accent-darkest"
|
||||
>{{
|
||||
getConvertTimer(roomInfoSubject.value.timeRoomInterval)
|
||||
}} </span
|
||||
>{{ 'chat.isRoomTypeSecret' | translate }}
|
||||
</div>-->
|
||||
<!-- Timer Room Info -->
|
||||
</div>
|
||||
<div class="room-option">
|
||||
<button
|
||||
*ngIf="!!roomInfoSubject.value"
|
||||
mat-icon-button
|
||||
(click)="onClickReceiveAlarm()"
|
||||
aria-label="Toggle Receive Alarm"
|
||||
>
|
||||
<!--<mat-icon
|
||||
class="amber-fg"
|
||||
*ngIf="roomInfoSubject.value.receiveAlarm"
|
||||
matTooltip="{{ 'chat.notificationIsOn' | translate }}"
|
||||
>notifications_active</mat-icon>-->
|
||||
<mat-icon
|
||||
class="icon-button"
|
||||
*ngIf="roomInfoSubject.value.receiveAlarm"
|
||||
matTooltip="{{ 'chat.notificationIsOn' | translate }}"
|
||||
><i class="mid mdi-bell-ring-outline"></i
|
||||
></mat-icon>
|
||||
|
||||
<mat-icon
|
||||
class="icon-button"
|
||||
*ngIf="!roomInfoSubject.value.receiveAlarm"
|
||||
matTooltip="{{ 'chat.notificationIsOff' | translate }}"
|
||||
><i class="mid mdi-bell-off-outline"></i
|
||||
></mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
#chatMenuTrigger="matMenuTrigger"
|
||||
[matMenuTriggerFor]="contactMenu"
|
||||
[matMenuTriggerRestoreFocus]="false"
|
||||
aria-label="more"
|
||||
>
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-search-frame">
|
||||
<div
|
||||
*ngIf="eventListProcessing$ | async"
|
||||
style="position: absolute; width: 100%;"
|
||||
>
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div *ngIf="isShowSearchArea" class="chat-search bg-accent-color">
|
||||
<ucap-chat-search
|
||||
[totalCount]="searchTotalCount"
|
||||
[curIndex]="searchCurrentIndex"
|
||||
(searchText)="onSearchChat($event)"
|
||||
(prevSearch)="onPrevSearch()"
|
||||
(nextSearch)="onNextSearch()"
|
||||
(searchAndPrev)="onSearchAndPrev()"
|
||||
(closeSearchArea)="onCloseSearchArea()"
|
||||
></ucap-chat-search>
|
||||
</div>
|
||||
</div>
|
||||
</mat-toolbar>
|
||||
<!-- / CHAT TOOLBAR -->
|
||||
|
||||
<!-- CHAT CONTENT -->
|
||||
<div
|
||||
fxFlex="1 1 auto"
|
||||
class="chat-content"
|
||||
ucapFileUploadFor
|
||||
[fileUploadQueue]="fileUploadQueue"
|
||||
(fileSelected)="onFileSelected($event)"
|
||||
(fileDragEnter)="onFileDragEnter($event)"
|
||||
(fileDragOver)="onFileDragOver()"
|
||||
(fileDragLeave)="onFileDragLeave()"
|
||||
>
|
||||
<!-- CHAT MESSAGES -->
|
||||
<!-- [translationSimpleview]="translationSimpleview" (massTranslationDetail)="onMassTranslationDetail($event)" -->
|
||||
<ucap-chat-messages
|
||||
#chatMessages
|
||||
[eventList$]="eventListSubject.asObservable()"
|
||||
[newEventList$]="eventListNewSubject.asObservable()"
|
||||
[searchedList$]="searchedListSubject.asObservable()"
|
||||
[roomInfo$]="roomInfoSubject.asObservable()"
|
||||
[eventInfoStatus$]="eventInfoStatusSubject.asObservable()"
|
||||
[eventRemained$]="eventRemainedSubject.asObservable()"
|
||||
[userInfos$]="userInfoListSubject.asObservable()"
|
||||
[loginRes$]="loginResSubject.asObservable()"
|
||||
[lock$]="lockSubject.asObservable()"
|
||||
[sessionVerInfo]="sessionVerInfo"
|
||||
[isShowUnreadCount]="getShowUnreadCount()"
|
||||
[clearReadHere]="clearReadHere"
|
||||
[minShowReadHere]="
|
||||
environment.productConfig.CommonSetting.readHereShowMinimumEventCount
|
||||
"
|
||||
[searchingMode]="moreSearchProcessing"
|
||||
(moreEvent)="onMoreEvent($event)"
|
||||
(massDetail)="onMassDetail($event)"
|
||||
(save)="onSave($event)"
|
||||
(fileViewer)="onFileViewer($event)"
|
||||
(contextMenu)="onContextMenuMessage($event)"
|
||||
(openProfile)="onClickOpenProfile($event)"
|
||||
(scrollUp)="onScrollupMessages($event)"
|
||||
(yReachStart)="onYReachStartMessages($event)"
|
||||
(yReachEnd)="onYReachEndMessages($event)"
|
||||
(existNewMessage)="onExistNewMessage($event)"
|
||||
>
|
||||
</ucap-chat-messages>
|
||||
|
||||
<!-- CHAT MESSAGES -->
|
||||
<div class="file-drop-zone-container">
|
||||
<ucap-file-upload-queue
|
||||
#fileUploadQueue
|
||||
[dropZoneIncludeParent]="true"
|
||||
class="file-drop-zone"
|
||||
>
|
||||
</ucap-file-upload-queue>
|
||||
</div>
|
||||
</div>
|
||||
<!-- / CHAT CONTENT -->
|
||||
|
||||
<!-- sticker-selector -->
|
||||
<div class="sticker-selector-container">
|
||||
<ucap-sticker-selector
|
||||
*ngIf="isShowStickerSelector"
|
||||
#stickerSelector
|
||||
[stickerHistory]="getStickerHistory()"
|
||||
(selectedSticker)="onSelectedSticker($event)"
|
||||
(closeSticker)="onShowToggleStickerSelector()"
|
||||
class="sticker-selector-zone"
|
||||
></ucap-sticker-selector>
|
||||
<div></div>
|
||||
</div>
|
||||
<!-- / sticker-selector -->
|
||||
|
||||
<!-- Translation
|
||||
<div class="translation-container">-->
|
||||
<!-- <ucap-translation-section
|
||||
*ngIf="isShowTranslation"
|
||||
[destLocale]="destLocale"
|
||||
[simpleView]="translationSimpleview"
|
||||
[preView]="translationPreview"
|
||||
[translationPreviewInfo]="translationPreviewInfo"
|
||||
(changeTranslationSimpleview)="onChangeTranslationSimpleView($event)"
|
||||
(changeTranslationPreview)="onChangeTranslationPreView($event)"
|
||||
(changeDestLocale)="onChangeDestLocale($event)"
|
||||
(cancelTranslation)="onCancelTranslation($event)"
|
||||
(sendTranslationMessage)="onSendTranslationMessage($event)"
|
||||
>
|
||||
</ucap-translation-section> -->
|
||||
<!-- </div>
|
||||
/ Translation -->
|
||||
|
||||
<!-- CHAT FOOTER -->
|
||||
<div fxFlex="0 0 auto" fxLayout="column" *ngIf="getEnableSend()">
|
||||
<!-- REPLY FORM -->
|
||||
<ucap-chat-form
|
||||
#chatForm
|
||||
[fileUploadQueue]="fileUploadQueue"
|
||||
(send)="onSendMessage($event)"
|
||||
(sendFiles)="onFileSelected($event)"
|
||||
(clearView)="clearView()"
|
||||
(toggleStickerSelector)="onShowToggleStickerSelector($event)"
|
||||
(clipboardPaste)="onClipboardPaste($event)"
|
||||
>
|
||||
</ucap-chat-form>
|
||||
<!-- / REPLY FORM -->
|
||||
</div>
|
||||
<!-- / CHAT FOOTER-->
|
||||
</div>
|
||||
<!-- / CHAT -->
|
||||
|
||||
<mat-menu #contactMenu="matMenu">
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('OPEN_ALBUM_LIST')"
|
||||
(click)="onClickContextMenu('OPEN_ALBUM_LIST')"
|
||||
>
|
||||
{{ 'chat.albumBox.label' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('OPEN_FILE_LIST')"
|
||||
(click)="onClickContextMenu('OPEN_FILE_LIST')"
|
||||
>
|
||||
{{ 'chat.fileBox.label' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('CHAT_SEARCH')"
|
||||
(click)="onClickContextMenu('CHAT_SEARCH')"
|
||||
>
|
||||
{{ 'chat.searchEventByText' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('OPEN_ROOM_USER')"
|
||||
(click)="onClickContextMenu('OPEN_ROOM_USER')"
|
||||
>
|
||||
{{ 'chat.listOfRoomMember' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('ADD_MEMBER')"
|
||||
(click)="onClickContextMenu('ADD_MEMBER')"
|
||||
>
|
||||
{{ 'chat.addMemberToRoom' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('ADD_GROUP')"
|
||||
(click)="onClickContextMenu('ADD_GROUP')"
|
||||
>
|
||||
{{ 'chat.addMemberToGroup' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('EDIT_ROOM')"
|
||||
(click)="onClickContextMenu('EDIT_ROOM')"
|
||||
>
|
||||
{{ 'chat.settingsOfRoom' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="getShowContextMenu('CLOSE_ROOM')"
|
||||
(click)="onClickContextMenu('CLOSE_ROOM')"
|
||||
>
|
||||
{{ 'chat.closeRoom' | translate }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
|
||||
<div
|
||||
style="visibility: hidden; position: fixed"
|
||||
[style.left]="messageContextMenuPosition.x"
|
||||
[style.top]="messageContextMenuPosition.y"
|
||||
#messageContextMenuTrigger="matMenuTrigger"
|
||||
[matMenuTriggerFor]="messageContextMenu"
|
||||
></div>
|
||||
<mat-menu #messageContextMenu="matMenu">
|
||||
<ng-template matMenuContent let-message="message" let-clicktype="clicktype">
|
||||
<ng-container *ngIf="!isRecalledMessage(message.type)">
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isCopyableMessage(message.type)"
|
||||
(click)="onClickMessageContextMenu('COPY', message, clicktype)"
|
||||
>
|
||||
{{ 'chat.copyChatText' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isForwardableMessage(message, roomInfoSubject.value)"
|
||||
(click)="onClickMessageContextMenu('FORWARD', message)"
|
||||
>
|
||||
{{ 'chat.forwardEventTo' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isForwardableMessage(message, roomInfoSubject.value)"
|
||||
(click)="onClickMessageContextMenu('FORWARD_TO_ME', message)"
|
||||
>
|
||||
{{ 'chat.forwardEventToMe' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
(click)="onClickMessageContextMenu('DELETE', message)"
|
||||
>
|
||||
{{ 'chat.removeEvent' | translate }}
|
||||
</button>
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isRecallableMessage(message, loginResSubject.value.userSeq)"
|
||||
(click)="onClickMessageContextMenu('RECALL', message)"
|
||||
>
|
||||
{{ 'chat.recallEvent' | translate }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</mat-menu>
|
233
documents/업무/2월/2째주/묵음파일백업/messages.component.scss
Normal file
233
documents/업무/2월/2째주/묵음파일백업/messages.component.scss
Normal file
|
@ -0,0 +1,233 @@
|
|||
@charset 'utf-s';
|
||||
:host {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@mixin ellipsis($row) {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@if $row == 1 {
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
word-wrap: normal;
|
||||
} @else if $row >= 2 {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: $row;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.chat-toolbar {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
align-items: center;
|
||||
background-color: #ffffff !important;
|
||||
border-bottom: 1px solid #dddddd;
|
||||
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16);
|
||||
z-index: 1;
|
||||
padding: 0;
|
||||
.chat-header {
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-items: center;
|
||||
padding: 4px 20px;
|
||||
.profile-img {
|
||||
margin-right: 10px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
.responsive-chats-button {
|
||||
display: none;
|
||||
line-height: normal;
|
||||
cursor: unset;
|
||||
&:last-child {
|
||||
display: block;
|
||||
padding: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
color: #efefef;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
&.thumbnail-mask {
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
img {
|
||||
width: 50px;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
.room-info {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
overflow: hidden;
|
||||
align-items: center;
|
||||
.room-name {
|
||||
font-size: 0.94rem;
|
||||
line-height: normal;
|
||||
@include ellipsis(1);
|
||||
}
|
||||
.room-type {
|
||||
font-size: 0.9rem;
|
||||
line-height: normal;
|
||||
height: 20px;
|
||||
span {
|
||||
border-radius: 10px;
|
||||
padding: 2px 6px;
|
||||
margin-right: 6px;
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.room-option {
|
||||
margin-left: auto;
|
||||
margin-right: -10px;
|
||||
.icon-button {
|
||||
transform: translateY(-2px);
|
||||
i {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.chat-search-frame {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
.chat-search {
|
||||
margin: 0 4px 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-content {
|
||||
position: relative;
|
||||
background: transparent;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
.file-drop-zone-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: transparent;
|
||||
|
||||
.file-drop-zone {
|
||||
position: absolute;
|
||||
padding: 10px;
|
||||
background-color: rgb(54, 54, 54, 0.8);
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.sticker-selector-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
|
||||
.sticker-selector-zone {
|
||||
position: absolute;
|
||||
padding: 10px 10px 0 10px;
|
||||
background-color: rgba(250, 255, 255, 0.8);
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.translation-container {
|
||||
.translation-section {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
border-top: 1px solid #dddddd;
|
||||
.translation-container {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: transparent;
|
||||
background-color: rgba(250, 255, 255, 0.8);
|
||||
border-top: 1px solid;
|
||||
|
||||
.translation-zone {
|
||||
position: absolute;
|
||||
padding: 10px 10px 0 10px;
|
||||
background-color: rgba(250, 255, 255, 0.8);
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//mat-snack-bar
|
||||
::ng-deep .cdk-global-overlay-wrapper {
|
||||
.mat-snack-bar-container {
|
||||
margin: 0;
|
||||
padding: 30px;
|
||||
max-width: 60vw;
|
||||
.mat-simple-snackbar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
span {
|
||||
@include ellipsis(3);
|
||||
display: inline-block;
|
||||
padding: 7px 20px;
|
||||
border: 1px solid #ffffff;
|
||||
background-color: rgb(255, 255, 255, 0.2);
|
||||
color: #ffffff;
|
||||
margin-right: 4px;
|
||||
flex: 1 1 auto;
|
||||
max-width: 40vw;
|
||||
}
|
||||
&-action {
|
||||
display: inline-flex;
|
||||
margin-left: auto;
|
||||
flex: 0 0 auto;
|
||||
height: 100%;
|
||||
button {
|
||||
//background-color: #00b6d5;
|
||||
border-radius: 2px;
|
||||
span {
|
||||
padding: 0 20px;
|
||||
color: #ffffff;
|
||||
background: none;
|
||||
border: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::ng-deep .chat-header {
|
||||
.profile-img {
|
||||
.chat-timer {
|
||||
.mat-button-wrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
.mat-icon {
|
||||
line-height: normal;
|
||||
color: #ffffff;
|
||||
font-size: 20px;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2086
documents/업무/2월/2째주/묵음파일백업/messages.component.ts
Normal file
2086
documents/업무/2월/2째주/묵음파일백업/messages.component.ts
Normal file
File diff suppressed because it is too large
Load Diff
1
documents/업무/2월/2째주/묶음파일변경사항.txt
Normal file
1
documents/업무/2월/2째주/묶음파일변경사항.txt
Normal file
|
@ -0,0 +1 @@
|
|||
c:\projects\work\next-ucap-messenger\projects\ucap-webmessenger-api-common\src\lib\services\common-api.service.ts
|
BIN
weekly-report/2월/주간보고_박병은_2020.0214.pptx
Normal file
BIN
weekly-report/2월/주간보고_박병은_2020.0214.pptx
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user