2월째주 업무
This commit is contained in:
parent
2db0103c0a
commit
8630261f42
|
@ -1,5 +1,5 @@
|
||||||
묶음파일
|
묶음파일
|
||||||
업로드
|
업로드 (부분 완료)
|
||||||
묶음파일 request 모델 정의
|
묶음파일 request 모델 정의
|
||||||
userSeq: number;
|
userSeq: number;
|
||||||
deviceType: DeviceType;
|
deviceType: DeviceType;
|
||||||
|
@ -24,6 +24,12 @@
|
||||||
이벤트 타입별 출력
|
이벤트 타입별 출력
|
||||||
묶음파일 타입 그리드 썸네일 컴포넌트 정의
|
묶음파일 타입 그리드 썸네일 컴포넌트 정의
|
||||||
그리드 알고리즘 작성
|
그리드 알고리즘 작성
|
||||||
|
썸네일 출력(완료)
|
||||||
|
출력 가이드 라인
|
||||||
|
최대 가로 출력 개수 3개
|
||||||
|
다음행에 출력 개수가 홀수 일때
|
||||||
|
빈 공간이 출력되지 않게 조정
|
||||||
|
최대 width, 최소 height 테스트 후 결정
|
||||||
앨범함
|
앨범함
|
||||||
묶음파일 타입 처리
|
묶음파일 타입 처리
|
||||||
뷰어 컴포넌트 (슬라이드 기능) (진행)
|
뷰어 컴포넌트 (슬라이드 기능) (진행)
|
||||||
|
@ -33,13 +39,6 @@
|
||||||
일반 이미지 출력
|
일반 이미지 출력
|
||||||
동영상인 경우
|
동영상인 경우
|
||||||
일반 동영상 썸네일 출력
|
일반 동영상 썸네일 출력
|
||||||
썸네일 출력
|
|
||||||
출력 가이드 라인
|
|
||||||
최대 가로 출력 개수 3개
|
|
||||||
다음행에 출력 개수가 홀수 일때
|
|
||||||
빈 공간이 출력되지 않게 조정
|
|
||||||
최대 width, 최소 height 테스트 후 결정
|
|
||||||
|
|
||||||
카톡 벤치마킹
|
카톡 벤치마킹
|
||||||
묶음파일 전송 후
|
묶음파일 전송 후
|
||||||
1개의 이미지 전송
|
1개의 이미지 전송
|
||||||
|
@ -47,6 +46,7 @@
|
||||||
동영상 전송
|
동영상 전송
|
||||||
동영상 썸네일 출력
|
동영상 썸네일 출력
|
||||||
동영상은 묶음파일 지원안함
|
동영상은 묶음파일 지원안함
|
||||||
|
묶음파일 기획은 카톡과 동일하게 진행
|
||||||
|
|
||||||
원본 출력
|
원본 출력
|
||||||
//원본 파일 호출할 때 리플레이스
|
//원본 파일 호출할 때 리플레이스
|
||||||
|
@ -93,22 +93,52 @@
|
||||||
기능 목록
|
기능 목록
|
||||||
모바일 주소록 동기화
|
모바일 주소록 동기화
|
||||||
기존방식 (데이터가 많은 경우 중간 서버에서 끊길 가능성이 농후)
|
기존방식 (데이터가 많은 경우 중간 서버에서 끊길 가능성이 농후)
|
||||||
PC 서버 요청
|
1. PC -> Server
|
||||||
모바일 노티
|
모바일 주소록 동기화 시작
|
||||||
for
|
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 서버 요청
|
PC -> 서버
|
||||||
모바일 노티
|
개인 주소록 동기화 요청
|
||||||
모바일 주소록 JSON 으로 전송
|
프로토콜 정의 협의
|
||||||
새로운 방식
|
서버 -> 모바일
|
||||||
생각해봐야함
|
개인 주소록 동기화 요청에 대한 푸시
|
||||||
서버에 개인주소록을 저장할 경우
|
모바일 -> 서버 (REST API)
|
||||||
PC에서 동기화 완료 후 서버 데이터 삭제 고려
|
개인 주소록 POST 전송
|
||||||
서버에 개인주소록을 저장하지 않을 경우
|
데이터 JSON 형태
|
||||||
서버 부하 고려
|
서버 -> 모바일 (REST API)
|
||||||
|
개인 주소록 전송에 대한 응답
|
||||||
|
(응답코드, 싱크번호, 시간, 사용자번호)
|
||||||
|
모바일 -> 서버
|
||||||
|
개인 주소록 전송 동기화 프로토콜 요청
|
||||||
|
(싱크번호, 시간, 사용자번호)
|
||||||
|
서버 -> 모바일
|
||||||
|
개인 주소록 전송 동기화 프로토콜 요청에 대한 응답
|
||||||
|
서버 -> PC
|
||||||
|
개인 주소록 동기화 요청 프로토콜에 대한 푸시
|
||||||
|
(싱크번호, 사용자번호)
|
||||||
|
PC -> 서버 (REST API)
|
||||||
|
개인 주소록 요청
|
||||||
|
(싱크번호, 사용자번호)
|
||||||
|
서버 -> PC
|
||||||
|
개인 주소록 JSON
|
||||||
|
(싱크번호, 시간, 사용자 번호)
|
||||||
|
|
||||||
모바일 주소록 초기화
|
모바일 주소록 초기화
|
||||||
PC에 저장된 모바일 주소록을 삭제
|
PC에 저장된 모바일 주소록을 삭제
|
||||||
엑샐
|
엑샐
|
||||||
|
@ -116,3 +146,14 @@
|
||||||
템플릿
|
템플릿
|
||||||
초기화
|
초기화
|
||||||
MAC용 빌드
|
MAC용 빌드
|
||||||
|
|
||||||
|
대화 저장
|
||||||
|
두개다 대화내용 암호화?
|
||||||
|
서버에서 대화내용을 제공
|
||||||
|
프로토콜 협의
|
||||||
|
PC에서 대화내용 조회후 제공
|
||||||
|
서버 부하
|
||||||
|
|
||||||
|
협의 필요
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,3 +34,4 @@ tems[position].FILE_THUMB_URL
|
||||||
.replace("WebFile", "AttFile")
|
.replace("WebFile", "AttFile")
|
||||||
.replace(".thumb.jpg", "")
|
.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{
|
1: "16F98292020-02-10 07:09:16{
|
||||||
|
|
||||||
↵"StatusCode":"200",
|
↵"StatusCode":"200",
|
||||||
↵"ErrorMessage":"",
|
↵"ErrorMessage":"",
|
||||||
↵"RoomID":"76",
|
↵"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